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