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