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
50extern int __yp_dobind_cflookup(char *, struct dom_binding **, int);
51
52static int dofirst(char *, char *, struct dom_binding *, struct timeval,
53    char **, int  *, char **, int  *);
54
55static 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 */
64int
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
117int
118yp_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
134static int
135dofirst(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 */
226int
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
283int
284yp_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 */
303static int
304donext(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