xref: /openbsd/lib/libc/yp/ypmatch_cache.c (revision db3296cf)
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  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #if defined(LIBC_SCCS) && !defined(lint)
28 static char *rcsid = "$OpenBSD: ypmatch_cache.c,v 1.11 2003/06/25 21:51:56 marc Exp $";
29 #endif /* LIBC_SCCS and not lint */
30 
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/file.h>
35 #include <sys/uio.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <rpc/rpc.h>
42 #include <rpc/xdr.h>
43 #include <rpcsvc/yp.h>
44 #include <rpcsvc/ypclnt.h>
45 #include "ypinternal.h"
46 
47 static bool_t ypmatch_add(const char *, const char *, u_int, char *, u_int);
48 static bool_t ypmatch_find(const char *, const char *, u_int, char **, u_int *);
49 
50 static struct ypmatch_ent {
51 	struct ypmatch_ent	*next;
52 	char			*map, *key;
53 	char			*val;
54 	int			 keylen, vallen;
55 	time_t			 expire_t;
56 } *ypmc;
57 
58 int _yplib_cache = 5;
59 
60 static bool_t
61 ypmatch_add(const char *map, const char *key, u_int keylen, char *val,
62     u_int vallen)
63 {
64 	struct ypmatch_ent *ep;
65 	time_t t;
66 
67 	if (keylen == 0 || vallen == 0)
68 		return (0);
69 
70 	(void)time(&t);
71 
72 	for (ep = ypmc; ep; ep = ep->next)
73 		if (ep->expire_t < t)
74 			break;
75 	if (ep == NULL) {
76 		if ((ep = malloc(sizeof *ep)) == NULL)
77 			return 0;
78 		(void)memset(ep, 0, sizeof *ep);
79 		if (ypmc)
80 			ep->next = ypmc;
81 		ypmc = ep;
82 	}
83 
84 	if (ep->key) {
85 		free(ep->key);
86 		ep->key = NULL;
87 	}
88 	if (ep->val) {
89 		free(ep->val);
90 		ep->val = NULL;
91 	}
92 
93 	if ((ep->key = malloc(keylen)) == NULL)
94 		return 0;
95 
96 	if ((ep->val = malloc(vallen)) == NULL) {
97 		free(ep->key);
98 		ep->key = NULL;
99 		return 0;
100 	}
101 
102 	ep->keylen = keylen;
103 	ep->vallen = vallen;
104 
105 	(void)memcpy(ep->key, key, ep->keylen);
106 	(void)memcpy(ep->val, val, ep->vallen);
107 
108 	if (ep->map) {
109 		if (strcmp(ep->map, map)) {
110 			free(ep->map);
111 			if ((ep->map = strdup(map)) == NULL)
112 				return 0;
113 		}
114 	} else {
115 		if ((ep->map = strdup(map)) == NULL)
116 			return 0;
117 	}
118 
119 	ep->expire_t = t + _yplib_cache;
120 	return 1;
121 }
122 
123 static bool_t
124 ypmatch_find(const char *map, const char *key, u_int keylen, 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(const char *indomain, const char *inmap, const char *inkey,
154     int inkeylen, char **outval, int *outvallen)
155 {
156 	struct dom_binding *ysd;
157 	struct ypresp_val yprv;
158 	struct timeval  tv;
159 	struct ypreq_key yprk;
160 	int tries = 0, r;
161 
162 	if (indomain == NULL || *indomain == '\0' ||
163 	    strlen(indomain) > YPMAXDOMAIN || inmap == NULL ||
164 	    *inmap == '\0' || strlen(inmap) > YPMAXMAP ||
165 	    inkey == NULL || inkeylen == 0 || inkeylen >= YPMAXRECORD)
166 		return YPERR_BADARGS;
167 
168 	*outval = NULL;
169 	*outvallen = 0;
170 
171 again:
172 	if (_yp_dobind(indomain, &ysd) != 0)
173 		return YPERR_DOMAIN;
174 
175 #ifdef YPMATCHCACHE
176 	if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
177 	    inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) {
178 		*outvallen = yprv.val.valdat_len;
179 		if ((*outval = malloc(*outvallen + 1)) == NULL) {
180 			_yp_unbind(ysd);
181 			return YPERR_YPERR;
182 		}
183 		(void)memcpy(*outval, yprv.val.valdat_val, *outvallen);
184 		(*outval)[*outvallen] = '\0';
185 		_yp_unbind(ysd);
186 		return 0;
187 	}
188 #endif
189 
190 	tv.tv_sec = _yplib_timeout;
191 	tv.tv_usec = 0;
192 
193 	yprk.domain = (char *)indomain;
194 	yprk.map = (char *)inmap;
195 	yprk.key.keydat_val = (char *) inkey;
196 	yprk.key.keydat_len = inkeylen;
197 
198 	memset(&yprv, 0, sizeof yprv);
199 
200 	r = clnt_call(ysd->dom_client, YPPROC_MATCH,
201 	    xdr_ypreq_key, &yprk, xdr_ypresp_val, &yprv, tv);
202 	if (r != RPC_SUCCESS) {
203 		if (tries++)
204 			clnt_perror(ysd->dom_client, "yp_match: clnt_call");
205 		ysd->dom_vers = -1;
206 		goto again;
207 	}
208 	if (!(r = ypprot_err(yprv.stat))) {
209 		*outvallen = yprv.val.valdat_len;
210 		if ((*outval = malloc(*outvallen + 1)) == NULL) {
211 			r = YPERR_YPERR;
212 			goto out;
213 		}
214 		(void)memcpy(*outval, yprv.val.valdat_val, *outvallen);
215 		(*outval)[*outvallen] = '\0';
216 #ifdef YPMATCHCACHE
217 		if (strcmp(_yp_domain, indomain) == 0)
218 			if (!ypmatch_add(inmap, inkey, inkeylen,
219 			    *outval, *outvallen))
220 				r = YPERR_RESRC;
221 #endif
222 	}
223 out:
224 	xdr_free(xdr_ypresp_val, (char *) &yprv);
225 	_yp_unbind(ysd);
226 	return r;
227 }
228 
229 int
230 yp_next(const char *indomain, const char *inmap, const char *inkey,
231     int inkeylen, char **outkey, int *outkeylen, char **outval, int *outvallen)
232 {
233 	struct ypresp_key_val yprkv;
234 	struct ypreq_key yprk;
235 	struct dom_binding *ysd;
236 	struct timeval  tv;
237 	int tries = 0, r;
238 
239 	if (indomain == NULL || *indomain == '\0' ||
240 	    strlen(indomain) > YPMAXDOMAIN || inmap == NULL ||
241 	    *inmap == '\0' || strlen(inmap) > YPMAXMAP ||
242 	    inkeylen == 0 || inkeylen >= YPMAXRECORD)
243 		return YPERR_BADARGS;
244 
245 	*outkey = *outval = NULL;
246 	*outkeylen = *outvallen = 0;
247 
248 again:
249 	if (_yp_dobind(indomain, &ysd) != 0)
250 		return YPERR_DOMAIN;
251 
252 	tv.tv_sec = _yplib_timeout;
253 	tv.tv_usec = 0;
254 
255 	yprk.domain = (char *)indomain;
256 	yprk.map = (char *)inmap;
257 	yprk.key.keydat_val = (char *)inkey;
258 	yprk.key.keydat_len = inkeylen;
259 	(void)memset(&yprkv, 0, sizeof yprkv);
260 
261 	r = clnt_call(ysd->dom_client, YPPROC_NEXT,
262 	    xdr_ypreq_key, &yprk, xdr_ypresp_key_val, &yprkv, tv);
263 	if (r != RPC_SUCCESS) {
264 		if (tries++)
265 			clnt_perror(ysd->dom_client, "yp_next: clnt_call");
266 		ysd->dom_vers = -1;
267 		goto again;
268 	}
269 	if (!(r = ypprot_err(yprkv.stat))) {
270 		*outkeylen = yprkv.key.keydat_len;
271 		if ((*outkey = malloc(*outkeylen + 1)) == NULL)
272 			r = YPERR_RESRC;
273 		else {
274 			(void)memcpy(*outkey, yprkv.key.keydat_val, *outkeylen);
275 			(*outkey)[*outkeylen] = '\0';
276 		}
277 		*outvallen = yprkv.val.valdat_len;
278 		if ((*outval = malloc(*outvallen + 1)) == NULL)
279 			r = YPERR_RESRC;
280 		else {
281 			(void)memcpy(*outval, yprkv.val.valdat_val, *outvallen);
282 			(*outval)[*outvallen] = '\0';
283 		}
284 	}
285 	xdr_free(xdr_ypresp_key_val, (char *) &yprkv);
286 	_yp_unbind(ysd);
287 	return r;
288 }
289