xref: /illumos-gate/usr/src/lib/libnsl/yp/yp_all.c (revision 7c478bd9)
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  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /*	  All Rights Reserved   */
28 
29 /*
30  * Portions of this source code were derived from Berkeley
31  * under license from the Regents of the University of
32  * California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 #define	NULL 0
38 #include "mt.h"
39 #include <rpc/rpc.h>
40 #include <syslog.h>
41 #include "yp_b.h"
42 #include <rpcsvc/yp_prot.h>
43 #include <rpcsvc/ypclnt.h>
44 #include <rpc/trace.h>
45 #include <netdir.h>
46 #include <string.h>
47 #include <stdlib.h>
48 
49 extern int __yp_dobind_cflookup(char *, struct dom_binding **, int);
50 
51 static struct timeval tp_timout = { 120, 0};
52 static char nullstring[] = "\000";
53 
54 /*
55  * __yp_all_cflookup() is a variant of the yp_all() code,
56  * which adds a 'hardlookup' parameter. This parameter is passed
57  * to __yp_dobind_cflookup(), and determines whether the server
58  * binding attempt is hard (try forever) of soft (retry a compiled-
59  * in number of times).
60  */
61 int
62 __yp_all_cflookup(domain, map, callback, hardlookup)
63 	char *domain;
64 	char *map;
65 	struct ypall_callback *callback;
66 	int hardlookup;
67 {
68 	size_t domlen;
69 	size_t maplen;
70 	struct ypreq_nokey req;
71 	int reason;
72 	struct dom_binding *pdomb;
73 	enum clnt_stat s;
74 	CLIENT *allc;
75 	char server_name[MAXHOSTNAMELEN];
76 	char errbuf[BUFSIZ];
77 
78 	trace1(TR_yp_all, 0);
79 	if ((map == NULL) || (domain == NULL)) {
80 		trace1(TR_yp_all, 1);
81 		return (YPERR_BADARGS);
82 	}
83 
84 	domlen = strlen(domain);
85 	maplen = strlen(map);
86 
87 	if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
88 	    (maplen == 0) || (maplen > YPMAXMAP) ||
89 	    (callback == (struct ypall_callback *)NULL)) {
90 		trace1(TR_yp_all, 1);
91 		return (YPERR_BADARGS);
92 	}
93 
94 	if (reason = __yp_dobind_cflookup(domain, &pdomb, hardlookup)) {
95 		trace1(TR_yp_all, 1);
96 		return (reason);
97 	}
98 
99 	if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) {
100 		__yp_rel_binding(pdomb);
101 		trace1(TR_yp_all, 1);
102 		return (YPERR_VERS);
103 	}
104 	mutex_lock(&pdomb->server_name_lock);
105 	if (!pdomb->dom_binding->ypbind_servername) {
106 		mutex_unlock(&pdomb->server_name_lock);
107 		__yp_rel_binding(pdomb);
108 		syslog(LOG_ERR, "yp_all: failed to get server's name\n");
109 		trace1(TR_yp_all, 1);
110 		return (YPERR_RPC);
111 	}
112 	(void) strcpy(server_name, pdomb->dom_binding->ypbind_servername);
113 	mutex_unlock(&pdomb->server_name_lock);
114 	if (strcmp(server_name, nullstring) == 0) {
115 		/*
116 		 * This is the case where ypbind is running in broadcast mode,
117 		 * we have to do the jugglery to get the
118 		 * ypserv's address on COTS transport based
119 		 * on the CLTS address ypbind gave us !
120 		 */
121 
122 		struct nd_hostservlist *nhs;
123 
124 		if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf,
125 			&nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) {
126 			syslog(LOG_ERR,
127 				"yp_all: failed to get server's name\n");
128 			__yp_rel_binding(pdomb);
129 			trace1(TR_yp_all, 1);
130 			return (YPERR_RPC);
131 		}
132 		/* check server name again, some other thread may have set it */
133 		mutex_lock(&pdomb->server_name_lock);
134 		if (strcmp(pdomb->dom_binding->ypbind_servername,
135 					nullstring) == 0) {
136 			pdomb->dom_binding->ypbind_servername =
137 				(char *)strdup(nhs->h_hostservs->h_host);
138 		}
139 		(void) strcpy(server_name,
140 		    pdomb->dom_binding->ypbind_servername);
141 		mutex_unlock(&pdomb->server_name_lock);
142 		netdir_free((char *)nhs, ND_HOSTSERVLIST);
143 	}
144 	__yp_rel_binding(pdomb);
145 	if ((allc = clnt_create(server_name, YPPROG,
146 		YPVERS, "circuit_n")) == (CLIENT *) NULL) {
147 			snprintf(errbuf, BUFSIZ, "yp_all \
148 - transport level create failure for domain %s / map %s", domain, map);
149 			syslog(LOG_ERR, clnt_spcreateerror(errbuf));
150 			trace1(TR_yp_all, 1);
151 			return (YPERR_RPC);
152 	}
153 
154 	req.domain = domain;
155 	req.map = map;
156 
157 
158 	s = clnt_call(allc, YPPROC_ALL,
159 		(xdrproc_t)xdr_ypreq_nokey, (char *)&req,
160 	    (xdrproc_t)xdr_ypall, (char *)callback, tp_timout);
161 
162 	if (s != RPC_SUCCESS && s != RPC_TIMEDOUT) {
163 		syslog(LOG_ERR, clnt_sperror(allc,
164 		    "yp_all - RPC clnt_call (transport level) failure"));
165 	}
166 
167 	clnt_destroy(allc);
168 	switch (s) {
169 	case RPC_SUCCESS:
170 		trace1(TR_yp_all, 1);
171 		return (0);
172 	case RPC_TIMEDOUT:
173 		trace1(TR_yp_all, 1);
174 		return (YPERR_YPSERV);
175 	default:
176 		trace1(TR_yp_all, 1);
177 		return (YPERR_RPC);
178 	}
179 }
180 
181 
182 /*
183  * This does the "glommed enumeration" stuff.  callback->foreach is the name
184  * of a function which gets called per decoded key-value pair:
185  *
186  * (*callback->foreach)(status, key, keylen, val, vallen, callback->data);
187  *
188  * If the server we get back from __yp_dobind speaks the old protocol, this
189  * returns YPERR_VERS, and does not attempt to emulate the new functionality
190  * by using the old protocol.
191  */
192 int
193 yp_all(domain, map, callback)
194 	char *domain;
195 	char *map;
196 	struct ypall_callback *callback;
197 {
198 	return (__yp_all_cflookup(domain, map, callback, 1));
199 }
200 
201 
202 /*
203  * This function is identical to 'yp_all' with the exception that it
204  * attempts to use reserve ports.
205  */
206 int
207 __yp_all_rsvdport(domain, map, callback)
208 	char *domain;
209 	char *map;
210 	struct ypall_callback *callback;
211 {
212 	size_t domlen;
213 	size_t maplen;
214 	struct ypreq_nokey req;
215 	int reason;
216 	struct dom_binding *pdomb;
217 	enum clnt_stat s;
218 	CLIENT *allc;
219 	char server_name[MAXHOSTNAMELEN];
220 	char errbuf[BUFSIZ];
221 
222 	trace1(TR_yp_all, 0);
223 	if ((map == NULL) || (domain == NULL)) {
224 		trace1(TR_yp_all, 1);
225 		return (YPERR_BADARGS);
226 	}
227 
228 	domlen =  strlen(domain);
229 	maplen =  strlen(map);
230 
231 	if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
232 	    (maplen == 0) || (maplen > YPMAXMAP) ||
233 	    (callback == (struct ypall_callback *)NULL)) {
234 		trace1(TR_yp_all, 1);
235 		return (YPERR_BADARGS);
236 	}
237 
238 	if (reason = __yp_dobind_rsvdport(domain, &pdomb)) {
239 		trace1(TR_yp_all, 1);
240 		return (reason);
241 	}
242 
243 	if (pdomb->dom_binding->ypbind_hi_vers < YPVERS) {
244 		/*
245 		 * Have to free the binding since the reserved
246 		 * port bindings are not cached.
247 		 */
248 		__yp_rel_binding(pdomb);
249 		free_dom_binding(pdomb);
250 		trace1(TR_yp_all, 1);
251 		return (YPERR_VERS);
252 	}
253 	mutex_lock(&pdomb->server_name_lock);
254 	if (!pdomb->dom_binding->ypbind_servername) {
255 		mutex_unlock(&pdomb->server_name_lock);
256 		syslog(LOG_ERR, "yp_all: failed to get server's name\n");
257 		__yp_rel_binding(pdomb);
258 		free_dom_binding(pdomb);
259 		trace1(TR_yp_all, 1);
260 		return (YPERR_RPC);
261 	}
262 	(void) strcpy(server_name, pdomb->dom_binding->ypbind_servername);
263 	mutex_unlock(&pdomb->server_name_lock);
264 	if (strcmp(server_name, nullstring) == 0) {
265 		/*
266 		 * This is the case where ypbind is running in broadcast mode,
267 		 * we have to do the jugglery to get the
268 		 * ypserv's address on COTS transport based
269 		 * on the CLTS address ypbind gave us !
270 		 */
271 
272 		struct nd_hostservlist *nhs;
273 
274 		if (netdir_getbyaddr(pdomb->dom_binding->ypbind_nconf,
275 			&nhs, pdomb->dom_binding->ypbind_svcaddr) != ND_OK) {
276 			syslog(LOG_ERR,
277 				"yp_all: failed to get server's name\n");
278 			__yp_rel_binding(pdomb);
279 			free_dom_binding(pdomb);
280 			trace1(TR_yp_all, 1);
281 			return (YPERR_RPC);
282 		}
283 		/* check server name again, some other thread may have set it */
284 		mutex_lock(&pdomb->server_name_lock);
285 		if (strcmp(pdomb->dom_binding->ypbind_servername,
286 					nullstring) == 0) {
287 			pdomb->dom_binding->ypbind_servername =
288 			(char *)strdup(nhs->h_hostservs->h_host);
289 		}
290 		(void) strcpy(server_name,
291 		    pdomb->dom_binding->ypbind_servername);
292 		mutex_unlock(&pdomb->server_name_lock);
293 		netdir_free((char *)nhs, ND_HOSTSERVLIST);
294 
295 	}
296 	__yp_rel_binding(pdomb);
297 	if ((allc = __yp_clnt_create_rsvdport(server_name, YPPROG, YPVERS,
298 	    "tcp6", 0, 0)) == (CLIENT *) NULL &&
299 		(allc = __yp_clnt_create_rsvdport(server_name, YPPROG, YPVERS,
300 	    "tcp", 0, 0)) == (CLIENT *) NULL) {
301 		snprintf(errbuf, BUFSIZ, "yp_all \
302 - transport level create failure for domain %s / map %s", domain, map);
303 		syslog(LOG_ERR, clnt_spcreateerror(errbuf));
304 		free_dom_binding(pdomb);
305 		trace1(TR_yp_all, 1);
306 		return (YPERR_RPC);
307 	}
308 
309 	req.domain = domain;
310 	req.map = map;
311 
312 	s = clnt_call(allc, YPPROC_ALL,
313 		(xdrproc_t)xdr_ypreq_nokey, (char *)&req,
314 	    (xdrproc_t)xdr_ypall, (char *)callback, tp_timout);
315 
316 	if (s != RPC_SUCCESS && s != RPC_TIMEDOUT) {
317 		syslog(LOG_ERR, clnt_sperror(allc,
318 		    "yp_all - RPC clnt_call (transport level) failure"));
319 	}
320 
321 	clnt_destroy(allc);
322 	free_dom_binding(pdomb);
323 	switch (s) {
324 	case RPC_SUCCESS:
325 		trace1(TR_yp_all, 1);
326 		return (0);
327 	case RPC_TIMEDOUT:
328 		trace1(TR_yp_all, 1);
329 		return (YPERR_YPSERV);
330 	default:
331 		trace1(TR_yp_all, 1);
332 		return (YPERR_RPC);
333 	}
334 }
335