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