yp_all.c revision 1219:f89f56c2d9ac
149594Simp/*
249593Simp * CDDL HEADER START
3139815Simp *
449593Simp * The contents of this file are subject to the terms of the
549593Simp * Common Development and Distribution License, Version 1.0 only
649593Simp * (the "License").  You may not use this file except in compliance
749593Simp * with the License.
849593Simp *
949593Simp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1049593Simp * or http://www.opensolaris.org/os/licensing.
1149593Simp * See the License for the specific language governing permissions
1249593Simp * and limitations under the License.
1349593Simp *
1449593Simp * When distributing Covered Code, include this CDDL HEADER in each
1549593Simp * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1649593Simp * If applicable, add the following below this CDDL HEADER, with the
1749593Simp * fields enclosed by brackets "[]" replaced with your own identifying
1849593Simp * information: Portions Copyright [yyyy] [name of copyright owner]
1949593Simp *
2049593Simp * CDDL HEADER END
2149593Simp */
2249593Simp
2349593Simp/*
2449593Simp * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2549593Simp * Use is subject to license terms.
2649593Simp */
2749593Simp
2849593Simp/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
2949593Simp/*	  All Rights Reserved   */
3049593Simp
31141209Sru/*
3249593Simp * Portions of this source code were derived from Berkeley
3386170Sobrien * under license from the Regents of the University of
3486170Sobrien * California.
3549593Simp */
3649593Simp
37103000Speter#pragma ident	"%Z%%M%	%I%	%E% SMI"
3849593Simp
3949593Simp#include "mt.h"
4049593Simp#include <stdlib.h>
4149593Simp#include <unistd.h>
4271191Sjedgar#include <rpc/rpc.h>
4380274Skris#include <syslog.h>
4480274Skris#include "yp_b.h"
4549593Simp#include <rpcsvc/yp_prot.h>
4680274Skris#include <rpcsvc/ypclnt.h>
4780274Skris#include <netdir.h>
4849593Simp#include <string.h>
4949593Simp
5049593Simpextern int __yp_dobind_cflookup(char *, struct dom_binding **, int);
5149593Simp
5292889Sobrienstatic struct timeval tp_timout = { 120, 0};
5392889Sobrienstatic char nullstring[] = "\000";
5492889Sobrien
5549593Simp/*
5649593Simp * __yp_all_cflookup() is a variant of the yp_all() code,
5749594Simp * which adds a 'hardlookup' parameter. This parameter is passed
5871191Sjedgar * to __yp_dobind_cflookup(), and determines whether the server
5949593Simp * binding attempt is hard (try forever) of soft (retry a compiled-
6049593Simp * in number of times).
6149594Simp */
6249593Simpint
6349593Simp__yp_all_cflookup(char *domain, char *map, struct ypall_callback *callback,
6449593Simp								int hardlookup)
6549593Simp{
6649593Simp	size_t domlen;
6749593Simp	size_t maplen;
6849593Simp	struct ypreq_nokey req;
6949593Simp	int reason;
7049593Simp	struct dom_binding *pdomb;
7149593Simp	enum clnt_stat s;
7249593Simp	CLIENT *allc;
7349593Simp	char server_name[MAXHOSTNAMELEN];
7449593Simp	char errbuf[BUFSIZ];
7549593Simp
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 */
176int
177yp_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 */
187int
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