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
50extern int __yp_dobind_cflookup(char *, struct dom_binding **, int);
51
52static struct timeval tp_timout = { 120, 0};
53static 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 */
62int
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 */
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