4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2012 Milan Jurik. All rights reserved.
28 #include <stdlib.h> /* getenv() */
34 #include <nss_dbdefs.h>
35 #include <exec_attr.h>
36 #include <gssapi/gssapi.h>
37 #include "nscd_door.h"
38 #include "nscd_switch.h"
40 #include "nscd_frontend.h"
42 #pragma weak nss_search = _nss_search
43 #define nss_search _nss_search
45 extern rwlock_t nscd_smf_service_state_lock
;
47 /* nscd id: main, forker, or child */
51 retry_test(nss_status_t res
, int n
, struct __nsw_lookup_v1
*lkp
)
53 if (res
!= NSS_TRYAGAIN
&& res
!= NSS_NISSERVDNS_TRYAGAIN
) {
54 if (res
== NSS_SUCCESS
) {
55 __NSW_UNPAUSE_ACTION(lkp
->actions
[__NSW_TRYAGAIN
]);
57 lkp
->actions
[__NSW_NISSERVDNS_TRYAGAIN
]);
62 if ((res
== NSS_TRYAGAIN
&&
63 lkp
->actions
[__NSW_TRYAGAIN
] == __NSW_TRYAGAIN_FOREVER
) ||
64 (res
== NSS_NISSERVDNS_TRYAGAIN
&&
65 lkp
->actions
[__NSW_NISSERVDNS_TRYAGAIN
] == __NSW_TRYAGAIN_FOREVER
))
68 if (res
== NSS_TRYAGAIN
&&
69 lkp
->actions
[__NSW_TRYAGAIN
] == __NSW_TRYAGAIN_NTIMES
)
70 if (n
<= lkp
->max_retries
)
73 lkp
->actions
[__NSW_TRYAGAIN
] = __NSW_TRYAGAIN_PAUSED
;
77 if (res
== NSS_NISSERVDNS_TRYAGAIN
&&
78 lkp
->actions
[__NSW_NISSERVDNS_TRYAGAIN
] == __NSW_TRYAGAIN_NTIMES
)
79 if (n
<= lkp
->max_retries
)
82 lkp
->actions
[__NSW_NISSERVDNS_TRYAGAIN
] =
83 __NSW_TRYAGAIN_PAUSED
;
90 static thread_key_t loopback_key
= THR_ONCE_KEY
;
91 typedef struct lb_key
{
99 set_loopback_key(lb_key_t
*key
) {
103 rc
= thr_keycreate_once(&loopback_key
, NULL
);
104 /* set key if not already set */
105 if (rc
== 0 && pthread_getspecific(loopback_key
) == NULL
)
106 rc
= thr_setspecific(loopback_key
, key
);
112 get_loopback_key(void) {
114 char *me
= "get_loopback_key";
117 k
= pthread_getspecific(loopback_key
);
119 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
120 (me
, "get loopback key, key = %p\n", k
);
126 clear_loopback_key(lb_key_t
*key
) {
128 char *me
= "clear_loopback_key";
130 if (loopback_key
!= THR_ONCE_KEY
&& key
!= NULL
) {
132 * key->lb_flagp points to the location of the
133 * flag, check_flag, in the stack where it was
134 * first set; clearing the flag tells that
135 * stack the loopback error has been resolved
138 (void) thr_setspecific(loopback_key
, NULL
);
141 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
142 (me
, "key %p cleared\n", key
);
145 static thread_key_t initf_key
= THR_ONCE_KEY
;
148 set_initf_key(void *pbuf
) {
152 rc
= thr_keycreate_once(&initf_key
, NULL
);
154 rc
= thr_setspecific(initf_key
, pbuf
);
160 get_initf_key(void) {
162 char *me
= "get_initf_key";
165 pbuf
= pthread_getspecific(initf_key
);
167 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
168 (me
, "got initf pbuf, key = %p\n", pbuf
);
174 clear_initf_key(void) {
176 char *me
= "clear_initf_key";
178 (void) thr_setspecific(initf_key
, NULL
);
180 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
181 (me
, "initf pbuf cleared\n");
185 * Call the input initf function to extract the
186 * NSS front end parameters and examine them to
187 * determine if an NSS lookup is to be performed
188 * on a regular or a pseudo (called from compat
189 * backend) database. Then set the necessary
190 * parameters for later data structures creation
196 nss_db_initf_t initf
,
197 nscd_nsw_params_t
*params
)
200 nscd_rc_t rc
= NSCD_SUCCESS
;
205 char *me
= "getparams";
208 (void) memset(params
, 0, sizeof (nscd_nsw_params_t
));
212 params
->compati
= -1;
215 /* map database name to index */
217 for (j
= 0; j
< NSCD_NUM_DB
; j
++) {
218 dbn
= NSCD_NSW_DB_NAME(j
);
221 if (strcmp(n
, dbn
) == 0) {
223 if (*n
!= 'h' && *n
!= 'i' && *n
!= 's' && *n
!= 'a')
225 if (strcmp(n
, NSS_DBNAM_HOSTS
) == 0 &&
226 search_fnum
== NSS_DBOP_HOSTS_BYNAME
)
228 else if (strcmp(n
, NSS_DBNAM_IPNODES
) == 0 &&
229 search_fnum
== NSS_DBOP_IPNODES_BYNAME
)
231 else if (strcmp(n
, NSS_DBNAM_SHADOW
) == 0)
238 * use the switch policy for passwd_compat or
241 if (p
->config_name
!= NULL
) {
243 for (j
= 0; j
< NSCD_NUM_DB
; j
++) {
244 dbn
= NSCD_NSW_DB_NAME(j
);
246 if (strcmp(n
, dbn
) == 0) {
254 /* map the database name to the pseudo database index */
255 if (params
->cfgdbi
!= -1) {
256 if (strstr(p
->config_name
, "_compat") != NULL
) {
258 for (j
= params
->cfgdbi
; j
< NSCD_NUM_DB
; j
++) {
259 dbn
= NSCD_NSW_DB_NAME(j
);
261 if (strcmp(n
, dbn
) == 0) {
271 * if unsupported database, let caller determine what to do next
273 if (params
->dbi
== -1) {
274 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
275 (me
, "unsupported database: %s\n", p
->name
);
276 return (NSCD_CFG_UNSUPPORTED_SWITCH_DB
);
283 nscd_initf(nss_db_params_t
*p
)
288 char *me
= "nscd_initf";
290 pbuf
= (nss_pheader_t
*)get_initf_key();
292 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
293 (me
, "ERROR: initf key not set\n");
297 if (pbuf
->dbd_len
<= sizeof (nss_dbd_t
)) {
298 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
299 (me
, "invalid db front params data ? dbd_len = %d\n",
305 pdbd
= (nss_dbd_t
*)((void *)((char *)pbuf
+ off
));
307 p
->name
= (char *)pdbd
+ pdbd
->o_name
;
308 p
->config_name
= (char *)pdbd
+ pdbd
->o_config_name
;
309 p
->default_config
= (char *)pdbd
+ pdbd
->o_default_config
;
310 p
->flags
= (enum nss_dbp_flags
)pdbd
->flags
;
311 (void) memcpy(&p
->private, &pbuf
->nscdpriv
, sizeof (p
->private));
313 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
314 (me
, "db frontend params: name =%s, config_name = %s, "
315 "default_config = %s, flags = %x\n", p
->name
,
316 (p
->config_name
&& *p
->config_name
!= '\0' ?
317 p
->config_name
: "<NOT SPECIFIED>"),
318 (p
->default_config
&& *p
->default_config
!= '\0' ?
319 p
->default_config
: "<NOT SPECIFIED>"),
330 nss_XbyY_args_t
*arg
)
335 char *data_str
= "<NOT STRING FORMAT>";
337 char *me
= "trace_result";
341 res_str
= "NSS_SUCCESS";
344 res_str
= "NSS_NOTFOUND";
347 res_str
= "NSS_UNAVAIL";
350 res_str
= "NSS_TRYAGAIN";
352 case NSS_NISSERVDNS_TRYAGAIN
:
353 res_str
= "NSS_NISSERVDNS_TRYAGAIN";
356 res_str
= "UNKNOWN STATUS";
361 db
= NSCD_NSW_DB_NAME(dbi
);
363 src
= NSCD_NSW_SRC_NAME(srci
);
365 if (arg
->buf
.result
== NULL
) {
366 data_str
= arg
->buf
.buffer
;
367 data_len
= arg
->returnlen
;
370 if (res
== NSS_SUCCESS
) {
371 _nscd_logit(me
, "%s: database: %s, operation: %d, "
372 "source: %s returned >>%s<<, length = %d\n",
373 res_str
, db
, op
, src
, data_str
, data_len
);
377 _nscd_logit(me
, "%s: database: %s, operation: %d, source: %s, "
378 "erange= %d, herrno: %s (%d)\n",
379 res_str
, db
, op
, src
, arg
->erange
, hstrerror(arg
->h_errno
),
384 * Determine if a request should be done locally in the getXbyY caller's
385 * process. Return none zero if yes, 0 otherwise. This should be called
386 * before the switch engine steps through the backends/sources.
387 * This function returns 1 if:
388 * -- the database is exec_attr and the search_flag is GET_ALL
395 struct nss_XbyY_args
*ap
= (struct nss_XbyY_args
*)arg
;
398 char *me
= "try_local";
400 if (strcmp(NSCD_NSW_DB_NAME(dbi
), NSS_DBNAM_EXECATTR
) == 0) {
401 if ((ep
= ap
->key
.attrp
) != NULL
&& IS_GET_ALL(ep
->search_flag
))
407 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
408 (me
, "TRYLOCAL: exec_attr:GET_ALL\n");
415 * Determine if a request should be done locally in the getXbyY caller's
416 * process. Return none zero if yes, 0 otherwise. This should be called
417 * before the switch engine invokes any backend.
418 * This function returns 1 if:
419 * -- the database is shadow and the source is compat
427 char *me
= "try_local2";
429 if (*NSCD_NSW_DB_NAME(dbi
) == 's' &&
430 strcmp(NSCD_NSW_DB_NAME(dbi
), NSS_DBNAM_SHADOW
) == 0) {
431 if (strcmp(NSCD_NSW_SRC_NAME(srci
), "compat") == 0)
436 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
437 (me
, "TRYLOCAL: database: shadow, source: %s\n",
438 NSCD_NSW_SRC_NAME(srci
));
445 get_lib_func(void **handle
, void **func
, mutex_t
*lock
,
446 char *lib
, char *name
, void **func_p
)
448 char *me
= "get_lib_func";
451 if (func_p
!= NULL
&& *handle
!= NULL
&& *func
!= NULL
) {
453 return (NSCD_SUCCESS
);
456 (void) mutex_lock(lock
);
458 /* close the handle if requested */
459 if (func_p
== NULL
) {
460 if (*handle
!= NULL
) {
461 (void) dlclose(*handle
);
465 (void) mutex_unlock(lock
);
466 return (NSCD_SUCCESS
);
469 if (*handle
!= NULL
&& *func
!= NULL
) {
471 (void) mutex_unlock(lock
);
472 return (NSCD_SUCCESS
);
475 if (*handle
== NULL
) {
476 *handle
= dlopen(lib
, RTLD_LAZY
);
477 if (*handle
== NULL
) {
478 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_ERROR
)
479 (me
, "unable to dlopen %s\n", lib
);
480 (void) mutex_unlock(lock
);
481 return (NSCD_CFG_DLOPEN_ERROR
);
485 if ((sym
= dlsym(*handle
, name
)) == NULL
) {
487 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_ERROR
)
488 (me
, "unable to find symbol %s:%s\n", lib
, name
);
489 (void) mutex_unlock(lock
);
490 return (NSCD_CFG_DLSYM_ERROR
);
496 (void) mutex_unlock(lock
);
497 return (NSCD_SUCCESS
);
501 get_libc_nss_search(void **func_p
)
503 static void *handle
= NULL
;
504 static void *func
= NULL
;
505 static mutex_t lock
= DEFAULTMUTEX
;
507 return (get_lib_func(&handle
, &func
, &lock
,
508 "libc.so", "nss_search", func_p
));
512 get_gss_func(void **func_p
)
514 static void *handle
= NULL
;
515 static void *func
= NULL
;
516 static mutex_t lock
= DEFAULTMUTEX
;
518 return (get_lib_func(&handle
, &func
, &lock
,
519 "libgss.so", "gss_inquire_cred", func_p
));
523 get_sldap_shadow_func(void **func_p
)
525 static void *handle
= NULL
;
526 static void *func
= NULL
;
527 static mutex_t lock
= DEFAULTMUTEX
;
529 return (get_lib_func(&handle
, &func
, &lock
,
530 "libsldap.so", "__ns_ldap_is_shadow_update_enabled",
535 * get_dns_funcs returns pointers to gethostbyname functions in the
536 * dynamically loaded nss_dns & nss_mdns modules that return host
537 * lookup results along with the TTL value in the DNS resource
538 * records. The dnsi parameter indicates whether the lookup database
539 * is hosts(0) or ipnodes(1). The srcname parameter identifies the DNS
540 * module: dns/mdns and the function returns the address of the specific
541 * gethostbyname function in func_p variable.
544 get_dns_funcs(int dnsi
, nss_status_t (**func_p
)(), const char *srcname
)
548 static void *handle
[2] = { NULL
, NULL
};
549 static mutex_t func_lock
[2] = { DEFAULTMUTEX
, DEFAULTMUTEX
};
550 static void *func
[2][2] = {{NULL
, NULL
}, {NULL
, NULL
}};
551 static const char *lib
[2] = { "nss_dns.so.1", "nss_mdns.so.1" };
552 static const char *func_name
[2][2] =
553 {{ "_nss_get_dns_hosts_name", "_nss_get_dns_ipnodes_name" },
554 { "_nss_get_mdns_hosts_name", "_nss_get_mdns_ipnodes_name" }};
556 /* source index: 0 = dns, 1 = mdns */
557 if (strcmp(srcname
, "dns") == 0)
563 * function index (func[si][dnsi]):
564 * [0,0] = dns/hosts, [0,1] = dns/ipnodes,
565 * [1,0] = mdns/hosts, [1,1] = mdns/ipnodes
568 if (dnsi
< 0) { /* close handle */
570 (void) mutex_lock(&func_lock
[si
]);
573 (void) mutex_unlock(&func_lock
[si
]);
575 funcpp
= (void **)func_p
;
577 return (get_lib_func(&handle
[si
], &func
[si
][dnsi
], &func_lock
[si
],
578 (char *)lib
[si
], (char *)func_name
[si
][dnsi
], funcpp
));
582 search_dns_withttl(nscd_sw_return_t
*swret
, const char *srcname
, int dnsi
)
584 nss_status_t (*func
)();
585 nss_status_t res
= NSS_UNAVAIL
;
589 if (strcmp(srcname
, "dns") != 0 && strcmp(srcname
, "mdns") != 0)
592 rc
= get_dns_funcs(dnsi
, &func
, srcname
);
593 if (rc
== NSCD_SUCCESS
) {
595 * data_len in the packed buf header may be changed
596 * by the dns or mdns backend, reset it just in
599 ((nss_pheader_t
*)swret
->pbuf
)->data_len
=
601 res
= (func
)(NULL
, &swret
->pbuf
, &swret
->pbufsiz
);
607 * Returns a flag to indicate if needs to fall back to the
608 * main nscd when a per-user lookup failed with rc NSS_NOTFOUND.
611 set_fallback_flag(char *srcname
, nss_status_t rc
)
613 char *me
= "set_fallback_flag";
614 if (strcmp(srcname
, "ldap") == 0 && rc
== NSS_NOTFOUND
) {
615 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
616 (me
, "NSS_NOTFOUND (ldap): fallback to main nscd "
624 nss_search(nss_db_root_t
*rootp
, nss_db_initf_t initf
, int search_fnum
,
627 char *me
= "nss_search";
628 nss_status_t res
= NSS_UNAVAIL
;
629 nscd_nsw_state_t
*s
= NULL
;
631 unsigned int status_vec
= 0;
633 int check_loopback
= 0;
635 lb_key_t key
, *k
= NULL
;
636 nss_db_root_t root_db
;
637 nscd_nsw_params_t params
;
638 nscd_sw_return_t
*swret
;
640 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
641 (me
, "rootp = %p, initf = %p, search_fnum = %d, "
642 "search_args = %p\n", rootp
, initf
,
643 search_fnum
, search_args
);
645 NSCD_SW_STATS_G
.lookup_request_received_g
++;
646 NSCD_SW_STATS_G
.lookup_request_in_progress_g
++;
647 NSCD_SW_STATS_G
.lookup_request_queued_g
++;
649 /* determine db index, cfg db index, etc */
650 if (getparams(search_fnum
, initf
, ¶ms
) ==
651 NSCD_CFG_UNSUPPORTED_SWITCH_DB
) {
653 * if unsupported database and the request is from the
654 * the door, tell the door client to try it locally
656 if (initf
== nscd_initf
) {
659 } else { /* otherwise, let libc:nss_search() handle it */
660 nss_status_t (*func
)();
662 if (get_libc_nss_search((void **)&func
) ==
664 return ((func
)(rootp
, initf
, search_fnum
,
672 /* get address of the switch engine return data area */
673 if (initf
== nscd_initf
) {
674 swret
= (nscd_sw_return_t
*)params
.p
.private;
682 * for door request that should be processed by the client,
683 * send it back with status NSS_TRYLOCAL
685 if (initf
== nscd_initf
&& try_local(dbi
, search_args
) == 1) {
690 NSCD_SW_STATS(dbi
).lookup_request_received
++;
691 NSCD_SW_STATS(dbi
).lookup_request_in_progress
++;
692 NSCD_SW_STATS(dbi
).lookup_request_queued
++;
694 /* if lookup not enabled, return NSS_UNAVAIL */
695 if (!(NSCD_SW_CFG_G
.enable_lookup_g
== nscd_true
&&
696 NSCD_SW_CFG(dbi
).enable_lookup
== nscd_true
)) {
698 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
699 (me
, "lookup not enabled for %s\n", NSCD_NSW_DB_NAME(dbi
));
704 /* determine if loopback checking is configured */
705 if (NSCD_SW_CFG_G
.enable_loopback_checking_g
== nscd_true
&&
706 NSCD_SW_CFG(dbi
).enable_loopback_checking
== nscd_true
) {
709 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
710 (me
, "loopback checking enabled for %s\n",
711 NSCD_NSW_DB_NAME(dbi
));
714 if (check_loopback
) {
715 k
= get_loopback_key();
717 if (k
->dbi
!= dbi
|| k
->fnum
!= search_fnum
) {
718 clear_loopback_key(k
);
727 if (check_loopback
) {
728 rc
= _nscd_get_nsw_state_thread(&root_db
, ¶ms
);
731 rc
= _nscd_get_nsw_state(&root_db
, ¶ms
);
733 NSCD_SW_STATS_G
.lookup_request_queued_g
--;
734 NSCD_SW_STATS(dbi
).lookup_request_queued
--;
736 if (rc
!= NSCD_SUCCESS
)
739 s
= (nscd_nsw_state_t
*)root_db
.s
;
742 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
743 (me
, "database = %s, config = >>%s<<\n", NSCD_NSW_DB_NAME(dbi
),
744 (*s
->nsw_cfg_p
)->nsw_cfg_str
);
746 for (n_src
= 0; n_src
< s
->max_src
; n_src
++) {
747 nss_backend_t
*be
= NULL
;
748 nss_backend_op_t funcp
= NULL
;
749 struct __nsw_lookup_v1
*lkp
;
757 lkp
= s
->config
->lookups
;
761 /* set the number of max. retries */
762 if (lkp
->actions
[__NSW_TRYAGAIN
] == __NSW_TRYAGAIN_NTIMES
)
763 max_retry
= lkp
->max_retries
;
765 srci
= (*s
->nsw_cfg_p
)->src_idx
[n_src
];
769 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
770 (me
, "nsw source = %s\n", NSCD_NSW_SRC_NAME(srci
));
773 * If no privilege to look up, skip.
774 * 'files' requires PRIV_FILE_DAC_READ to read shadow(4) data,
775 * 'ldap' requires all zones privilege.
777 if (params
.privdb
== 1 && swret
!= NULL
) {
778 boolean_t (*is_shadow_update_enabled
)();
779 boolean_t check_ldap_priv
= B_FALSE
;
781 if (strcmp(NSCD_NSW_SRC_NAME(srci
), "ldap") == 0) {
782 if (get_sldap_shadow_func(
783 (void **)&is_shadow_update_enabled
) ==
785 is_shadow_update_enabled()) {
786 check_ldap_priv
= B_TRUE
;
789 * A peruser nscd doesn't have
790 * the privileges to lookup a
791 * private database, such as shadow,
792 * returns NSS_ALTRETRY to have the
793 * main nscd do the job.
795 if (_whoami
== NSCD_CHILD
) {
802 if ((strcmp(NSCD_NSW_SRC_NAME(srci
), "files") == 0 &&
803 _nscd_check_client_priv(NSCD_READ_PRIV
) != 0) ||
805 _nscd_check_client_priv(NSCD_ALL_PRIV
) != 0)) {
806 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
,
807 NSCD_LOG_LEVEL_DEBUG
)
808 (me
, "no privilege to look up, skip source\n");
814 /* get state of the (backend) client service */
815 smf_state
= _nscd_get_smf_state(srci
, dbi
, 0);
817 /* stop if the source is one that should be TRYLOCAL */
818 if (initf
== nscd_initf
&& /* request is from the door */
819 (smf_state
== NSCD_SVC_STATE_UNSUPPORTED_SRC
||
820 (smf_state
== NSCD_SVC_STATE_FOREIGN_SRC
&&
821 s
->be_version_p
[n_src
] == NULL
) ||
822 (params
.privdb
&& try_local2(dbi
, srci
) == 1))) {
823 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
824 (me
, "returning TRYLOCAL ... \n");
829 if (check_loopback
&& k
!= NULL
) {
831 if (k
->srci
== srci
&& k
->dbi
== dbi
)
832 if (k
->fnum
== search_fnum
) {
834 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
,
835 NSCD_LOG_LEVEL_DEBUG
)
836 (me
, "loopback detected: "
837 "source = %s, database = %s "
838 "search fnum = %d\n",
839 NSCD_NSW_SRC_NAME(srci
),
840 NSCD_NSW_DB_NAME(dbi
), search_fnum
);
842 NSCD_SW_STATS_G
.loopback_nsw_db_skipped_g
++;
843 NSCD_SW_STATS(dbi
).loopback_nsw_db_skipped
++;
850 funcp
= NSS_LOOKUP_DBOP(be
, search_fnum
);
852 /* request could be from within nscd so check states again */
853 if (be
== NULL
|| (params
.dnsi
< 0 && (funcp
== NULL
||
854 (smf_state
!= NSCD_SVC_STATE_UNINITED
&&
855 smf_state
!= NSCD_SVC_STATE_UNSUPPORTED_SRC
&&
856 smf_state
!= NSCD_SVC_STATE_FOREIGN_SRC
&&
857 smf_state
< SCF_STATE_ONLINE
)))) {
859 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
,
860 NSCD_LOG_LEVEL_DEBUG
)
861 (me
, "unable to look up source %s: be = %p, "
862 "smf state = %d, funcp = %p\n",
863 NSCD_NSW_SRC_NAME(srci
), be
, smf_state
, funcp
);
870 * we can only retry max_retry times,
871 * otherwise threads may get stuck in this
872 * do-while loop forever
874 if (n_loop
> max_retry
) {
881 * set up to prevent loopback
883 if (check_loopback
&& k
== NULL
) {
886 key
.fnum
= search_fnum
;
887 key
.lb_flagp
= &check_loopback
;
888 (void) set_loopback_key(&key
);
892 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
,
893 NSCD_LOG_LEVEL_DEBUG
)
894 (me
, "looking up source = %s, loop# = %d \n",
895 NSCD_NSW_SRC_NAME(srci
), n_loop
);
898 * search the backend, if hosts lookups,
899 * try to get the hosts data with ttl first
901 if (params
.dnsi
>= 0) {
902 res
= search_dns_withttl(swret
,
903 NSCD_NSW_SRC_NAME(srci
), params
.dnsi
);
905 * if not able to get ttl, fall back
906 * to the regular backend call
908 if (res
== NSS_ERROR
)
909 res
= (*funcp
)(be
, search_args
);
912 * status/result are in the
919 res
= (*funcp
)(be
, search_args
);
921 swret
->errnum
= errno
;
924 * backend is not up, check and update the
927 if (res
== NSS_UNAVAIL
)
928 (void) _nscd_get_smf_state(srci
, dbi
, 1);
931 * may need to fall back to use the main nscd
934 if (_whoami
== NSCD_CHILD
&& swret
!= NULL
)
935 swret
->fallback
= set_fallback_flag(
936 NSCD_NSW_SRC_NAME(srci
), res
);
938 _NSCD_LOG_IF(NSCD_LOG_SWITCH_ENGINE
,
939 NSCD_LOG_LEVEL_DEBUG
) {
942 * set up to trace the result/status
943 * of the dns/ttl lookup
945 if (swret
!= NULL
&& swret
->noarg
== 1) {
947 struct nss_XbyY_args
*arg
;
948 arg
= (struct nss_XbyY_args
*)
950 phdr
= (nss_pheader_t
*)swret
->pbuf
;
951 arg
->buf
.buffer
= (char *)phdr
+
953 arg
->returnlen
= phdr
->data_len
;
954 if (phdr
->p_errno
== ERANGE
)
956 arg
->h_errno
= phdr
->p_herrno
;
959 trace_result(dbi
, srci
, search_fnum
, res
,
960 (nss_XbyY_args_t
*)search_args
);
964 } while (retry_test(res
, n_loop
, lkp
));
968 status_vec
|= (1 << res
);
970 if (__NSW_ACTION_V1(lkp
, res
) == __NSW_RETURN
) {
978 _nscd_put_nsw_state_thread(s
);
980 _nscd_put_nsw_state(s
);
981 if (check_loopback
&& k
!= NULL
)
982 clear_loopback_key(k
);
984 if (res
!= NSS_SUCCESS
)
987 NSCD_SW_STATS_G
.lookup_request_succeeded_g
++;
988 NSCD_SW_STATS(dbi
).lookup_request_succeeded
++;
989 NSCD_SW_STATS_G
.lookup_request_in_progress_g
--;
990 NSCD_SW_STATS(dbi
).lookup_request_in_progress
--;
992 return (NSS_SUCCESS
);
996 NSCD_SW_STATS_G
.lookup_request_failed_g
++;
997 NSCD_SW_STATS_G
.lookup_request_in_progress_g
--;
998 NSCD_SW_STATS(dbi
).lookup_request_failed
++;
999 NSCD_SW_STATS(dbi
).lookup_request_in_progress
--;
1005 /* ===> get/set/endent */
1007 static void nss_setent_u(nss_db_root_t
*,
1010 static nss_status_t
nss_getent_u(nss_db_root_t
*,
1014 static void nss_endent_u(nss_db_root_t
*,
1019 nss_setent(nss_db_root_t
*rootp
, nss_db_initf_t initf
,
1020 nss_getent_t
*contextpp
)
1024 nss_setent_u(rootp
, initf
, contextpp
);
1028 nss_getent(nss_db_root_t
*rootp
, nss_db_initf_t initf
, nss_getent_t
*contextpp
,
1031 nss_status_t status
;
1033 if (contextpp
== 0) {
1034 return (NSS_UNAVAIL
);
1036 status
= nss_getent_u(rootp
, initf
, contextpp
, args
);
1041 nss_endent(nss_db_root_t
*rootp
, nss_db_initf_t initf
,
1042 nss_getent_t
*contextpp
)
1046 nss_endent_u(rootp
, initf
, contextpp
);
1051 end_iter_u(nss_db_root_t
*rootp
, struct nss_getent_context
*contextp
)
1053 nscd_getent_context_t
*ctx
;
1054 nscd_nsw_state_t
*s
;
1058 ctx
= (nscd_getent_context_t
*)contextp
;
1064 if (n_src
< s
->max_src
&& be
!= 0) {
1065 (void) NSS_INVOKE_DBOP(be
, NSS_DBOP_ENDENT
, 0);
1066 ctx
->be
= 0; /* Should be unnecessary, but hey */
1073 nss_setent_u(nss_db_root_t
*rootp
, nss_db_initf_t initf
,
1074 nss_getent_t
*contextpp
)
1076 char *me
= "nss_setent_u";
1077 nscd_nsw_state_t
*s
;
1078 nscd_getent_context_t
*contextp
;
1079 nscd_nsw_params_t params
;
1083 nscd_sw_return_t
*swret
= NULL
;
1085 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1086 (me
, "rootp = %p, initf = %p, contextpp = %p \n",
1087 rootp
, initf
, contextpp
);
1090 * Get the nsw db index via the initf function. If unsupported
1091 * database, no need to continue
1093 if (getparams(-1, initf
, ¶ms
) == NSCD_CFG_UNSUPPORTED_SWITCH_DB
)
1096 /* get address of the switch engine return data area */
1097 if (initf
== nscd_initf
)
1098 swret
= (nscd_sw_return_t
*)params
.p
.private;
1100 /* if no privilege to look up, return */
1101 if (params
.privdb
== 1 && swret
!= NULL
&&
1102 _nscd_check_client_priv(NSCD_READ_PRIV
) != 0) {
1104 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1105 (me
, "no privilege \n");
1109 if ((contextp
= (nscd_getent_context_t
*)contextpp
->ctx
) == 0) {
1110 if ((_nscd_get_getent_ctx(contextpp
, ¶ms
)) !=
1114 contextp
= (nscd_getent_context_t
*)contextpp
->ctx
;
1116 s
= contextp
->nsw_state
;
1119 if (_nscd_get_nsw_state(&root
, ¶ms
) !=
1123 s
= (nscd_nsw_state_t
*)root
.s
;
1124 contextp
->nsw_state
= s
;
1127 s
= contextp
->nsw_state
;
1128 n_src
= contextp
->n_src
;
1130 if (n_src
== 0 && be
!= 0) {
1132 * Optimization: don't do endent, don't change
1133 * backends, just do the setent. Look Ma, no locks
1134 * (nor any context that needs updating).
1136 (void) NSS_INVOKE_DBOP(be
, NSS_DBOP_SETENT
, 0);
1139 if (n_src
< s
->max_src
&& be
!= 0) {
1140 (void) NSS_INVOKE_DBOP(be
, NSS_DBOP_ENDENT
, 0);
1141 contextp
->be
= 0; /* Play it safe */
1144 for (n_src
= 0, be
= 0; n_src
< s
->max_src
&&
1145 (be
= s
->be
[n_src
]) == 0; n_src
++) {
1149 contextp
->n_src
= n_src
;
1153 /* Things are broken enough that we can't do setent/getent */
1154 nss_endent_u(rootp
, initf
, contextpp
);
1159 * make sure all the backends are supported
1161 for (i
= 0; i
< s
->max_src
; i
++) {
1164 if (s
->be
[i
] == NULL
)
1167 srci
= (*s
->nsw_cfg_p
)->src_idx
[i
];
1168 st
= _nscd_get_smf_state(srci
, params
.dbi
, 1);
1169 if (st
== NSCD_SVC_STATE_UNSUPPORTED_SRC
||
1170 (st
== NSCD_SVC_STATE_FOREIGN_SRC
&&
1171 s
->be_version_p
[i
] == NULL
&& initf
== nscd_initf
) ||
1172 st
== NSCD_SVC_STATE_UNINITED
||
1174 try_local2(params
.dbi
, srci
) == 1)) {
1175 nss_endent_u(rootp
, initf
, contextpp
);
1177 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
,
1178 NSCD_LOG_LEVEL_DEBUG
)
1179 (me
, "backend (%s) not available (state = %d)\n",
1180 NSCD_NSW_SRC_NAME(srci
), st
);
1186 (void) NSS_INVOKE_DBOP(be
, NSS_DBOP_SETENT
, 0);
1190 nss_getent_u(nss_db_root_t
*rootp
, nss_db_initf_t initf
,
1191 nss_getent_t
*contextpp
, void *args
)
1193 char *me
= "nss_getent_u";
1194 nscd_nsw_state_t
*s
;
1195 nscd_getent_context_t
*contextp
;
1199 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1200 (me
, "rootp = %p, initf = %p, contextpp = %p, args = %p\n",
1201 rootp
, initf
, contextpp
, args
);
1203 if ((contextp
= (nscd_getent_context_t
*)contextpp
->ctx
) == 0) {
1204 nss_setent_u(rootp
, initf
, contextpp
);
1205 if ((contextp
= (nscd_getent_context_t
*)contextpp
->ctx
) == 0) {
1207 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
,
1208 NSCD_LOG_LEVEL_ERROR
)
1209 (me
, "not able to obtain getent context ... give up\n");
1211 return (NSS_UNAVAIL
);
1215 s
= contextp
->nsw_state
;
1216 n_src
= contextp
->n_src
;
1221 * We've done an end_iter() and haven't done nss_setent()
1222 * or nss_endent() since; we should stick in this state
1223 * until the caller invokes one of those two routines.
1225 return (NSS_SUCCESS
);
1228 while (n_src
< s
->max_src
) {
1230 struct __nsw_lookup_v1
*lkp
= NULL
;
1233 /* get the nsw config for the current source */
1234 lkp
= s
->config
->lookups
;
1235 for (n
= 0; n
< n_src
; n
++)
1239 /* If it's null it's a bug, but let's play safe */
1242 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
,
1243 NSCD_LOG_LEVEL_DEBUG
)
1244 (me
, "database: %s, backend: %s, nsswitch config: %s\n",
1245 NSCD_NSW_DB_NAME(s
->dbi
),
1247 (*s
->nsw_cfg_p
)->nsw_cfg_str
);
1249 res
= NSS_INVOKE_DBOP(be
, NSS_DBOP_GETENT
, args
);
1252 if (__NSW_ACTION_V1(lkp
, res
) == __NSW_RETURN
) {
1253 if (res
!= __NSW_SUCCESS
) {
1255 (struct nss_getent_context
*)contextp
);
1259 (void) NSS_INVOKE_DBOP(be
, NSS_DBOP_ENDENT
, 0);
1262 } while (n_src
< s
->max_src
&&
1263 (be
= s
->be
[n_src
]) == 0);
1266 * This is the case where we failed to get the backend
1267 * for the last source. We exhausted all sources.
1269 nss_endent_u(rootp
, initf
, contextpp
);
1270 return (NSS_NOTFOUND
);
1272 contextp
->n_src
= n_src
;
1274 (void) NSS_INVOKE_DBOP(be
, NSS_DBOP_SETENT
, 0);
1276 /* Got to the end of the sources without finding another entry */
1277 end_iter_u(rootp
, (struct nss_getent_context
*)contextp
);
1278 return (NSS_SUCCESS
);
1279 /* success is either a successful entry or end of the sources */
1284 nss_endent_u(nss_db_root_t
*rootp
, nss_db_initf_t initf
,
1285 nss_getent_t
*contextpp
)
1287 char *me
= "nss_endent_u";
1288 nscd_getent_context_t
*contextp
;
1290 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1291 (me
, "rootp = %p, initf = %p, contextpp = %p \n",
1292 rootp
, initf
, contextpp
);
1294 if ((contextp
= (nscd_getent_context_t
*)contextpp
->ctx
) == 0) {
1295 /* nss_endent() on an unused context is a no-op */
1299 if (_nscd_is_getent_ctx_in_use(contextp
) == 0) {
1300 end_iter_u(rootp
, (struct nss_getent_context
*)contextp
);
1301 _nscd_put_getent_ctx(contextp
);
1302 contextpp
->ctx
= NULL
;
1307 * _nss_db_state_destr() and nss_delete() do nothing in nscd
1308 * but is needed to make the caller (below nscd) happy
1312 _nss_db_state_destr(struct nss_db_state
*s
)
1314 /* nsw state in nscd is always reused, so do nothing here */
1319 nss_delete(nss_db_root_t
*rootp
)
1322 * the only resource kept tracked by the nss_db_root_t
1323 * is the nsw state which is always reused and no need
1324 * to be freed. So just return.
1329 * Start of nss_psearch/nss_psetent()/nss_pgetent()/nss_pendent()
1330 * buffers switch entry points
1334 * nss_psearch opens a packed structure header, assembles a local
1335 * nss_XbyY_args_t structure and calls the local copy of nss_search.
1336 * The return data is assembled in "files native format" in the
1337 * return buffer location. Status if packed back up with the buffer
1338 * and the whole wad is returned to the cache or the client.
1342 nss_psearch(void *buffer
, size_t length
)
1345 nss_db_initf_t initf
;
1348 nss_XbyY_args_t arg
;
1349 nss_status_t status
;
1350 nscd_sw_return_t swret
= { 0 }, *swrp
= &swret
;
1351 nss_pheader_t
*pbuf
= (nss_pheader_t
*)buffer
;
1352 char *me
= "nss_psearch";
1354 if (buffer
== NULL
|| length
== 0) {
1355 NSCD_SET_STATUS(pbuf
, NSS_ERROR
, EFAULT
);
1359 status
= nss_packed_arg_init(buffer
, length
,
1360 NULL
, &initf
, &dbop
, &arg
);
1361 if (status
!= NSS_SUCCESS
) {
1362 NSCD_SET_STATUS(pbuf
, status
, -1);
1367 * pass the address of the return data area
1368 * for the switch engine to return its own data
1370 (void) memcpy(&pbuf
->nscdpriv
, &swrp
, sizeof (swrp
));
1371 swret
.pbuf
= buffer
;
1372 swret
.pbufsiz
= length
;
1373 swret
.datalen
= pbuf
->data_len
;
1376 * use the generic nscd_initf for all database lookups
1377 * (the TSD key is the pointer to the packed header)
1379 rc
= set_initf_key(pbuf
);
1381 NSCD_SET_STATUS(pbuf
, NSS_UNAVAIL
, EINVAL
);
1386 /* Perform local search and pack results into return buffer */
1387 /* nscd's search ignores db_root */
1388 status
= nss_search(NULL
, initf
, dbop
, &arg
);
1391 * If status is NSS_NOTFOUND and ldap also returned
1392 * NSS_NOTFOUND, it is possible that the user does
1393 * not have a credential, so check and see if
1394 * needs to return NSS_ALTRETRY to let the main
1395 * nscd get a chance to process the lookup
1397 if (swret
.fallback
== 1 && status
== NSS_NOTFOUND
) {
1398 OM_uint32 (*func
)();
1402 rc
= get_gss_func((void **)&func
);
1403 if (rc
== NSCD_SUCCESS
) {
1404 if (func(&stat
, GSS_C_NO_CREDENTIAL
,
1405 NULL
, NULL
, NULL
, NULL
) != GSS_S_COMPLETE
) {
1407 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
,
1408 NSCD_LOG_LEVEL_DEBUG
)
1409 (me
, "NSS_ALTRETRY: fallback to main nscd needed\n");
1411 status
= NSS_ALTRETRY
;
1416 NSCD_SET_STATUS(pbuf
, status
, -1);
1417 errno
= swret
.errnum
;
1420 * Move result/status from args to packed buffer only if
1421 * arg was being used and rc from the switch engine is not
1424 if (!swret
.noarg
&& status
!= NSS_TRYLOCAL
)
1425 nss_packed_set_status(buffer
, length
, status
, &arg
);
1427 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1428 (me
, "switch engine result: source is %s, status %d, "
1429 "herrno is %d, errno is %s\n",
1430 (swret
.srci
!= -1) ? NSCD_NSW_SRC_NAME(swret
.srci
) : "<NOTSET>",
1431 pbuf
->p_status
, pbuf
->p_herrno
, strerror(pbuf
->p_errno
));
1433 /* clear the TSD key used by the generic initf */
1439 nscd_map_contextp(void *buffer
, nss_getent_t
*contextp
,
1440 nssuint_t
**cookie_num_p
, nssuint_t
**seqnum_p
, int setent
)
1442 nss_pheader_t
*pbuf
= (nss_pheader_t
*)buffer
;
1444 nscd_getent_context_t
*ctx
;
1445 char *me
= "nscd_map_contextp";
1446 nscd_getent_p1_cookie_t
*cookie
;
1448 if (buffer
== NULL
) {
1449 NSCD_SET_STATUS(pbuf
, NSS_ERROR
, EFAULT
);
1453 off
= pbuf
->key_off
;
1454 cookie
= (nscd_getent_p1_cookie_t
*)((void *)((char *)buffer
+ off
));
1455 if (seqnum_p
!= NULL
)
1456 *seqnum_p
= &cookie
->p1_seqnum
;
1459 * if called by nss_psetent, and the passed in cookie number
1460 * is NSCD_NEW_COOKIE, then there is no cookie yet, return a
1461 * pointer pointing to where the cookie number will be stored.
1462 * Also because there is no cookie to validate, just return
1465 * On the other hand, if a cookie number is passed in, we need
1466 * to validate the cookie number before returning.
1468 if (cookie_num_p
!= NULL
)
1469 *cookie_num_p
= &cookie
->p1_cookie_num
;
1470 if (setent
== 1 && cookie
->p1_cookie_num
== NSCD_NEW_COOKIE
) {
1471 NSCD_SET_STATUS_SUCCESS(pbuf
);
1476 * If the sequence number and start time match nscd's p0 cookie,
1477 * then either setent was done twice in a row or this is the
1478 * first getent after the setent, return success as well.
1480 if (cookie
->p1_seqnum
== NSCD_P0_COOKIE_SEQNUM
) {
1481 nscd_getent_p0_cookie_t
*p0c
=
1482 (nscd_getent_p0_cookie_t
*)cookie
;
1483 if (p0c
->p0_time
== _nscd_get_start_time()) {
1484 NSCD_SET_STATUS_SUCCESS(pbuf
);
1489 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1490 (me
, "cookie # = %lld, sequence # = %lld\n",
1491 cookie
->p1_cookie_num
, cookie
->p1_seqnum
);
1493 ctx
= _nscd_is_getent_ctx(cookie
->p1_cookie_num
);
1496 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1497 (me
, "No matching context found (cookie number: %lld)\n",
1498 cookie
->p1_cookie_num
);
1500 NSCD_SET_STATUS(pbuf
, NSS_ERROR
, EFAULT
);
1504 /* if not called by nss_psetent, verify sequence number */
1505 if (setent
!= 1 && ctx
->seq_num
!=
1506 (nscd_seq_num_t
)cookie
->p1_seqnum
) {
1507 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1508 (me
, "invalid sequence # (%lld)\n", cookie
->p1_seqnum
);
1510 _nscd_free_ctx_if_aborted(ctx
);
1511 NSCD_SET_STATUS(pbuf
, NSS_ERROR
, EFAULT
);
1515 contextp
->ctx
= (struct nss_getent_context
*)ctx
;
1517 NSCD_SET_STATUS_SUCCESS(pbuf
);
1521 nss_psetent(void *buffer
, size_t length
, pid_t pid
)
1523 nss_getent_t context
= { 0 };
1524 nss_getent_t
*contextp
= &context
;
1525 nssuint_t
*cookie_num_p
;
1526 nssuint_t
*seqnum_p
;
1527 nss_pheader_t
*pbuf
= (nss_pheader_t
*)buffer
;
1528 nscd_getent_p0_cookie_t
*p0c
;
1529 char *me
= "nss_psetent";
1531 if (buffer
== NULL
|| length
== 0) {
1532 NSCD_SET_STATUS(pbuf
, NSS_ERROR
, EFAULT
);
1537 * If this is a per-user nscd, and the user does not have
1538 * the necessary credential, return NSS_TRYLOCAL, so the
1539 * setent/getent can be done locally in the process of the
1542 if (_whoami
== NSCD_CHILD
) {
1543 OM_uint32 (*func
)();
1547 rc
= get_gss_func((void **)&func
);
1548 if (rc
== NSCD_SUCCESS
) {
1549 if (func(&stat
, GSS_C_NO_CREDENTIAL
,
1550 NULL
, NULL
, NULL
, NULL
) != GSS_S_COMPLETE
) {
1552 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
,
1553 NSCD_LOG_LEVEL_DEBUG
)
1554 (me
, "NSS_TRYLOCAL: fallback to caller process\n");
1555 NSCD_SET_STATUS(pbuf
, NSS_TRYLOCAL
, 0);
1561 /* check cookie number */
1562 nscd_map_contextp(buffer
, contextp
, &cookie_num_p
, &seqnum_p
, 1);
1563 if (NSCD_STATUS_IS_NOT_OK(pbuf
))
1566 /* set cookie number and sequence number */
1567 p0c
= (nscd_getent_p0_cookie_t
*)cookie_num_p
;
1568 if (contextp
->ctx
== NULL
) {
1570 * first setent (no existing getent context),
1571 * return a p0 cookie
1573 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1574 (me
, "first setent, no getent context yet\n");
1577 * doing setent on an existing getent context,
1578 * release resources allocated and return a
1581 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1582 (me
, "setent resetting sequence number = %lld\n", *seqnum_p
);
1584 if (_nscd_is_getent_ctx_in_use((nscd_getent_context_t
*)
1585 contextp
->ctx
) == 0) {
1587 * context not in use, release the backend and
1588 * return the context to the pool
1590 end_iter_u(NULL
, contextp
->ctx
);
1591 _nscd_put_getent_ctx(
1592 (nscd_getent_context_t
*)contextp
->ctx
);
1593 contextp
->ctx
= NULL
;
1598 p0c
->p0_time
= _nscd_get_start_time();
1599 p0c
->p0_seqnum
= NSCD_P0_COOKIE_SEQNUM
;
1600 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1601 (me
, "returning a p0 cookie: pid = %ld, time = %ld, seq #= %llx\n",
1602 p0c
->p0_pid
, p0c
->p0_time
, p0c
->p0_seqnum
);
1604 NSCD_SET_STATUS(pbuf
, NSS_SUCCESS
, 0);
1608 delayed_setent(nss_pheader_t
*pbuf
, nss_db_initf_t initf
,
1609 nss_getent_t
*contextp
, nssuint_t
*cookie_num_p
,
1610 nssuint_t
*seqnum_p
, pid_t pid
)
1612 nscd_getent_context_t
*ctx
;
1613 nscd_sw_return_t swret
= { 0 }, *swrp
= &swret
;
1614 char *me
= "delayed_setent";
1619 _nscd_APP_check_cred(pbuf
, &pid
, "NSCD_DELAYED_SETENT",
1620 NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_ERROR
);
1621 if (NSCD_STATUS_IS_NOT_OK(pbuf
)) {
1622 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1623 (me
, "invalid credential\n");
1628 * pass the packed header buffer pointer to nss_setent
1630 (void) memcpy(&pbuf
->nscdpriv
, &swrp
, sizeof (swrp
));
1633 /* Perform local setent and set context */
1634 nss_setent(NULL
, initf
, contextp
);
1636 /* insert cookie info into packed buffer header */
1637 ctx
= (nscd_getent_context_t
*)contextp
->ctx
;
1639 *cookie_num_p
= ctx
->cookie_num
;
1640 *seqnum_p
= ctx
->seq_num
;
1644 * not able to allocate a getent context, the
1645 * client should try the enumeration locally
1647 *cookie_num_p
= NSCD_LOCAL_COOKIE
;
1650 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1651 (me
, "NSS_TRYLOCAL: cookie # = %lld, sequence # = %lld\n",
1652 *cookie_num_p
, *seqnum_p
);
1653 NSCD_SET_STATUS(pbuf
, NSS_TRYLOCAL
, 0);
1657 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1658 (me
, "NSS_SUCCESS: cookie # = %lld, sequence # = %lld\n",
1659 ctx
->cookie_num
, ctx
->seq_num
);
1661 NSCD_SET_STATUS(pbuf
, NSS_SUCCESS
, 0);
1665 nss_pgetent(void *buffer
, size_t length
)
1668 nss_db_initf_t initf
;
1669 nss_getent_t context
= { 0 };
1670 nss_getent_t
*contextp
= &context
;
1671 nss_XbyY_args_t arg
= { 0};
1672 nss_status_t status
;
1673 nssuint_t
*cookie_num_p
;
1674 nssuint_t
*seqnum_p
;
1675 nscd_getent_context_t
*ctx
;
1677 nss_pheader_t
*pbuf
= (nss_pheader_t
*)buffer
;
1678 char *me
= "nss_pgetent";
1680 if (buffer
== NULL
|| length
== 0) {
1681 NSCD_SET_STATUS(pbuf
, NSS_ERROR
, EFAULT
);
1685 /* verify the cookie passed in */
1686 nscd_map_contextp(buffer
, contextp
, &cookie_num_p
, &seqnum_p
, 0);
1687 if (NSCD_STATUS_IS_NOT_OK(pbuf
))
1691 * use the generic nscd_initf for all the getent requests
1692 * (the TSD key is the pointer to the packed header)
1694 rc
= set_initf_key(pbuf
);
1696 NSCD_SET_STATUS(pbuf
, NSS_UNAVAIL
, EINVAL
);
1701 /* if no context yet, get one */
1702 if (contextp
->ctx
== NULL
) {
1703 nscd_getent_p0_cookie_t
*p0c
=
1704 (nscd_getent_p0_cookie_t
*)cookie_num_p
;
1706 delayed_setent(pbuf
, initf
, contextp
, cookie_num_p
,
1707 seqnum_p
, p0c
->p0_pid
);
1708 if (NSCD_STATUS_IS_NOT_OK(pbuf
)) {
1714 status
= nss_packed_context_init(buffer
, length
,
1715 NULL
, &initf
, &contextp
, &arg
);
1716 if (status
!= NSS_SUCCESS
) {
1718 _nscd_free_ctx_if_aborted(
1719 (nscd_getent_context_t
*)contextp
->ctx
);
1720 NSCD_SET_STATUS(pbuf
, status
, -1);
1724 /* Perform local search and pack results into return buffer */
1725 status
= nss_getent(NULL
, initf
, contextp
, &arg
);
1726 NSCD_SET_STATUS(pbuf
, status
, -1);
1727 nss_packed_set_status(buffer
, length
, status
, &arg
);
1729 /* increment sequence number in the buffer and nscd context */
1730 if (status
== NSS_SUCCESS
) {
1731 ctx
= (nscd_getent_context_t
*)contextp
->ctx
;
1733 *seqnum_p
= ctx
->seq_num
;
1734 *cookie_num_p
= ctx
->cookie_num
;
1736 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1737 (me
, "getent OK, new sequence # = %lld, len = %lld,"
1738 " data = >>%s<<\n", *seqnum_p
,
1739 pbuf
->data_len
, (char *)buffer
+ pbuf
->data_off
);
1741 _nscd_free_ctx_if_aborted(ctx
);
1743 /* release the resources used */
1744 ctx
= (nscd_getent_context_t
*)contextp
->ctx
;
1745 if (ctx
!= NULL
&& _nscd_is_getent_ctx_in_use(ctx
) == 0) {
1746 _nscd_put_getent_ctx(ctx
);
1747 contextp
->ctx
= NULL
;
1749 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1750 (me
, "getent failed, status = %d, sequence # = %lld\n",
1754 /* clear the TSD key used by the generic initf */
1759 nss_pendent(void *buffer
, size_t length
)
1761 nss_getent_t context
= { 0 };
1762 nss_getent_t
*contextp
= &context
;
1763 nssuint_t
*seqnum_p
;
1764 nssuint_t
*cookie_num_p
;
1765 nss_pheader_t
*pbuf
= (nss_pheader_t
*)buffer
;
1766 char *me
= "nss_pendent";
1768 if (buffer
== NULL
|| length
== 0) {
1769 NSCD_SET_STATUS(pbuf
, NSS_ERROR
, EFAULT
);
1773 /* map the contextp from the cookie information */
1774 nscd_map_contextp(buffer
, contextp
, &cookie_num_p
, &seqnum_p
, 0);
1775 if (NSCD_STATUS_IS_NOT_OK(pbuf
))
1778 if (contextp
->ctx
== NULL
)
1781 _NSCD_LOG(NSCD_LOG_SWITCH_ENGINE
, NSCD_LOG_LEVEL_DEBUG
)
1782 (me
, "endent, cookie = %lld, sequence # = %lld\n",
1783 *cookie_num_p
, *seqnum_p
);
1785 /* Perform local endent and reset context */
1786 nss_endent(NULL
, NULL
, contextp
);
1788 NSCD_SET_STATUS(pbuf
, NSS_SUCCESS
, 0);
1793 nss_pdelete(void *buffer
, size_t length
)
1795 nss_pheader_t
*pbuf
= (nss_pheader_t
*)buffer
;
1797 /* unnecessary, kept for completeness */
1798 NSCD_SET_STATUS_SUCCESS(pbuf
);