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