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