1 /* $NetBSD: yp_match.c,v 1.19 2012/03/20 16:30:26 matt 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.19 2012/03/20 16:30:26 matt 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 int _yplib_bindtries; 51 extern char _yp_domain[]; 52 53 #ifdef __weak_alias 54 __weak_alias(yp_match,_yp_match) 55 #endif 56 57 #ifdef YPMATCHCACHE 58 int _yplib_cache = 5; 59 60 static struct ypmatch_ent { 61 struct ypmatch_ent *next; 62 char *map, *key; 63 char *val; 64 int keylen, vallen; 65 time_t expire_t; 66 } *ypmc; 67 68 static bool_t ypmatch_add(const char *, const char *, int, char *, int); 69 static bool_t ypmatch_find(const char *, const char *, int, const char **, 70 int *); 71 72 static bool_t 73 ypmatch_add(const char *map, const char *key, int keylen, char *val, int vallen) 74 { 75 struct ypmatch_ent *ep; 76 time_t t; 77 78 _DIAGASSERT(map != NULL); 79 _DIAGASSERT(key != NULL); 80 _DIAGASSERT(val != NULL); 81 82 (void)time(&t); 83 84 for (ep = ypmc; ep; ep = ep->next) 85 if (ep->expire_t < t) 86 break; 87 if (ep == NULL) { 88 if ((ep = malloc(sizeof *ep)) == NULL) 89 return 0; 90 (void)memset(ep, 0, sizeof *ep); 91 if (ypmc) 92 ep->next = ypmc; 93 ypmc = ep; 94 } 95 96 if (ep->key) { 97 free(ep->key); 98 ep->key = NULL; 99 } 100 if (ep->val) { 101 free(ep->val); 102 ep->val = NULL; 103 } 104 105 if ((ep->key = malloc((size_t)keylen)) == NULL) 106 return 0; 107 108 if ((ep->val = malloc((size_t)vallen)) == NULL) { 109 free(ep->key); 110 ep->key = NULL; 111 return 0; 112 } 113 114 ep->keylen = keylen; 115 ep->vallen = vallen; 116 117 (void)memcpy(ep->key, key, (size_t)ep->keylen); 118 (void)memcpy(ep->val, val, (size_t)ep->vallen); 119 120 if (ep->map) { 121 if (strcmp(ep->map, map)) { 122 free(ep->map); 123 if ((ep->map = strdup(map)) == NULL) 124 return 0; 125 } 126 } else { 127 if ((ep->map = strdup(map)) == NULL) 128 return 0; 129 } 130 131 ep->expire_t = t + _yplib_cache; 132 return 1; 133 } 134 135 static bool_t 136 ypmatch_find(const char *map, const char *key, int keylen, const char **val, 137 int *vallen) 138 { 139 struct ypmatch_ent *ep; 140 time_t t; 141 142 _DIAGASSERT(map != NULL); 143 _DIAGASSERT(key != NULL); 144 _DIAGASSERT(val != NULL); 145 146 if (ypmc == NULL) 147 return 0; 148 149 (void) time(&t); 150 151 for (ep = ypmc; ep; ep = ep->next) { 152 if (ep->keylen != keylen) 153 continue; 154 if (strcmp(ep->map, map)) 155 continue; 156 if (memcmp(ep->key, key, (size_t)keylen)) 157 continue; 158 if (t > ep->expire_t) 159 continue; 160 161 *val = ep->val; 162 *vallen = ep->vallen; 163 return 1; 164 } 165 return 0; 166 } 167 #endif 168 169 int 170 yp_match(const char *indomain, const char *inmap, const char *inkey, 171 int inkeylen, char **outval, int *outvallen) 172 { 173 struct dom_binding *ysd; 174 struct ypresp_val yprv; 175 struct ypreq_key yprk; 176 int r, nerrs = 0; 177 178 if (outval == NULL || outvallen == NULL) 179 return YPERR_BADARGS; 180 *outval = NULL; 181 *outvallen = 0; 182 183 if (_yp_invalid_domain(indomain)) 184 return YPERR_BADARGS; 185 if (inmap == NULL || *inmap == '\0' 186 || strlen(inmap) > YPMAXMAP) 187 return YPERR_BADARGS; 188 if (inkey == NULL || inkeylen == 0) 189 return YPERR_BADARGS; 190 191 again: 192 if (_yp_dobind(indomain, &ysd) != 0) 193 return YPERR_DOMAIN; 194 195 #ifdef YPMATCHCACHE 196 if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey, 197 inkeylen, &yprv.valdat.dptr, &yprv.valdat.dsize)) { 198 *outvallen = yprv.valdat.dsize; 199 if ((*outval = malloc((size_t)(*outvallen + 1))) == NULL) 200 return YPERR_YPERR; 201 (void)memcpy(*outval, yprv.valdat.dptr, (size_t)*outvallen); 202 (*outval)[*outvallen] = '\0'; 203 return 0; 204 } 205 #endif 206 207 yprk.domain = indomain; 208 yprk.map = inmap; 209 yprk.keydat.dptr = __UNCONST(inkey); 210 yprk.keydat.dsize = inkeylen; 211 212 memset(&yprv, 0, sizeof yprv); 213 214 r = clnt_call(ysd->dom_client, (rpcproc_t)YPPROC_MATCH, 215 (xdrproc_t)xdr_ypreq_key, &yprk, 216 (xdrproc_t)xdr_ypresp_val, &yprv, 217 _yplib_timeout); 218 if (r != RPC_SUCCESS) { 219 if (_yplib_bindtries <= 0 && ++nerrs == _yplib_nerrs) { 220 clnt_perror(ysd->dom_client, "yp_match: clnt_call"); 221 nerrs = 0; 222 } 223 else if (_yplib_bindtries > 0 && ++nerrs == _yplib_bindtries) { 224 return YPERR_YPSERV; 225 } 226 ysd->dom_vers = -1; 227 goto again; 228 } 229 if (!(r = ypprot_err(yprv.status))) { 230 *outvallen = yprv.valdat.dsize; 231 if ((*outval = malloc((size_t)(*outvallen + 1))) == NULL) 232 return YPERR_YPERR; 233 (void)memcpy(*outval, yprv.valdat.dptr, (size_t)*outvallen); 234 (*outval)[*outvallen] = '\0'; 235 #ifdef YPMATCHCACHE 236 if (strcmp(_yp_domain, indomain) == 0) 237 if (!ypmatch_add(inmap, inkey, inkeylen, 238 *outval, *outvallen)) 239 r = YPERR_RESRC; 240 #endif 241 } 242 xdr_free((xdrproc_t)xdr_ypresp_val, (char *)(void *)&yprv); 243 __yp_unbind(ysd); 244 if (r != 0) { 245 if (*outval) { 246 free(*outval); 247 *outval = NULL; 248 } 249 } 250 return r; 251 } 252