1 /* $OpenBSD: ypmatch_cache.c,v 1.17 2015/09/13 20:57:28 guenther 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/types.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <limits.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 char *newmap = NULL, *newkey = NULL, *newval = NULL; 58 time_t t; 59 60 if (keylen == 0 || vallen == 0) 61 return (0); 62 63 (void)time(&t); 64 65 /* Allocate all required memory first. */ 66 if ((newmap = strdup(map)) == NULL || 67 (newkey = malloc(keylen)) == NULL || 68 (newval = malloc(vallen)) == NULL) { 69 free(newkey); 70 free(newmap); 71 return 0; 72 } 73 74 for (ep = ypmc; ep; ep = ep->next) 75 if (ep->expire_t < t) 76 break; 77 78 if (ep == NULL) { 79 /* No expired node, create a new one. */ 80 if ((ep = malloc(sizeof *ep)) == NULL) { 81 free(newval); 82 free(newkey); 83 free(newmap); 84 return 0; 85 } 86 ep->next = ypmc; 87 ypmc = ep; 88 } else { 89 /* Reuse the first expired node from the list. */ 90 free(ep->val); 91 free(ep->key); 92 free(ep->map); 93 } 94 95 /* Now we have all the memory we need, copy the data in. */ 96 (void)memcpy(newkey, key, keylen); 97 (void)memcpy(newval, val, vallen); 98 ep->map = newmap; 99 ep->key = newkey; 100 ep->val = newval; 101 ep->keylen = keylen; 102 ep->vallen = vallen; 103 ep->expire_t = t + _yplib_cache; 104 return 1; 105 } 106 107 static bool_t 108 ypmatch_find(const char *map, const char *key, u_int keylen, char **val, 109 u_int *vallen) 110 { 111 struct ypmatch_ent *ep; 112 time_t t; 113 114 if (ypmc == NULL) 115 return 0; 116 117 (void) time(&t); 118 119 for (ep = ypmc; ep; ep = ep->next) { 120 if (ep->keylen != keylen) 121 continue; 122 if (strcmp(ep->map, map)) 123 continue; 124 if (memcmp(ep->key, key, keylen)) 125 continue; 126 if (t > ep->expire_t) 127 continue; 128 129 *val = ep->val; 130 *vallen = ep->vallen; 131 return 1; 132 } 133 return 0; 134 } 135 #endif 136 137 int 138 yp_match(const char *indomain, const char *inmap, const char *inkey, 139 int inkeylen, char **outval, int *outvallen) 140 { 141 struct dom_binding *ysd; 142 struct ypresp_val yprv; 143 struct timeval tv; 144 struct ypreq_key yprk; 145 int tries = 0, r; 146 147 if (indomain == NULL || *indomain == '\0' || 148 strlen(indomain) > YPMAXDOMAIN || inmap == NULL || 149 *inmap == '\0' || strlen(inmap) > YPMAXMAP || 150 inkey == NULL || inkeylen == 0 || inkeylen >= YPMAXRECORD) 151 return YPERR_BADARGS; 152 153 *outval = NULL; 154 *outvallen = 0; 155 156 again: 157 if (_yp_dobind(indomain, &ysd) != 0) 158 return YPERR_DOMAIN; 159 160 #ifdef YPMATCHCACHE 161 if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey, 162 inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) { 163 *outvallen = yprv.val.valdat_len; 164 if ((*outval = malloc(*outvallen + 1)) == NULL) { 165 _yp_unbind(ysd); 166 return YPERR_RESRC; 167 } 168 (void)memcpy(*outval, yprv.val.valdat_val, *outvallen); 169 (*outval)[*outvallen] = '\0'; 170 _yp_unbind(ysd); 171 return 0; 172 } 173 #endif 174 175 tv.tv_sec = _yplib_timeout; 176 tv.tv_usec = 0; 177 178 yprk.domain = (char *)indomain; 179 yprk.map = (char *)inmap; 180 yprk.key.keydat_val = (char *) inkey; 181 yprk.key.keydat_len = inkeylen; 182 183 memset(&yprv, 0, sizeof yprv); 184 185 r = clnt_call(ysd->dom_client, YPPROC_MATCH, 186 xdr_ypreq_key, &yprk, xdr_ypresp_val, &yprv, tv); 187 if (r != RPC_SUCCESS) { 188 if (tries++) 189 clnt_perror(ysd->dom_client, "yp_match: clnt_call"); 190 ysd->dom_vers = -1; 191 goto again; 192 } 193 if (!(r = ypprot_err(yprv.stat))) { 194 *outvallen = yprv.val.valdat_len; 195 if ((*outval = malloc(*outvallen + 1)) == NULL) { 196 r = YPERR_RESRC; 197 goto out; 198 } 199 (void)memcpy(*outval, yprv.val.valdat_val, *outvallen); 200 (*outval)[*outvallen] = '\0'; 201 #ifdef YPMATCHCACHE 202 if (strcmp(_yp_domain, indomain) == 0) 203 (void)ypmatch_add(inmap, inkey, inkeylen, 204 *outval, *outvallen); 205 #endif 206 } 207 out: 208 xdr_free(xdr_ypresp_val, (char *) &yprv); 209 _yp_unbind(ysd); 210 return r; 211 } 212 DEF_WEAK(yp_match); 213 214 int 215 yp_next(const char *indomain, const char *inmap, const char *inkey, 216 int inkeylen, char **outkey, int *outkeylen, char **outval, int *outvallen) 217 { 218 struct ypresp_key_val yprkv; 219 struct ypreq_key yprk; 220 struct dom_binding *ysd; 221 struct timeval tv; 222 int tries = 0, r; 223 224 if (indomain == NULL || *indomain == '\0' || 225 strlen(indomain) > YPMAXDOMAIN || inmap == NULL || 226 *inmap == '\0' || strlen(inmap) > YPMAXMAP || 227 inkeylen == 0 || inkeylen >= YPMAXRECORD) 228 return YPERR_BADARGS; 229 230 *outkey = *outval = NULL; 231 *outkeylen = *outvallen = 0; 232 233 again: 234 if (_yp_dobind(indomain, &ysd) != 0) 235 return YPERR_DOMAIN; 236 237 tv.tv_sec = _yplib_timeout; 238 tv.tv_usec = 0; 239 240 yprk.domain = (char *)indomain; 241 yprk.map = (char *)inmap; 242 yprk.key.keydat_val = (char *)inkey; 243 yprk.key.keydat_len = inkeylen; 244 (void)memset(&yprkv, 0, sizeof yprkv); 245 246 r = clnt_call(ysd->dom_client, YPPROC_NEXT, 247 xdr_ypreq_key, &yprk, xdr_ypresp_key_val, &yprkv, tv); 248 if (r != RPC_SUCCESS) { 249 if (tries++) 250 clnt_perror(ysd->dom_client, "yp_next: clnt_call"); 251 ysd->dom_vers = -1; 252 goto again; 253 } 254 if (!(r = ypprot_err(yprkv.stat))) { 255 *outkeylen = yprkv.key.keydat_len; 256 *outvallen = yprkv.val.valdat_len; 257 if ((*outkey = malloc(*outkeylen + 1)) == NULL || 258 (*outval = malloc(*outvallen + 1)) == NULL) { 259 free(*outkey); 260 r = YPERR_RESRC; 261 } else { 262 (void)memcpy(*outkey, yprkv.key.keydat_val, *outkeylen); 263 (*outkey)[*outkeylen] = '\0'; 264 (void)memcpy(*outval, yprkv.val.valdat_val, *outvallen); 265 (*outval)[*outvallen] = '\0'; 266 } 267 } 268 xdr_free(xdr_ypresp_key_val, (char *) &yprkv); 269 _yp_unbind(ysd); 270 return r; 271 } 272 DEF_WEAK(yp_next); 273