xref: /illumos-gate/usr/src/lib/libnsl/yp/yp_all.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
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
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
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
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