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
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]
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
38 #pragma ident "%Z%%M% %I% %E% SMI"
45 #include <sys/types.h>
47 #include <rpcsvc/yp_prot.h>
48 #include <rpcsvc/ypclnt.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();
72 static mutex_t cache_lock
= DEFAULTMUTEX
;
73 static int generation
; /* Incremented when we add to cache */
74 static struct cache
*head
;
80 freenode(struct cache
*n
)
94 * Attempt to Add item to cache
97 makenode(char *domain
, char *map
, int keylen
, int vallen
)
101 /* Do not cache 'passwd' values i.e. passwd.byname or passwd.byuid. */
102 if (strncmp(map
, "passwd", 6) == 0)
105 if ((n
= calloc(1, sizeof (*n
))) == 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)) {
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.
123 in_cache(char *domain
, char *map
, char *key
, int keylen
, char **val
,
126 struct cache
*c
, **pp
;
131 /* The 'passwd' data is not cached. */
132 if (strncmp(map
, "passwd", 6) == 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)) {
144 (void) gettimeofday(&now
, &tz
);
145 if ((now
.tv_sec
- c
->birth
) > CACHETO
) {
146 /* rats. it is too old to use */
154 /* Ersatz LRU: Move this entry to the front */
161 if (cnt
>= CACHESZ
) {
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
)
183 struct dom_binding
*pdomb
;
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
;
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
);
216 (void) mutex_unlock(&cache_lock
);
217 return (0); /* Success */
219 (void) mutex_unlock(&cache_lock
);
223 if (reason
= __yp_dobind_cflookup(domain
, &pdomb
, hardlookup
))
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 */) {
236 (void) sleep(_ypsleeptime
); /* retry */
242 __yp_rel_binding(pdomb
);
247 /* add to our cache */
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...
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
);
275 (void) gettimeofday(&now
, &tz
);
276 c
->birth
= now
.tv_sec
;
279 (void) memcpy(c
->key
, key
, (size_t)keylen
);
280 (void) memcpy(c
->val
, *val
, (size_t)savesize
);
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
295 rsvdreason
= yp_match_rsvdport(domain
, map
, key
, keylen
, val
,
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));
318 __empty_yp_cache(void)
322 /* Copy the cache pointer and make it ZERO */
323 (void) mutex_lock(&cache_lock
);
326 (void) mutex_unlock(&cache_lock
);
331 /* Empty the cache */
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
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(
360 char **val
, /* returns value array */
361 int *vallen
, /* returns bytes in val */
362 int hardlookup
) /* retry until we can an answer */
367 struct dom_binding
*pdomb
;
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
;
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
);
399 (void) mutex_unlock(&cache_lock
);
400 return (0); /* Success */
402 (void) mutex_unlock(&cache_lock
);
406 if (reason
= __yp_dobind_rsvdport_cflookup(domain
, &pdomb
,
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 */) {
426 (void) sleep(_ypsleeptime
); /* retry */
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
);
442 /* add to our cache */
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...
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
);
470 (void) gettimeofday(&now
, &tz
);
471 c
->birth
= now
.tv_sec
;
474 (void) memcpy(c
->key
, key
, (size_t)keylen
);
475 (void) memcpy(c
->val
, *val
, (size_t)savesize
);
482 (void) mutex_unlock(&cache_lock
);
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
,
504 * This talks v3 protocol to ypserv
507 domatch(char *domain
, char *map
, char *key
, int keylen
,
508 struct dom_binding
*pdomb
, struct timeval
*timeoutp
, char **val
,
511 struct ypreq_key req
;
512 struct ypresp_val resp
;
513 unsigned int retval
= 0;
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
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
,
536 return (YPERR_YPSERV
);
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 */
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
);