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