1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23 /*
24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
30
31 /*
32 * Portions of this source code were derived from Berkeley
33 * under license from the Regents of the University of
34 * California.
35 */
36
37 #include "mt.h"
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <rpc/rpc.h>
41 #include <syslog.h>
42 #include "yp_b.h"
43 #include <rpcsvc/yp_prot.h>
44 #include <rpcsvc/ypclnt.h>
45 #include <netdir.h>
46 #include <string.h>
47
48 extern int __yp_dobind_cflookup(char *, struct dom_binding **, int);
49
50 static struct timeval tp_timout = { 120, 0};
51 static char nullstring[] = "\000";
52
53 /*
54 * __yp_all_cflookup() is a variant of the yp_all() code,
55 * which adds a 'hardlookup' parameter. This parameter is passed
56 * to __yp_dobind_cflookup(), and determines whether the server
57 * binding attempt is hard (try forever) of soft (retry a compiled-
58 * in number of times).
59 */
60 int
__yp_all_cflookup(char * domain,char * map,struct ypall_callback * callback,int hardlookup)61 __yp_all_cflookup(char *domain, char *map, struct ypall_callback *callback,
62 int hardlookup)
63 {
64 size_t domlen;
65 size_t maplen;
66 struct ypreq_nokey req;
67 int reason;
68 struct dom_binding *pdomb;
69 enum clnt_stat s;
70 CLIENT *allc;
71 char server_name[MAXHOSTNAMELEN];
72 char errbuf[BUFSIZ];
73
74 if ((map == NULL) || (domain == NULL))
75 return (YPERR_BADARGS);
76
77 domlen = strlen(domain);
78 maplen = strlen(map);
79
80 if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
81 (maplen == 0) || (maplen > YPMAXMAP) ||
82 (callback == NULL))
83 return (YPERR_BADARGS);
84
85 if (reason = __yp_dobind_cflookup(domain, &pdomb, hardlookup))
86 return (reason);
87
88 if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) {
89 __yp_rel_binding(pdomb);
90 return (YPERR_VERS);
91 }
92 (void) mutex_lock(&pdomb->server_name_lock);
93 if (!pdomb->dom_binding->ypbind_servername) {
94 (void) mutex_unlock(&pdomb->server_name_lock);
95 __yp_rel_binding(pdomb);
96 syslog(LOG_ERR, "yp_all: failed to get server's name\n");
97 return (YPERR_RPC);
98 }
99 (void) strcpy(server_name, pdomb->dom_binding->ypbind_servername);
100 (void) mutex_unlock(&pdomb->server_name_lock);
101 if (strcmp(server_name, nullstring) == 0) {
102 /*
103 * This is the case where ypbind is running in broadcast mode,
104 * we have to do the jugglery to get the
105 * ypserv's address on COTS transport based
106 * on the CLTS address ypbind gave us !
107 */
108
109 struct nd_hostservlist *nhs;
110
111 if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf,
112 &nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) {
113 syslog(LOG_ERR,
114 "yp_all: failed to get server's name\n");
115 __yp_rel_binding(pdomb);
116 return (YPERR_RPC);
117 }
118 /* check server name again, some other thread may have set it */
119 (void) mutex_lock(&pdomb->server_name_lock);
120 if (strcmp(pdomb->dom_binding->ypbind_servername,
121 nullstring) == 0) {
122 pdomb->dom_binding->ypbind_servername =
123 (char *)strdup(nhs->h_hostservs->h_host);
124 }
125 (void) strcpy(server_name,
126 pdomb->dom_binding->ypbind_servername);
127 (void) mutex_unlock(&pdomb->server_name_lock);
128 netdir_free((char *)nhs, ND_HOSTSERVLIST);
129 }
130 __yp_rel_binding(pdomb);
131 if ((allc = clnt_create(server_name, YPPROG,
132 YPVERS, "circuit_n")) == NULL) {
133 (void) snprintf(errbuf, BUFSIZ, "yp_all \
134 - transport level create failure for domain %s / map %s", domain, map);
135 syslog(LOG_ERR, "%s", clnt_spcreateerror(errbuf));
136 return (YPERR_RPC);
137 }
138
139 req.domain = domain;
140 req.map = map;
141
142
143 s = clnt_call(allc, YPPROC_ALL,
144 (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
145 (xdrproc_t)xdr_ypall, (char *)callback, tp_timout);
146
147 if (s != RPC_SUCCESS && s != RPC_TIMEDOUT) {
148 syslog(LOG_ERR, "%s", clnt_sperror(allc,
149 "yp_all - RPC clnt_call (transport level) failure"));
150 }
151
152 clnt_destroy(allc);
153 switch (s) {
154 case RPC_SUCCESS:
155 return (0);
156 case RPC_TIMEDOUT:
157 return (YPERR_YPSERV);
158 default:
159 return (YPERR_RPC);
160 }
161 }
162
163
164 /*
165 * This does the "glommed enumeration" stuff. callback->foreach is the name
166 * of a function which gets called per decoded key-value pair:
167 *
168 * (*callback->foreach)(status, key, keylen, val, vallen, callback->data);
169 *
170 * If the server we get back from __yp_dobind speaks the old protocol, this
171 * returns YPERR_VERS, and does not attempt to emulate the new functionality
172 * by using the old protocol.
173 */
174 int
yp_all(char * domain,char * map,struct ypall_callback * callback)175 yp_all(char *domain, char *map, struct ypall_callback *callback)
176 {
177 return (__yp_all_cflookup(domain, map, callback, 1));
178 }
179
180
181 /*
182 * This function is identical to 'yp_all' with the exception that it
183 * attempts to use reserve ports.
184 */
185 int
__yp_all_rsvdport(char * domain,char * map,struct ypall_callback * callback)186 __yp_all_rsvdport(char *domain, char *map, struct ypall_callback *callback)
187 {
188 size_t domlen;
189 size_t maplen;
190 struct ypreq_nokey req;
191 int reason;
192 struct dom_binding *pdomb;
193 enum clnt_stat s;
194 CLIENT *allc;
195 char server_name[MAXHOSTNAMELEN];
196 char errbuf[BUFSIZ];
197
198 if ((map == NULL) || (domain == NULL))
199 return (YPERR_BADARGS);
200
201 domlen = strlen(domain);
202 maplen = strlen(map);
203
204 if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
205 (maplen == 0) || (maplen > YPMAXMAP) ||
206 (callback == NULL))
207 return (YPERR_BADARGS);
208
209 if (reason = __yp_dobind_rsvdport(domain, &pdomb))
210 return (reason);
211
212 if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) {
213 /*
214 * Have to free the binding since the reserved
215 * port bindings are not cached.
216 */
217 __yp_rel_binding(pdomb);
218 free_dom_binding(pdomb);
219 return (YPERR_VERS);
220 }
221 (void) mutex_lock(&pdomb->server_name_lock);
222 if (!pdomb->dom_binding->ypbind_servername) {
223 (void) mutex_unlock(&pdomb->server_name_lock);
224 syslog(LOG_ERR, "yp_all: failed to get server's name\n");
225 __yp_rel_binding(pdomb);
226 free_dom_binding(pdomb);
227 return (YPERR_RPC);
228 }
229 (void) strcpy(server_name, pdomb->dom_binding->ypbind_servername);
230 (void) mutex_unlock(&pdomb->server_name_lock);
231 if (strcmp(server_name, nullstring) == 0) {
232 /*
233 * This is the case where ypbind is running in broadcast mode,
234 * we have to do the jugglery to get the
235 * ypserv's address on COTS transport based
236 * on the CLTS address ypbind gave us !
237 */
238
239 struct nd_hostservlist *nhs;
240
241 if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf,
242 &nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) {
243 syslog(LOG_ERR,
244 "yp_all: failed to get server's name\n");
245 __yp_rel_binding(pdomb);
246 free_dom_binding(pdomb);
247 return (YPERR_RPC);
248 }
249 /* check server name again, some other thread may have set it */
250 (void) mutex_lock(&pdomb->server_name_lock);
251 if (strcmp(pdomb->dom_binding->ypbind_servername,
252 nullstring) == 0) {
253 pdomb->dom_binding->ypbind_servername =
254 (char *)strdup(nhs->h_hostservs->h_host);
255 }
256 (void) strcpy(server_name,
257 pdomb->dom_binding->ypbind_servername);
258 (void) mutex_unlock(&pdomb->server_name_lock);
259 netdir_free((char *)nhs, ND_HOSTSERVLIST);
260
261 }
262 __yp_rel_binding(pdomb);
263 if ((allc = __yp_clnt_create_rsvdport(server_name, YPPROG, YPVERS,
264 "tcp6", 0, 0)) == NULL &&
265 (allc = __yp_clnt_create_rsvdport(server_name, YPPROG, YPVERS,
266 "tcp", 0, 0)) == NULL) {
267 (void) snprintf(errbuf, BUFSIZ, "yp_all \
268 - transport level create failure for domain %s / map %s", domain, map);
269 syslog(LOG_ERR, "%s", clnt_spcreateerror(errbuf));
270 free_dom_binding(pdomb);
271 return (YPERR_RPC);
272 }
273
274 req.domain = domain;
275 req.map = map;
276
277 s = clnt_call(allc, YPPROC_ALL,
278 (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
279 (xdrproc_t)xdr_ypall, (char *)callback, tp_timout);
280
281 if (s != RPC_SUCCESS && s != RPC_TIMEDOUT) {
282 syslog(LOG_ERR, "%s", clnt_sperror(allc,
283 "yp_all - RPC clnt_call (transport level) failure"));
284 }
285
286 clnt_destroy(allc);
287 free_dom_binding(pdomb);
288 switch (s) {
289 case RPC_SUCCESS:
290 return (0);
291 case RPC_TIMEDOUT:
292 return (YPERR_YPSERV);
293 default:
294 return (YPERR_RPC);
295 }
296 }
297