xref: /openbsd/lib/libc/yp/ypmatch_cache.c (revision f2dfb0a4)
1 /*
2  * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by Theo de Raadt.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #if defined(LIBC_SCCS) && !defined(lint)
33 static char *rcsid = "$OpenBSD: ypmatch_cache.c,v 1.7 1998/01/20 18:40:27 deraadt Exp $";
34 #endif /* LIBC_SCCS and not lint */
35 
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/file.h>
40 #include <sys/uio.h>
41 #include <errno.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <rpc/rpc.h>
47 #include <rpc/xdr.h>
48 #include <rpcsvc/yp.h>
49 #include <rpcsvc/ypclnt.h>
50 #define YPMATCHCACHE
51 #include "ypinternal.h"
52 
53 int _yplib_cache = 5;
54 
55 static bool_t
56 ypmatch_add(map, key, keylen, val, vallen)
57 	const char     *map;
58 	const char     *key;
59 	u_int           keylen;
60 	char           *val;
61 	u_int           vallen;
62 {
63 	struct ypmatch_ent *ep;
64 	time_t t;
65 
66 	(void)time(&t);
67 
68 	for (ep = ypmc; ep; ep = ep->next)
69 		if (ep->expire_t < t)
70 			break;
71 	if (ep == NULL) {
72 		if ((ep = malloc(sizeof *ep)) == NULL)
73 			return 0;
74 		(void)memset(ep, 0, sizeof *ep);
75 		if (ypmc)
76 			ep->next = ypmc;
77 		ypmc = ep;
78 	}
79 
80 	if (ep->key) {
81 		free(ep->key);
82 		ep->key = NULL;
83 	}
84 	if (ep->val) {
85 		free(ep->val);
86 		ep->val = NULL;
87 	}
88 
89 	if ((ep->key = malloc(keylen)) == NULL)
90 		return 0;
91 
92 	if ((ep->val = malloc(vallen)) == NULL) {
93 		free(ep->key);
94 		ep->key = NULL;
95 		return 0;
96 	}
97 
98 	ep->keylen = keylen;
99 	ep->vallen = vallen;
100 
101 	(void)memcpy(ep->key, key, ep->keylen);
102 	(void)memcpy(ep->val, val, ep->vallen);
103 
104 	if (ep->map) {
105 		if (strcmp(ep->map, map)) {
106 			free(ep->map);
107 			if ((ep->map = strdup(map)) == NULL)
108 				return 0;
109 		}
110 	} else {
111 		if ((ep->map = strdup(map)) == NULL)
112 			return 0;
113 	}
114 
115 	ep->expire_t = t + _yplib_cache;
116 	return 1;
117 }
118 
119 static bool_t
120 ypmatch_find(map, key, keylen, val, vallen)
121 	const char     *map;
122 	const char     *key;
123 	u_int           keylen;
124 	char          **val;
125 	u_int          *vallen;
126 {
127 	struct ypmatch_ent *ep;
128 	time_t          t;
129 
130 	if (ypmc == NULL)
131 		return 0;
132 
133 	(void) time(&t);
134 
135 	for (ep = ypmc; ep; ep = ep->next) {
136 		if (ep->keylen != keylen)
137 			continue;
138 		if (strcmp(ep->map, map))
139 			continue;
140 		if (memcmp(ep->key, key, keylen))
141 			continue;
142 		if (t > ep->expire_t)
143 			continue;
144 
145 		*val = ep->val;
146 		*vallen = ep->vallen;
147 		return 1;
148 	}
149 	return 0;
150 }
151 
152 int
153 yp_match(indomain, inmap, inkey, inkeylen, outval, outvallen)
154 	const char     *indomain;
155 	const char     *inmap;
156 	const char     *inkey;
157 	int             inkeylen;
158 	char          **outval;
159 	int            *outvallen;
160 {
161 	struct dom_binding *ysd;
162 	struct ypresp_val yprv;
163 	struct timeval  tv;
164 	struct ypreq_key yprk;
165 	int tries = 0, r;
166 
167 	if (indomain == NULL || *indomain == '\0' ||
168 	    strlen(indomain) > YPMAXDOMAIN || inmap == NULL ||
169 	    *inmap == '\0' || strlen(inmap) > YPMAXMAP ||
170 	    inkey == NULL || inkeylen == 0 || inkeylen >= YPMAXRECORD)
171 		return YPERR_BADARGS;
172 
173 	*outval = NULL;
174 	*outvallen = 0;
175 
176 again:
177 	if (_yp_dobind(indomain, &ysd) != 0)
178 		return YPERR_DOMAIN;
179 
180 #ifdef YPMATCHCACHE
181 	if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
182 	    inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) {
183 		*outvallen = yprv.val.valdat_len;
184 		if ((*outval = malloc(*outvallen + 1)) == NULL) {
185 			_yp_unbind(ysd);
186 			return YPERR_YPERR;
187 		}
188 		(void)memcpy(*outval, yprv.val.valdat_val, *outvallen);
189 		(*outval)[*outvallen] = '\0';
190 		_yp_unbind(ysd);
191 		return 0;
192 	}
193 #endif
194 
195 	tv.tv_sec = _yplib_timeout;
196 	tv.tv_usec = 0;
197 
198 	yprk.domain = (char *)indomain;
199 	yprk.map = (char *)inmap;
200 	yprk.key.keydat_val = (char *) inkey;
201 	yprk.key.keydat_len = inkeylen;
202 
203 	memset(&yprv, 0, sizeof yprv);
204 
205 	r = clnt_call(ysd->dom_client, YPPROC_MATCH,
206 	    xdr_ypreq_key, &yprk, xdr_ypresp_val, &yprv, tv);
207 	if (r != RPC_SUCCESS) {
208 		if (tries++)
209 			clnt_perror(ysd->dom_client, "yp_match: clnt_call");
210 		ysd->dom_vers = -1;
211 		goto again;
212 	}
213 	if (!(r = ypprot_err(yprv.stat))) {
214 		*outvallen = yprv.val.valdat_len;
215 		if ((*outval = malloc(*outvallen + 1)) == NULL) {
216 			r = YPERR_YPERR;
217 			goto out;
218 		}
219 		(void)memcpy(*outval, yprv.val.valdat_val, *outvallen);
220 		(*outval)[*outvallen] = '\0';
221 #ifdef YPMATCHCACHE
222 		if (strcmp(_yp_domain, indomain) == 0)
223 			if (!ypmatch_add(inmap, inkey, inkeylen,
224 			    *outval, *outvallen))
225 				r = YPERR_RESRC;
226 #endif
227 	}
228 out:
229 	xdr_free(xdr_ypresp_val, (char *) &yprv);
230 	_yp_unbind(ysd);
231 	return r;
232 }
233 
234 int
235 yp_next(indomain, inmap, inkey, inkeylen, outkey, outkeylen, outval, outvallen)
236 	const char     *indomain;
237 	const char     *inmap;
238 	const char     *inkey;
239 	int             inkeylen;
240 	char          **outkey;
241 	int            *outkeylen;
242 	char          **outval;
243 	int            *outvallen;
244 {
245 	struct ypresp_key_val yprkv;
246 	struct ypreq_key yprk;
247 	struct dom_binding *ysd;
248 	struct timeval  tv;
249 	int tries = 0, r;
250 
251 	if (indomain == NULL || *indomain == '\0' ||
252 	    strlen(indomain) > YPMAXDOMAIN || inmap == NULL ||
253 	    *inmap == '\0' || strlen(inmap) > YPMAXMAP ||
254 	    inkeylen == 0 || inkeylen >= YPMAXRECORD)
255 		return YPERR_BADARGS;
256 
257 	*outkey = *outval = NULL;
258 	*outkeylen = *outvallen = 0;
259 
260 again:
261 	if (_yp_dobind(indomain, &ysd) != 0)
262 		return YPERR_DOMAIN;
263 
264 	tv.tv_sec = _yplib_timeout;
265 	tv.tv_usec = 0;
266 
267 	yprk.domain = (char *)indomain;
268 	yprk.map = (char *)inmap;
269 	yprk.key.keydat_val = (char *)inkey;
270 	yprk.key.keydat_len = inkeylen;
271 	(void)memset(&yprkv, 0, sizeof yprkv);
272 
273 	r = clnt_call(ysd->dom_client, YPPROC_NEXT,
274 	    xdr_ypreq_key, &yprk, xdr_ypresp_key_val, &yprkv, tv);
275 	if (r != RPC_SUCCESS) {
276 		if (tries++)
277 			clnt_perror(ysd->dom_client, "yp_next: clnt_call");
278 		ysd->dom_vers = -1;
279 		goto again;
280 	}
281 	if (!(r = ypprot_err(yprkv.stat))) {
282 		*outkeylen = yprkv.key.keydat_len;
283 		if ((*outkey = malloc(*outkeylen + 1)) == NULL)
284 			r = YPERR_RESRC;
285 		else {
286 			(void)memcpy(*outkey, yprkv.key.keydat_val, *outkeylen);
287 			(*outkey)[*outkeylen] = '\0';
288 		}
289 		*outvallen = yprkv.val.valdat_len;
290 		if ((*outval = malloc(*outvallen + 1)) == NULL)
291 			r = YPERR_RESRC;
292 		else {
293 			(void)memcpy(*outval, yprkv.val.valdat_val, *outvallen);
294 			(*outval)[*outvallen] = '\0';
295 		}
296 	}
297 	xdr_free(xdr_ypresp_key_val, (char *) &yprkv);
298 	_yp_unbind(ysd);
299 	return r;
300 }
301