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