xref: /illumos-gate/usr/src/lib/libnsl/yp/yp_enum.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 1999 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 <rpc/rpc.h>
39 #include <sys/types.h>
40 #include <rpc/trace.h>
41 #include "yp_b.h"
42 #include <rpcsvc/yp_prot.h>
43 #include <rpcsvc/ypclnt.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 
48 extern int __yp_dobind_cflookup(char *, struct dom_binding **, int);
49 
50 static int dofirst(char *, char *, struct dom_binding *, struct timeval,
51     char **, int  *, char **, int  *);
52 
53 static int donext(char *, char *, char *, int, struct dom_binding *,
54     struct timeval, char **, int *, char **val, int *);
55 
56 /*
57  * This requests the yp server associated with a given domain to return the
58  * first key/value pair from the map data base.  The returned key should be
59  * used as an input to the call to ypclnt_next.  This part does the parameter
60  * checking, and the do-until-success loop if 'hardlookup' is set.
61  */
62 int
63 __yp_first_cflookup(
64 	char *domain,
65 	char *map,
66 	char **key,		/* return: key array */
67 	int  *keylen,		/* return: bytes in key */
68 	char **val,		/* return: value array */
69 	int  *vallen,		/* return: bytes in val */
70 	int  hardlookup)
71 {
72 	size_t domlen;
73 	size_t maplen;
74 	struct dom_binding *pdomb;
75 	int reason;
76 
77 	trace1(TR_yp_first, 0);
78 	if ((map == NULL) || (domain == NULL)) {
79 		trace1(TR_yp_first, 1);
80 		return (YPERR_BADARGS);
81 	}
82 
83 	domlen =  strlen(domain);
84 	maplen =  strlen(map);
85 
86 	if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
87 	    (maplen == 0) || (maplen > YPMAXMAP)) {
88 		trace1(TR_yp_first, 1);
89 		return (YPERR_BADARGS);
90 	}
91 
92 	for (;;) {
93 
94 		if (reason = __yp_dobind_cflookup(domain, &pdomb,
95 						    hardlookup)) {
96 			trace1(TR_yp_first, 1);
97 			return (reason);
98 		}
99 
100 		if (pdomb->dom_binding->ypbind_hi_vers == YPVERS) {
101 
102 			reason = dofirst(domain, map, pdomb, _ypserv_timeout,
103 			    key, keylen, val, vallen);
104 
105 			__yp_rel_binding(pdomb);
106 			if (reason == YPERR_RPC || reason == YPERR_YPSERV ||
107 			    reason == YPERR_BUSY /* as if */) {
108 				yp_unbind(domain);
109 				if (hardlookup)
110 					(void) _sleep(_ypsleeptime); /* retry */
111 				else {
112 					trace1(TR_yp_match, 1);
113 					return (reason);
114 				}
115 			} else
116 				break;
117 		} else {
118 			__yp_rel_binding(pdomb);
119 			trace1(TR_yp_first, 1);
120 			return (YPERR_VERS);
121 		}
122 	}
123 	trace1(TR_yp_first, 1);
124 	return (reason);
125 }
126 
127 int
128 yp_first(
129 	char *domain,
130 	char *map,
131 	char **key,		/* return: key array */
132 	int  *keylen,		/* return: bytes in key */
133 	char **val,		/* return: value array */
134 	int  *vallen)		/* return: bytes in val */
135 {
136 	/* traditional yp_firs loops forever until success */
137 	return (__yp_first_cflookup(domain, map, key, keylen, val, vallen, 1));
138 }
139 
140 /*
141  * This part of the "get first" interface talks to ypserv.
142  */
143 
144 static int
145 dofirst(domain, map, pdomb, timeout, key, keylen, val, vallen)
146 	char *domain;
147 	char *map;
148 	struct dom_binding *pdomb;
149 	struct timeval timeout;
150 	char **key;
151 	int  *keylen;
152 	char **val;
153 	int  *vallen;
154 
155 {
156 	struct ypreq_nokey req;
157 	struct ypresp_key_val resp;
158 	unsigned int retval = 0;
159 
160 	trace1(TR_dofirst, 0);
161 	req.domain = domain;
162 	req.map = map;
163 	resp.keydat.dptr = resp.valdat.dptr = NULL;
164 	resp.keydat.dsize = resp.valdat.dsize = 0;
165 
166 	/*
167 	 * Do the get first request.  If the rpc call failed, return with status
168 	 * from this point.
169 	 */
170 
171 	(void) memset((char *)&resp, 0, sizeof (struct ypresp_key_val));
172 
173 	switch (clnt_call(pdomb->dom_client, YPPROC_FIRST,
174 			(xdrproc_t)xdr_ypreq_nokey,
175 			(char *)&req, (xdrproc_t)xdr_ypresp_key_val,
176 			(char *)&resp, timeout)) {
177 	case RPC_SUCCESS:
178 		break;
179 	case RPC_TIMEDOUT:
180 		trace1(TR_dofirst, 1);
181 		return (YPERR_YPSERV);
182 	default:
183 		trace1(TR_dofirst, 1);
184 		return (YPERR_RPC);
185 	}
186 
187 	/* See if the request succeeded */
188 
189 	if (resp.status != YP_TRUE) {
190 		retval = ypprot_err(resp.status);
191 	}
192 
193 	/* Get some memory which the user can get rid of as he likes */
194 
195 	if (!retval) {
196 
197 		if ((*key = malloc((size_t)resp.keydat.dsize + 2)) != NULL) {
198 
199 			if ((*val = malloc(
200 			    (size_t)resp.valdat.dsize + 2)) == NULL) {
201 				free((char *)*key);
202 				retval = YPERR_RESRC;
203 			}
204 
205 		} else {
206 			retval = YPERR_RESRC;
207 		}
208 	}
209 
210 	/* Copy the returned key and value byte strings into the new memory */
211 
212 	if (!retval) {
213 		*keylen = (int)resp.keydat.dsize;
214 		(void) memcpy(*key, resp.keydat.dptr,
215 		    (size_t)resp.keydat.dsize);
216 		(*key)[resp.keydat.dsize] = '\n';
217 		(*key)[resp.keydat.dsize + 1] = '\0';
218 
219 		*vallen = (int)resp.valdat.dsize;
220 		(void) memcpy(*val, resp.valdat.dptr,
221 		    (size_t)resp.valdat.dsize);
222 		(*val)[resp.valdat.dsize] = '\n';
223 		(*val)[resp.valdat.dsize + 1] = '\0';
224 	}
225 
226 	CLNT_FREERES(pdomb->dom_client,
227 		(xdrproc_t)xdr_ypresp_key_val, (char *)&resp);
228 	trace1(TR_dofirst, 1);
229 	return (retval);
230 }
231 
232 /*
233  * This requests the yp server associated with a given domain to return the
234  * "next" key/value pair from the map data base.  The input key should be
235  * one returned by ypclnt_first or a previous call to ypclnt_next.  The
236  * returned key should be used as an input to the next call to ypclnt_next.
237  * This part does the parameter checking, and the do-until-success loop.
238  * if 'hardlookup' is set.
239  */
240 int
241 __yp_next_cflookup(
242 	char *domain,
243 	char *map,
244 	char *inkey,
245 	int  inkeylen,
246 	char **outkey,		/* return: key array associated with val */
247 	int  *outkeylen,	/* return: bytes in key */
248 	char **val,		/* return: value array associated with outkey */
249 	int  *vallen,		/* return: bytes in val */
250 	int  hardlookup)
251 {
252 	size_t domlen;
253 	size_t maplen;
254 	struct dom_binding *pdomb;
255 	int reason;
256 
257 
258 	trace1(TR_yp_next, 0);
259 	if ((map == NULL) || (domain == NULL) || (inkey == NULL)) {
260 		trace1(TR_yp_next, 1);
261 		return (YPERR_BADARGS);
262 	}
263 
264 	domlen =  strlen(domain);
265 	maplen =  strlen(map);
266 
267 	if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
268 	    (maplen == 0) || (maplen > YPMAXMAP)) {
269 		trace1(TR_yp_next, 1);
270 		return (YPERR_BADARGS);
271 	}
272 
273 	for (;;) {
274 		if (reason = __yp_dobind_cflookup(domain, &pdomb,
275 						hardlookup)) {
276 			trace1(TR_yp_next, 1);
277 			return (reason);
278 		}
279 
280 		if (pdomb->dom_binding->ypbind_hi_vers == YPVERS) {
281 
282 			reason = donext(domain, map, inkey, inkeylen, pdomb,
283 			    _ypserv_timeout, outkey, outkeylen, val, vallen);
284 
285 			__yp_rel_binding(pdomb);
286 
287 			if (reason == YPERR_RPC || reason == YPERR_YPSERV ||
288 			    reason == YPERR_BUSY /* as if */) {
289 				yp_unbind(domain);
290 				if (hardlookup)
291 					(void) _sleep(_ypsleeptime); /* retry */
292 				else {
293 					trace1(TR_yp_match, 1);
294 					return (reason);
295 				}
296 			} else
297 				break;
298 		} else {
299 			__yp_rel_binding(pdomb);
300 			trace1(TR_yp_next, 1);
301 			return (YPERR_VERS);
302 		}
303 	}
304 
305 	trace1(TR_yp_next, 1);
306 	return (reason);
307 }
308 
309 int
310 yp_next(
311 	char *domain,
312 	char *map,
313 	char *inkey,
314 	int  inkeylen,
315 	char **outkey,		/* return: key array associated with val */
316 	int  *outkeylen,	/* return: bytes in key */
317 	char **val,		/* return: value array associated with outkey */
318 	int  *vallen)		/* return: bytes in val */
319 {
320 	/* traditional yp_next loops forever until success */
321 	return (__yp_next_cflookup(domain, map, inkey, inkeylen, outkey,
322 				outkeylen, val, vallen, 1));
323 }
324 
325 
326 /*
327  * This part of the "get next" interface talks to ypserv.
328  */
329 static int
330 donext(domain, map, inkey, inkeylen, pdomb, timeout, outkey, outkeylen,
331     val, vallen)
332 	char *domain;
333 	char *map;
334 	char *inkey;
335 	int  inkeylen;
336 	struct dom_binding *pdomb;
337 	struct timeval timeout;
338 	char **outkey;		/* return: key array associated with val */
339 	int  *outkeylen;	/* return: bytes in key */
340 	char **val;		/* return: value array associated with outkey */
341 	int  *vallen;		/* return: bytes in val */
342 
343 {
344 	struct ypreq_key req;
345 	struct ypresp_key_val resp;
346 	unsigned int retval = 0;
347 
348 	trace2(TR_donext, 0, inkeylen);
349 	req.domain = domain;
350 	req.map = map;
351 	req.keydat.dptr = inkey;
352 	req.keydat.dsize = inkeylen;
353 
354 	resp.keydat.dptr = resp.valdat.dptr = NULL;
355 	resp.keydat.dsize = resp.valdat.dsize = 0;
356 
357 	/*
358 	 * Do the get next request.  If the rpc call failed, return with status
359 	 * from this point.
360 	 */
361 
362 	switch (clnt_call(pdomb->dom_client,
363 			YPPROC_NEXT, (xdrproc_t)xdr_ypreq_key, (char *)&req,
364 			(xdrproc_t)xdr_ypresp_key_val, (char *)&resp,
365 			timeout)) {
366 	case RPC_SUCCESS:
367 		break;
368 	case RPC_TIMEDOUT:
369 		trace1(TR_dofirst, 1);
370 		return (YPERR_YPSERV);
371 	default:
372 		trace1(TR_dofirst, 1);
373 		return (YPERR_RPC);
374 	}
375 
376 	/* See if the request succeeded */
377 
378 	if (resp.status != YP_TRUE) {
379 		retval = ypprot_err(resp.status);
380 	}
381 
382 	/* Get some memory which the user can get rid of as he likes */
383 
384 	if (!retval) {
385 		if ((*outkey = malloc((size_t)
386 		    resp.keydat.dsize + 2)) != NULL) {
387 
388 			if ((*val = malloc((size_t)
389 			    resp.valdat.dsize + 2)) == NULL) {
390 				free((char *)*outkey);
391 				retval = YPERR_RESRC;
392 			}
393 
394 		} else {
395 			retval = YPERR_RESRC;
396 		}
397 	}
398 
399 	/* Copy the returned key and value byte strings into the new memory */
400 
401 	if (!retval) {
402 		*outkeylen = (int)resp.keydat.dsize;
403 		(void) memcpy(*outkey, resp.keydat.dptr,
404 		    (size_t)resp.keydat.dsize);
405 		(*outkey)[resp.keydat.dsize] = '\n';
406 		(*outkey)[resp.keydat.dsize + 1] = '\0';
407 
408 		*vallen = (int)resp.valdat.dsize;
409 		(void) memcpy(*val, resp.valdat.dptr,
410 		    (size_t)resp.valdat.dsize);
411 		(*val)[resp.valdat.dsize] = '\n';
412 		(*val)[resp.valdat.dsize + 1] = '\0';
413 	}
414 
415 	CLNT_FREERES(pdomb->dom_client, (xdrproc_t)xdr_ypresp_key_val,
416 		    (char *)&resp);
417 	trace1(TR_donext, 1);
418 	return (retval);
419 }
420