import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / nsl / yp_match.c
blobe0b46a4025dd0023e40c2f4f2da3a30b25de9a9d
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 * Copyright (c) 2016 by Delphix. All rights reserved.
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
33 * Portions of this source code were derived from Berkeley
34 * under license from the Regents of the University of
35 * California.
38 #pragma ident "%Z%%M% %I% %E% SMI"
40 #include "mt.h"
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include "rpc_mt.h"
44 #include <rpc/rpc.h>
45 #include <sys/types.h>
46 #include "yp_b.h"
47 #include <rpcsvc/yp_prot.h>
48 #include <rpcsvc/ypclnt.h>
49 #include <malloc.h>
50 #include <string.h>
51 #include <sys/time.h>
53 extern int __yp_dobind_cflookup(char *, struct dom_binding **, int);
54 extern int __yp_dobind_rsvdport_cflookup(char *, struct dom_binding **, int);
56 static int domatch(char *, char *, char *, int, struct dom_binding *,
57 struct timeval *, char **, int *);
58 int yp_match_rsvdport();
59 int yp_match_rsvdport_cflookup();
61 struct cache {
62 struct cache *next;
63 unsigned int birth;
64 char *domain;
65 char *map;
66 char *key;
67 int keylen;
68 char *val;
69 int vallen;
72 static mutex_t cache_lock = DEFAULTMUTEX;
73 static int generation; /* Incremented when we add to cache */
74 static struct cache *head;
76 #define CACHESZ 16
77 #define CACHETO 600
79 static void
80 freenode(struct cache *n)
82 if (n->val != 0)
83 free(n->val);
84 if (n->key != 0)
85 free(n->key);
86 if (n->map != 0)
87 free(n->map);
88 if (n->domain != 0)
89 free(n->domain);
90 free(n);
94 * Attempt to Add item to cache
96 static struct cache *
97 makenode(char *domain, char *map, int keylen, int vallen)
99 struct cache *n;
101 /* Do not cache 'passwd' values i.e. passwd.byname or passwd.byuid. */
102 if (strncmp(map, "passwd", 6) == 0)
103 return (0);
105 if ((n = calloc(1, sizeof (*n))) == 0)
106 return (0);
107 if (((n->domain = strdup(domain)) == 0) ||
108 ((n->map = strdup(map)) == 0) ||
109 ((n->key = malloc(keylen)) == 0) ||
110 ((n->val = malloc(vallen)) == 0)) {
111 freenode(n);
112 return (0);
114 return (n);
118 * Look for a matching result in the per-process cache.
119 * Upon finding a match set the passed in 'val' and 'vallen'
120 * parameters and return 1. Otherwise return 0.
122 static int
123 in_cache(char *domain, char *map, char *key, int keylen, char **val,
124 int *vallen)
126 struct cache *c, **pp;
127 int cnt;
128 struct timeval now;
129 struct timezone tz;
131 /* The 'passwd' data is not cached. */
132 if (strncmp(map, "passwd", 6) == 0)
133 return (0);
136 * Assumes that caller (yp_match) has locked the cache
138 for (pp = &head, cnt = 0; (c = *pp) != 0; pp = &c->next, cnt++) {
139 if ((c->keylen == keylen) &&
140 (memcmp(key, c->key, (size_t)keylen) == 0) &&
141 (strcmp(map, c->map) == 0) &&
142 (strcmp(domain, c->domain) == 0)) {
143 /* cache hit */
144 (void) gettimeofday(&now, &tz);
145 if ((now.tv_sec - c->birth) > CACHETO) {
146 /* rats. it is too old to use */
147 *pp = c->next;
148 freenode(c);
149 break;
150 } else {
151 *val = c->val;
152 *vallen = c->vallen;
154 /* Ersatz LRU: Move this entry to the front */
155 *pp = c->next;
156 c->next = head;
157 head = c;
158 return (1);
161 if (cnt >= CACHESZ) {
162 *pp = c->next;
163 freenode(c);
164 break;
167 return (0);
171 * Requests the yp server associated with a given domain to attempt to match
172 * the passed key datum in the named map, and to return the associated value
173 * datum. This part does parameter checking, and implements the "infinite"
174 * (until success) sleep loop if 'hardlookup' parameter is set.
177 __yp_match_cflookup(char *domain, char *map, char *key, int keylen, char **val,
178 int *vallen, int hardlookup)
180 size_t domlen;
181 size_t maplen;
182 int reason;
183 struct dom_binding *pdomb;
184 int savesize;
185 struct timeval now;
186 struct timezone tz;
187 char *my_val;
188 int my_vallen;
189 int found_it;
190 int cachegen;
192 if ((map == NULL) || (domain == NULL))
193 return (YPERR_BADARGS);
195 domlen = strlen(domain);
196 maplen = strlen(map);
198 if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
199 (maplen == 0) || (maplen > YPMAXMAP) ||
200 (key == NULL) || (keylen == 0))
201 return (YPERR_BADARGS);
203 (void) mutex_lock(&cache_lock);
204 found_it = in_cache(domain, map, key, keylen, &my_val, &my_vallen);
205 cachegen = generation;
207 if (found_it) {
208 /* NB: Copy two extra bytes; see below */
209 savesize = my_vallen + 2;
210 if ((*val = malloc((size_t)savesize)) == 0) {
211 (void) mutex_unlock(&cache_lock);
212 return (YPERR_RESRC);
214 (void) memcpy(*val, my_val, (size_t)savesize);
215 *vallen = my_vallen;
216 (void) mutex_unlock(&cache_lock);
217 return (0); /* Success */
219 (void) mutex_unlock(&cache_lock);
221 for (;;) {
223 if (reason = __yp_dobind_cflookup(domain, &pdomb, hardlookup))
224 return (reason);
226 if (pdomb->dom_binding->ypbind_hi_vers >= YPVERS) {
228 reason = domatch(domain, map, key, keylen, pdomb,
229 &_ypserv_timeout, val, vallen);
231 __yp_rel_binding(pdomb);
232 if (reason == YPERR_RPC || reason == YPERR_YPSERV ||
233 reason == YPERR_BUSY /* as if */) {
234 yp_unbind(domain);
235 if (hardlookup)
236 (void) sleep(_ypsleeptime); /* retry */
237 else
238 return (reason);
239 } else
240 break;
241 } else {
242 __yp_rel_binding(pdomb);
243 return (YPERR_VERS);
247 /* add to our cache */
248 if (reason == 0) {
249 (void) mutex_lock(&cache_lock);
251 * Check whether some other annoying thread did the same
252 * thing in parallel with us. I hate it when that happens...
254 if (generation != cachegen &&
255 in_cache(domain, map, key, keylen, &my_val, &my_vallen)) {
257 * Could get cute and update the birth time, but it's
258 * not worth the bother.
259 * It looks strange that we return one val[] array
260 * to the caller and have a different copy of the
261 * val[] array in the cache (presumably with the
262 * same contents), but it should work just fine.
263 * So, do absolutely nothing...
265 /* EMPTY */
266 } else {
267 struct cache *c;
269 * NB: allocate and copy extract two bytes of the
270 * value; these are mandatory CR and NULL bytes.
272 savesize = *vallen + 2;
273 c = makenode(domain, map, keylen, savesize);
274 if (c != 0) {
275 (void) gettimeofday(&now, &tz);
276 c->birth = now.tv_sec;
277 c->keylen = keylen;
278 c->vallen = *vallen;
279 (void) memcpy(c->key, key, (size_t)keylen);
280 (void) memcpy(c->val, *val, (size_t)savesize);
282 c->next = head;
283 head = c;
284 ++generation;
287 (void) mutex_unlock(&cache_lock);
288 } else if (reason == YPERR_MAP && geteuid() == 0) {
290 * Lookup could be for a secure map; fail over to retry
291 * from a reserved port. Only useful to try this if we're
292 * the super user.
294 int rsvdreason;
295 rsvdreason = yp_match_rsvdport(domain, map, key, keylen, val,
296 vallen);
297 if (rsvdreason == 0)
298 reason = rsvdreason;
300 return (reason);
304 yp_match(
305 char *domain,
306 char *map,
307 char *key,
308 int keylen,
309 char **val, /* returns value array */
310 int *vallen) /* returns bytes in val */
313 /* the traditional yp_match loops forever thus hardlookup is set */
314 return (__yp_match_cflookup(domain, map, key, keylen, val, vallen, 1));
317 extern void
318 __empty_yp_cache(void)
320 struct cache *p, *n;
322 /* Copy the cache pointer and make it ZERO */
323 (void) mutex_lock(&cache_lock);
324 p = head;
325 head = 0;
326 (void) mutex_unlock(&cache_lock);
328 if (p == 0)
329 return;
331 /* Empty the cache */
332 n = p->next;
333 while (p) {
334 freenode(p);
335 p = n;
336 if (p)
337 n = p->next;
342 * Requests the yp server associated with a given domain to attempt to match
343 * the passed key datum in the named map, and to return the associated value
344 * datum. This part does parameter checking, and implements the "infinite"
345 * (until success) sleep loop.
347 * XXX special version for handling C2 (passwd.adjunct) lookups when we need
348 * a reserved port.
349 * Only difference against yp_match is that this function uses
350 * __yp_dobind_rsvdport().
352 * Only called from NIS switch backend.
355 __yp_match_rsvdport_cflookup(
356 char *domain,
357 char *map,
358 char *key,
359 int keylen,
360 char **val, /* returns value array */
361 int *vallen, /* returns bytes in val */
362 int hardlookup) /* retry until we can an answer */
364 size_t domlen;
365 size_t maplen;
366 int reason;
367 struct dom_binding *pdomb;
368 int savesize;
369 struct timeval now;
370 struct timezone tz;
371 char *my_val;
372 int my_vallen;
373 int found_it;
374 int cachegen;
376 if ((map == NULL) || (domain == NULL))
377 return (YPERR_BADARGS);
379 domlen = strlen(domain);
380 maplen = strlen(map);
382 if ((domlen == 0) || (domlen > YPMAXDOMAIN) ||
383 (maplen == 0) || (maplen > YPMAXMAP) ||
384 (key == NULL) || (keylen == 0))
385 return (YPERR_BADARGS);
387 (void) mutex_lock(&cache_lock);
388 found_it = in_cache(domain, map, key, keylen, &my_val, &my_vallen);
389 cachegen = generation;
390 if (found_it) {
391 /* NB: Copy two extra bytes; see below */
392 savesize = my_vallen + 2;
393 if ((*val = malloc((size_t)savesize)) == 0) {
394 (void) mutex_unlock(&cache_lock);
395 return (YPERR_RESRC);
397 (void) memcpy(*val, my_val, (size_t)savesize);
398 *vallen = my_vallen;
399 (void) mutex_unlock(&cache_lock);
400 return (0); /* Success */
402 (void) mutex_unlock(&cache_lock);
404 for (;;) {
406 if (reason = __yp_dobind_rsvdport_cflookup(domain, &pdomb,
407 hardlookup))
408 return (reason);
410 if (pdomb->dom_binding->ypbind_hi_vers >= YPVERS) {
412 reason = domatch(domain, map, key, keylen,
413 pdomb, &_ypserv_timeout, val, vallen);
416 * Have to free the binding since the reserved
417 * port bindings are not cached.
419 __yp_rel_binding(pdomb);
420 free_dom_binding(pdomb);
422 if (reason == YPERR_RPC || reason == YPERR_YPSERV ||
423 reason == YPERR_BUSY /* as if */) {
424 yp_unbind(domain);
425 if (hardlookup)
426 (void) sleep(_ypsleeptime); /* retry */
427 else
428 return (reason);
429 } else
430 break;
431 } else {
433 * Have to free the binding since the reserved
434 * port bindings are not cached.
436 __yp_rel_binding(pdomb);
437 free_dom_binding(pdomb);
438 return (YPERR_VERS);
442 /* add to our cache */
443 if (reason == 0) {
444 (void) mutex_lock(&cache_lock);
446 * Check whether some other annoying thread did the same
447 * thing in parallel with us. I hate it when that happens...
449 if (generation != cachegen &&
450 in_cache(domain, map, key, keylen, &my_val, &my_vallen)) {
452 * Could get cute and update the birth time, but it's
453 * not worth the bother.
454 * It looks strange that we return one val[] array
455 * to the caller and have a different copy of the
456 * val[] array in the cache (presumably with the
457 * same contents), but it should work just fine.
458 * So, do absolutely nothing...
460 /* EMPTY */
461 } else {
462 struct cache *c;
464 * NB: allocate and copy extract two bytes of the
465 * value; these are mandatory CR and NULL bytes.
467 savesize = *vallen + 2;
468 c = makenode(domain, map, keylen, savesize);
469 if (c != 0) {
470 (void) gettimeofday(&now, &tz);
471 c->birth = now.tv_sec;
472 c->keylen = keylen;
473 c->vallen = *vallen;
474 (void) memcpy(c->key, key, (size_t)keylen);
475 (void) memcpy(c->val, *val, (size_t)savesize);
477 c->next = head;
478 head = c;
479 ++generation;
482 (void) mutex_unlock(&cache_lock);
484 return (reason);
489 yp_match_rsvdport(
490 char *domain,
491 char *map,
492 char *key,
493 int keylen,
494 char **val, /* returns value array */
495 int *vallen) /* returns bytes in val */
497 /* traditional yp_match retries forever so set hardlookup */
498 return (__yp_match_rsvdport_cflookup(domain, map, key, keylen, val,
499 vallen, 1));
504 * This talks v3 protocol to ypserv
506 static int
507 domatch(char *domain, char *map, char *key, int keylen,
508 struct dom_binding *pdomb, struct timeval *timeoutp, char **val,
509 int *vallen)
511 struct ypreq_key req;
512 struct ypresp_val resp;
513 unsigned int retval = 0;
515 req.domain = domain;
516 req.map = map;
517 req.keydat.dptr = key;
518 req.keydat.dsize = keylen;
520 resp.valdat.dptr = NULL;
521 resp.valdat.dsize = 0;
522 (void) memset((char *)&resp, 0, sizeof (struct ypresp_val));
525 * Do the match request. If the rpc call failed, return with status
526 * from this point.
529 switch (clnt_call(pdomb->dom_client, YPPROC_MATCH,
530 (xdrproc_t)xdr_ypreq_key, (char *)&req,
531 (xdrproc_t)xdr_ypresp_val, (char *)&resp,
532 *timeoutp)) {
533 case RPC_SUCCESS:
534 break;
535 case RPC_TIMEDOUT:
536 return (YPERR_YPSERV);
537 default:
538 return (YPERR_RPC);
541 /* See if the request succeeded */
543 if (resp.status != YP_TRUE) {
544 retval = ypprot_err(resp.status);
547 /* Get some memory which the user can get rid of as they likes */
549 if (!retval && ((*val = malloc((size_t)
550 resp.valdat.dsize + 2)) == NULL)) {
551 retval = YPERR_RESRC;
554 /* Copy the returned value byte string into the new memory */
556 if (!retval) {
557 *vallen = (int)resp.valdat.dsize;
558 (void) memcpy(*val, resp.valdat.dptr,
559 (size_t)resp.valdat.dsize);
560 (*val)[resp.valdat.dsize] = '\n';
561 (*val)[resp.valdat.dsize + 1] = '\0';
564 CLNT_FREERES(pdomb->dom_client,
565 (xdrproc_t)xdr_ypresp_val, (char *)&resp);
566 return (retval);