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