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