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