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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2012 Milan Jurik. All rights reserved.
39 #include <sys/socket.h>
40 #include <net/route.h>
45 #include "nscd_common.h"
46 #include "nscd_door.h"
47 #include "nscd_config.h"
48 #include "nscd_switch.h"
50 #include "nscd_selfcred.h"
51 #include "nscd_frontend.h"
52 #include "nscd_admin.h"
54 static void rts_mon(void);
55 static void keep_open_dns_socket(void);
57 extern nsc_ctx_t
*cache_ctx_p
[];
60 * Current active Configuration data for the frontend component
62 static nscd_cfg_global_frontend_t frontend_cfg_g
;
63 static nscd_cfg_frontend_t
*frontend_cfg
;
65 static int max_servers
= 0;
66 static int max_servers_set
= 0;
67 static int per_user_is_on
= 1;
69 static char *main_execname
;
70 static char **main_argv
;
73 extern mutex_t activity_lock
;
75 static sema_t common_sema
;
77 static thread_key_t lookup_state_key
;
78 static mutex_t create_lock
= DEFAULTMUTEX
;
79 static int num_servers
= 0;
80 static thread_key_t server_key
;
83 * Bind a TSD value to a server thread. This enables the destructor to
84 * be called if/when this thread exits. This would be a programming
85 * error, but better safe than sorry.
89 server_tsd_bind(void *arg
)
91 static void *value
= 0;
93 /* disable cancellation to avoid hangs if server threads disappear */
94 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
95 (void) thr_setspecific(server_key
, value
);
96 (void) door_return(NULL
, 0, NULL
, 0);
103 * Server threads are created here.
107 server_create(door_info_t
*dip
)
109 (void) mutex_lock(&create_lock
);
110 if (++num_servers
> max_servers
) {
112 (void) mutex_unlock(&create_lock
);
115 (void) mutex_unlock(&create_lock
);
116 (void) thr_create(NULL
, 0, server_tsd_bind
, NULL
,
117 THR_BOUND
|THR_DETACHED
, NULL
);
121 * Server thread are destroyed here
125 server_destroy(void *arg
)
127 (void) mutex_lock(&create_lock
);
129 (void) mutex_unlock(&create_lock
);
136 _nscd_get_clearance(sema_t
*sema
) {
137 if (sema_trywait(&common_sema
) == 0) {
138 (void) thr_setspecific(lookup_state_key
, NULL
);
142 if (sema_trywait(sema
) == 0) {
143 (void) thr_setspecific(lookup_state_key
, (void*)1);
155 _nscd_release_clearance(sema_t
*sema
) {
158 (void) thr_getspecific(lookup_state_key
, (void**)&which
);
159 if (which
== 0) /* from common pool */ {
160 (void) sema_post(&common_sema
);
164 (void) sema_post(sema
);
175 * _nscd_restart_if_cfgfile_changed()
176 * Restart if modification times of nsswitch.conf or resolv.conf have changed.
178 * If nsswitch.conf has changed then it is possible that sources for
179 * various backends have changed and therefore the current cached
180 * data may not be consistent with the new data sources. By
181 * restarting the cache will be cleared and the new configuration will
184 * The check for resolv.conf is made as only the first call to
185 * res_gethostbyname() or res_getaddrbyname() causes a call to
186 * res_ninit() to occur which in turn parses resolv.conf. Therefore
187 * to benefit from changes to resolv.conf nscd must be restarted when
188 * resolv.conf is updated, removed or created. If res_getXbyY calls
189 * are removed from NSS then this check could be removed.
193 _nscd_restart_if_cfgfile_changed()
196 static mutex_t nsswitch_lock
= DEFAULTMUTEX
;
197 static timestruc_t last_nsswitch_check
= { 0 };
198 static timestruc_t last_nsswitch_modified
= { 0 };
199 static timestruc_t last_resolv_modified
= { -1, 0 };
200 static mutex_t restarting_lock
= DEFAULTMUTEX
;
201 static int restarting
= 0;
203 time_t now
= time(NULL
);
204 char *me
= "_nscd_restart_if_cfgfile_changed";
206 #define FLAG_RESTART_REQUIRED if (restarting == 0) {\
207 (void) mutex_lock(&restarting_lock);\
208 if (restarting == 0) {\
212 (void) mutex_unlock(&restarting_lock);\
218 if (now
- last_nsswitch_check
.tv_sec
< _NSC_FILE_CHECK_TIME
)
221 (void) mutex_lock(&nsswitch_lock
);
223 if (now
- last_nsswitch_check
.tv_sec
>= _NSC_FILE_CHECK_TIME
) {
227 last_nsswitch_check
.tv_sec
= now
;
228 last_nsswitch_check
.tv_nsec
= 0;
230 (void) mutex_unlock(&nsswitch_lock
); /* let others continue */
232 if (stat("/etc/nsswitch.conf", &nss_buf
) < 0) {
234 } else if (last_nsswitch_modified
.tv_sec
== 0) {
235 last_nsswitch_modified
= nss_buf
.st_mtim
;
238 if (last_nsswitch_modified
.tv_sec
< nss_buf
.st_mtim
.tv_sec
||
239 (last_nsswitch_modified
.tv_sec
== nss_buf
.st_mtim
.tv_sec
&&
240 last_nsswitch_modified
.tv_nsec
< nss_buf
.st_mtim
.tv_nsec
)) {
241 FLAG_RESTART_REQUIRED
;
245 if (stat("/etc/resolv.conf", &res_buf
) < 0) {
246 /* Unable to stat file, were we previously? */
247 if (last_resolv_modified
.tv_sec
> 0) {
248 /* Yes, it must have been removed. */
249 FLAG_RESTART_REQUIRED
;
250 } else if (last_resolv_modified
.tv_sec
== -1) {
251 /* No, then we've never seen it. */
252 last_resolv_modified
.tv_sec
= 0;
254 } else if (last_resolv_modified
.tv_sec
== -1) {
255 /* We've just started and file is present. */
256 last_resolv_modified
= res_buf
.st_mtim
;
257 } else if (last_resolv_modified
.tv_sec
== 0) {
258 /* Wasn't there at start-up. */
259 FLAG_RESTART_REQUIRED
;
260 } else if (last_resolv_modified
.tv_sec
<
261 res_buf
.st_mtim
.tv_sec
||
262 (last_resolv_modified
.tv_sec
==
263 res_buf
.st_mtim
.tv_sec
&&
264 last_resolv_modified
.tv_nsec
<
265 res_buf
.st_mtim
.tv_nsec
)) {
266 FLAG_RESTART_REQUIRED
;
274 * if in self cred mode, kill the forker and
277 if (_nscd_is_self_cred_on(0, NULL
)) {
279 _nscd_kill_all_children();
285 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_INFO
)
286 (me
, "nscd restart due to %s or %s change\n",
287 "/etc/nsswitch.conf", "resolv.conf");
289 * try to restart under smf
291 if ((fmri
= getenv("SMF_FMRI")) == NULL
) {
292 /* not running under smf - reexec */
293 (void) execv(main_execname
, main_argv
);
294 exit(1); /* just in case */
297 if (smf_restart_instance(fmri
) == 0)
298 (void) sleep(10); /* wait a bit */
299 exit(1); /* give up waiting for resurrection */
303 (void) mutex_unlock(&nsswitch_lock
);
307 _nscd_get_client_euid()
311 char *me
= "get_client_euid";
313 if (door_ucred(&uc
) != 0) {
314 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
315 (me
, "door_ucred: %s\n", strerror(errno
));
319 id
= ucred_geteuid(uc
);
325 * Check to see if the door client's euid is 0 or if it has required_priv
326 * privilege. Return 0 if yes, -1 otherwise.
327 * Supported values for required_priv are:
328 * - NSCD_ALL_PRIV: for all zones privileges
329 * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege
332 _nscd_check_client_priv(int required_priv
)
336 const priv_set_t
*eset
;
337 char *me
= "_nscd_check_client_read_priv";
338 priv_set_t
*zs
; /* zone */
340 if (door_ucred(&uc
) != 0) {
341 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
342 (me
, "door_ucred: %s\n", strerror(errno
));
346 if (ucred_geteuid(uc
) == 0) {
351 eset
= ucred_getprivset(uc
, PRIV_EFFECTIVE
);
352 switch (required_priv
) {
354 zs
= priv_str_to_set("zone", ",", NULL
);
355 if (!priv_isequalset(eset
, zs
)) {
356 _NSCD_LOG(NSCD_LOG_FRONT_END
,
357 NSCD_LOG_LEVEL_ERROR
)
358 (me
, "missing all zones privileges\n");
364 if (!priv_ismember(eset
, PRIV_FILE_DAC_READ
))
368 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
369 (me
, "unknown required_priv: %d\n", required_priv
);
382 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
384 const priv_set_t
*eset
;
387 char *me
= "N2N_check_priv";
389 if (door_ucred(&uc
) != 0) {
391 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
392 (me
, "door_ucred: %s\n", strerror(errno
));
394 NSCD_SET_STATUS(phdr
, NSS_ERROR
, errnum
);
398 eset
= ucred_getprivset(uc
, PRIV_EFFECTIVE
);
399 zoneid
= ucred_getzoneid(uc
);
401 if ((zoneid
!= GLOBAL_ZONEID
&& zoneid
!= getzoneid()) ||
402 eset
!= NULL
? !priv_ismember(eset
, PRIV_SYS_ADMIN
) :
403 ucred_geteuid(uc
) != 0) {
405 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
)
406 (me
, "%s call failed(cred): caller pid %d, uid %d, "
407 "euid %d, zoneid %d\n", dc_str
, ucred_getpid(uc
),
408 ucred_getruid(uc
), ucred_geteuid(uc
), zoneid
);
411 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EACCES
);
415 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
416 (me
, "nscd received %s cmd from pid %d, uid %d, "
417 "euid %d, zoneid %d\n", dc_str
, ucred_getpid(uc
),
418 ucred_getruid(uc
), ucred_geteuid(uc
), zoneid
);
422 NSCD_SET_STATUS_SUCCESS(phdr
);
426 _nscd_APP_check_cred(
433 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
439 char *me
= "_nscd_APP_check_cred";
441 if (door_ucred(&uc
) != 0) {
443 _NSCD_LOG(log_comp
, NSCD_LOG_LEVEL_ERROR
)
444 (me
, "door_ucred: %s\n", strerror(errno
));
446 NSCD_SET_STATUS(phdr
, NSS_ERROR
, errnum
);
450 NSCD_SET_STATUS_SUCCESS(phdr
);
451 pid
= ucred_getpid(uc
);
452 if (NSS_PACKED_CRED_CHECK(buf
, ruid
= ucred_getruid(uc
),
453 euid
= ucred_geteuid(uc
))) {
455 if (*pidp
== (pid_t
)-1)
457 else if (*pidp
!= pid
) {
458 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EACCES
);
462 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EACCES
);
467 if (NSCD_STATUS_IS_NOT_OK(phdr
)) {
468 _NSCD_LOG(log_comp
, log_level
)
469 (me
, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
470 "euid %d, header ruid %d, header euid %d\n", dc_str
,
471 pid
, (pidp
!= NULL
) ? *pidp
: -1, ruid
, euid
,
472 ((nss_pheader_t
*)(buf
))->p_ruid
,
473 ((nss_pheader_t
*)(buf
))->p_euid
);
477 /* log error and return -1 when an invalid packed buffer header is found */
479 pheader_error(nss_pheader_t
*phdr
, uint32_t call_number
)
483 switch (call_number
) {
485 call_num_str
= "NSCD_SEARCH";
488 call_num_str
= "NSCD_SETENT";
491 call_num_str
= "NSCD_GETENT";
494 call_num_str
= "NSCD_ENDENT";
497 call_num_str
= "NSCD_PUT";
500 call_num_str
= "NSCD_GETHINTS";
503 call_num_str
= "UNKNOWN";
507 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
)
508 ("pheader_error", "call number %s: invalid packed buffer header\n",
511 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EINVAL
);
516 * Validate the header of a getXbyY or setent/getent/endent request.
517 * Return 0 if good, -1 otherwise.
519 * A valid header looks like the following (size is arg_size, does
520 * not include the output area):
521 * +----------------------------------+ --
522 * | nss_pheader_t (header fixed part)| ^
524 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
525 * | data_off .... | |
527 * +----------------------------------+ <----- dbd_off
528 * | dbd (database description) | ^
529 * | nss_dbd_t + up to 3 strings | |
530 * | length = sizeof(nss_dbd_t) + | len = key_off - dbd_off
531 * | length of 3 strings + | |
532 * | length of padding | |
533 * | (total length in multiple of 4) | v
534 * +----------------------------------+ <----- key_off
536 * | nss_XbyY_key_t, content varies, | |
537 * | based on database and lookup op | len = data_off - key_off
538 * | length = data_off - key_off | |
539 * | including padding, multiple of 4 | v
540 * +----------------------------------+ <----- data_off (= arg_size)
542 * | area to hold results | |
543 * | | len = data_len (= pbufsiz -
546 * +----------------------------------+ <----- pbufsiz
552 uint32_t call_number
)
554 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
558 * current version is NSCD_HEADER_REV, length of the fixed part
559 * of the header must match the size of nss_pheader_t
561 if (phdr
->p_version
!= NSCD_HEADER_REV
||
562 phdr
->dbd_off
!= sizeof (nss_pheader_t
))
563 return (pheader_error(phdr
, call_number
));
566 * buffer size and offsets must be in multiple of 4
568 if ((arg_size
& 3) || (phdr
->dbd_off
& 3) || (phdr
->key_off
& 3) ||
569 (phdr
->data_off
& 3))
570 return (pheader_error(phdr
, call_number
));
573 * the input arg_size is the length of the request header
574 * and should be less than NSCD_PHDR_MAXLEN
576 if (phdr
->data_off
!= arg_size
|| arg_size
> NSCD_PHDR_MAXLEN
)
577 return (pheader_error(phdr
, call_number
));
579 /* get length of the dbd area */
580 l1
= phdr
->key_off
- phdr
-> dbd_off
;
583 * dbd area may contain padding, so length of dbd should
584 * not be less than the length of the actual data
586 if (l1
< phdr
->dbd_len
)
587 return (pheader_error(phdr
, call_number
));
589 /* get length of the key area */
590 l2
= phdr
->data_off
- phdr
->key_off
;
593 * key area may contain padding, so length of key area should
594 * not be less than the length of the actual data
596 if (l2
< phdr
->key_len
)
597 return (pheader_error(phdr
, call_number
));
600 * length of fixed part + lengths of dbd and key area = length of
603 if (sizeof (nss_pheader_t
) + l1
+ l2
!= phdr
->data_off
)
604 return (pheader_error(phdr
, call_number
));
606 /* header length + data length = buffer length */
607 if (phdr
->data_off
+ phdr
->data_len
!= phdr
->pbufsiz
)
608 return (pheader_error(phdr
, call_number
));
613 /* log error and return -1 when an invalid nscd to nscd buffer is found */
615 N2Nbuf_error(nss_pheader_t
*phdr
, uint32_t call_number
)
619 switch (call_number
) {
621 call_num_str
= "NSCD_PING";
625 call_num_str
= "NSCD_IMHERE";
629 call_num_str
= "NSCD_PULSE";
633 call_num_str
= "NSCD_FORK";
637 call_num_str
= "NSCD_KILL";
641 call_num_str
= "NSCD_REFRESH";
644 case NSCD_GETPUADMIN
:
645 call_num_str
= "NSCD_GETPUADMIN";
649 call_num_str
= "NSCD_GETADMIN";
653 call_num_str
= "NSCD_SETADMIN";
656 case NSCD_KILLSERVER
:
657 call_num_str
= "NSCD_KILLSERVER";
660 call_num_str
= "UNKNOWN";
664 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
)
665 ("N2Nbuf_error", "call number %s: invalid N2N buffer\n", call_num_str
);
667 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
668 NSCD_DOOR_BUFFER_CHECK_FAILED
);
674 * Validate the buffer of an nscd to nscd request.
675 * Return 0 if good, -1 otherwise.
677 * A valid buffer looks like the following (size is arg_size):
678 * +----------------------------------+ --
679 * | nss_pheader_t (header fixed part)| ^
681 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
682 * | data_off .... | |
684 * +----------------------------------+ <---dbd_off = key_off = data_off
686 * | input data/output data | |
687 * | OR no data | len = data_len (= pbufsiz -
689 * | | | len could be zero
691 * +----------------------------------+ <--- pbufsiz
697 uint32_t call_number
)
699 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
702 * current version is NSCD_HEADER_REV, length of the fixed part
703 * of the header must match the size of nss_pheader_t
705 if (phdr
->p_version
!= NSCD_HEADER_REV
||
706 phdr
->dbd_off
!= sizeof (nss_pheader_t
))
707 return (N2Nbuf_error(phdr
, call_number
));
710 * There are no dbd and key data, so the dbd, key, data
711 * offsets should be equal
713 if (phdr
->dbd_off
!= phdr
->key_off
||
714 phdr
->dbd_off
!= phdr
->data_off
)
715 return (N2Nbuf_error(phdr
, call_number
));
718 * the input arg_size is the buffer length and should
719 * be less or equal than NSCD_N2NBUF_MAXLEN
721 if (phdr
->pbufsiz
!= arg_size
|| arg_size
> NSCD_N2NBUF_MAXLEN
)
722 return (N2Nbuf_error(phdr
, call_number
));
724 /* header length + data length = buffer length */
725 if (phdr
->data_off
+ phdr
->data_len
!= phdr
->pbufsiz
)
726 return (N2Nbuf_error(phdr
, call_number
));
732 lookup(char *argp
, size_t arg_size
)
734 nsc_lookup_args_t largs
;
735 char space
[NSCD_LOOKUP_BUFSIZE
];
736 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
738 NSCD_ALLOC_LOOKUP_BUFFER(argp
, arg_size
, phdr
, space
,
742 * make sure the first couple bytes of the data area is null,
743 * so that bad strings in the packed header stop here
745 (void) memset((char *)phdr
+ phdr
->data_off
, 0, 16);
747 (void) memset(&largs
, 0, sizeof (largs
));
749 largs
.bufsize
= arg_size
;
750 nsc_lookup(&largs
, 0);
753 * only the PUN needs to keep track of the
754 * activity count to determine when to
757 if (_whoami
== NSCD_CHILD
) {
758 (void) mutex_lock(&activity_lock
);
760 (void) mutex_unlock(&activity_lock
);
763 NSCD_SET_RETURN_ARG(phdr
, arg_size
);
764 (void) door_return(argp
, arg_size
, NULL
, 0);
768 getent(char *argp
, size_t arg_size
)
770 char space
[NSCD_LOOKUP_BUFSIZE
];
771 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
773 NSCD_ALLOC_LOOKUP_BUFFER(argp
, arg_size
, phdr
, space
, sizeof (space
));
775 nss_pgetent(argp
, arg_size
);
777 NSCD_SET_RETURN_ARG(phdr
, arg_size
);
778 (void) door_return(argp
, arg_size
, NULL
, 0);
782 is_db_per_user(void *buf
, char *dblist
)
784 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
789 /* copy db name into a temp buffer */
790 pdbd
= (nss_dbd_t
*)((void *)((char *)buf
+ phdr
->dbd_off
));
791 dbname
= (char *)pdbd
+ pdbd
->o_name
;
792 len
= strlen(dbname
);
793 dbn
= alloca(len
+ 2);
794 (void) memcpy(dbn
, dbname
, len
);
796 /* check if <dbname> + ',' can be found in the dblist string */
799 if (strstr(dblist
, dbn
) != NULL
)
803 * check if <dbname> can be found in the last part
804 * of the dblist string
807 if (strstr(dblist
, dbn
) != NULL
)
814 * Check to see if all conditions are met for processing per-user
815 * requests. Returns 1 if yes, -1 if backend is not configured,
819 need_per_user_door(void *buf
, int whoami
, uid_t uid
, char **dblist
)
821 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
823 NSCD_SET_STATUS_SUCCESS(phdr
);
825 /* if already a per-user nscd, no need to get per-user door */
826 if (whoami
== NSCD_CHILD
)
829 /* forker shouldn't be asked */
830 if (whoami
== NSCD_FORKER
) {
831 NSCD_SET_STATUS(phdr
, NSS_ERROR
, ENOTSUP
);
835 /* if door client is root, no need for a per-user door */
840 * if per-user lookup is not configured, no per-user
843 if (_nscd_is_self_cred_on(0, dblist
) == 0)
847 * if per-user lookup is not configured for the db,
850 if (is_db_per_user(phdr
, *dblist
) == 0)
857 if_selfcred_return_per_user_door(char *argp
, size_t arg_size
,
858 door_desc_t
*dp
, int whoami
)
860 nss_pheader_t
*phdr
= (nss_pheader_t
*)((void *)argp
);
869 * check to see if self-cred is configured and
870 * need to return an alternate PUN door
872 if (per_user_is_on
== 1) {
873 rc
= need_per_user_door(argp
, whoami
,
874 _nscd_get_client_euid(), &dblist
);
880 * self-cred not configured, and no error detected,
881 * return to continue the door call processing
883 if (NSCD_STATUS_IS_OK(phdr
))
887 * configured but error detected,
888 * stop the door call processing
890 (void) door_return(argp
, phdr
->data_off
, NULL
, 0);
893 /* get the alternate PUN door */
894 _nscd_proc_alt_get(argp
, &door
);
895 if (NSCD_GET_STATUS(phdr
) != NSS_ALTRETRY
) {
896 (void) door_return(argp
, phdr
->data_off
, NULL
, 0);
899 /* return the alternate door descriptor */
900 len
= strlen(dblist
) + 1;
901 space
= alloca(arg_size
+ len
);
902 phdr
->data_len
= len
;
903 (void) memcpy(space
, phdr
, arg_size
);
904 (void) strncpy((char *)space
+ arg_size
, dblist
, len
);
906 dp
->d_attributes
= DOOR_DESCRIPTOR
;
907 dp
->d_data
.d_desc
.d_descriptor
= door
;
909 (void) door_return(space
, arg_size
, dp
, 1);
914 switcher(void *cookie
, char *argp
, size_t arg_size
,
915 door_desc_t
*dp
, uint_t n_desc
)
919 nss_pheader_t
*phdr
= (nss_pheader_t
*)((void *)argp
);
924 char *me
= "switcher";
926 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
927 (me
, "switcher ...\n");
929 if (argp
== DOOR_UNREF_DATA
) {
930 (void) printf("Door Slam... exiting\n");
934 if (argp
== NULL
) { /* empty door call */
935 (void) door_return(NULL
, 0, 0, 0); /* return the favor */
939 * need to restart if main nscd and config file(s) changed
941 if (_whoami
== NSCD_MAIN
)
942 _nscd_restart_if_cfgfile_changed();
944 if ((phdr
->nsc_callnumber
& NSCDV2CATMASK
) == NSCD_CALLCAT_APP
) {
946 /* make sure the packed buffer header is good */
947 if (validate_pheader(argp
, arg_size
,
948 phdr
->nsc_callnumber
) == -1)
949 (void) door_return(argp
, arg_size
, NULL
, 0);
951 switch (phdr
->nsc_callnumber
) {
955 /* if a fallback to main nscd, skip per-user setup */
956 if (phdr
->p_status
!= NSS_ALTRETRY
)
957 if_selfcred_return_per_user_door(argp
, arg_size
,
959 lookup(argp
, arg_size
);
965 _nscd_APP_check_cred(argp
, &ent_pid
, "NSCD_SETENT",
966 NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
);
967 if (NSCD_STATUS_IS_OK(phdr
)) {
968 if_selfcred_return_per_user_door(argp
, arg_size
,
970 nss_psetent(argp
, arg_size
, ent_pid
);
976 getent(argp
, arg_size
);
981 nss_pendent(argp
, arg_size
);
986 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
987 (me
, "door call NSCD_PUT not supported yet\n");
989 NSCD_SET_STATUS(phdr
, NSS_ERROR
, ENOTSUP
);
994 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
995 (me
, "door call NSCD_GETHINTS not supported yet\n");
997 NSCD_SET_STATUS(phdr
, NSS_ERROR
, ENOTSUP
);
1002 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1003 (me
, "Unknown name service door call op %x\n",
1004 phdr
->nsc_callnumber
);
1006 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EINVAL
);
1010 (void) door_return(argp
, arg_size
, NULL
, 0);
1014 callnum
= phdr
->nsc_callnumber
& ~NSCD_WHOAMI
;
1015 if (callnum
== NSCD_IMHERE
||
1016 callnum
== NSCD_PULSE
|| callnum
== NSCD_FORK
)
1017 iam
= phdr
->nsc_callnumber
& NSCD_WHOAMI
;
1019 callnum
= phdr
->nsc_callnumber
;
1021 /* nscd -> nscd v2 calls */
1023 /* make sure the buffer is good */
1024 if (validate_N2Nbuf(argp
, arg_size
, callnum
) == -1)
1025 (void) door_return(argp
, arg_size
, NULL
, 0);
1030 NSCD_SET_STATUS_SUCCESS(phdr
);
1034 _nscd_proc_iamhere(argp
, dp
, n_desc
, iam
);
1038 N2N_check_priv(argp
, "NSCD_PULSE");
1039 if (NSCD_STATUS_IS_OK(phdr
))
1040 _nscd_proc_pulse(argp
, iam
);
1044 N2N_check_priv(argp
, "NSCD_FORK");
1045 if (NSCD_STATUS_IS_OK(phdr
))
1046 _nscd_proc_fork(argp
, iam
);
1050 N2N_check_priv(argp
, "NSCD_KILL");
1051 if (NSCD_STATUS_IS_OK(phdr
))
1056 N2N_check_priv(argp
, "NSCD_REFRESH");
1057 if (NSCD_STATUS_IS_OK(phdr
)) {
1058 if (_nscd_refresh() != NSCD_SUCCESS
)
1060 NSCD_SET_STATUS_SUCCESS(phdr
);
1064 case NSCD_GETPUADMIN
:
1066 if (_nscd_is_self_cred_on(0, NULL
)) {
1067 _nscd_peruser_getadmin(argp
, sizeof (nscd_admin_t
));
1069 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
1070 NSCD_SELF_CRED_NOT_CONFIGURED
);
1076 len
= _nscd_door_getadmin((void *)argp
);
1080 /* size of door buffer not big enough, allocate one */
1081 NSCD_ALLOC_DOORBUF(NSCD_GETADMIN
, len
, uptr
, buflen
);
1083 /* copy packed header */
1084 *(nss_pheader_t
*)uptr
= *(nss_pheader_t
*)((void *)argp
);
1086 /* set new buffer size */
1087 ((nss_pheader_t
*)uptr
)->pbufsiz
= buflen
;
1089 /* try one more time */
1090 (void) _nscd_door_getadmin((void *)uptr
);
1091 (void) door_return(uptr
, buflen
, NULL
, 0);
1095 N2N_check_priv(argp
, "NSCD_SETADMIN");
1096 if (NSCD_STATUS_IS_OK(phdr
))
1097 _nscd_door_setadmin(argp
);
1100 case NSCD_KILLSERVER
:
1101 N2N_check_priv(argp
, "NSCD_KILLSERVER");
1102 if (NSCD_STATUS_IS_OK(phdr
)) {
1103 /* also kill the forker nscd if one is running */
1104 _nscd_kill_forker();
1110 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1111 (me
, "Unknown name service door call op %d\n",
1112 phdr
->nsc_callnumber
);
1114 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EINVAL
);
1116 (void) door_return(argp
, arg_size
, NULL
, 0);
1120 (void) door_return(argp
, arg_size
, NULL
, 0);
1124 _nscd_setup_server(char *execname
, char **argv
)
1129 int bind_failed
= 0;
1133 struct sigaction action
;
1134 char *me
= "_nscd_setup_server";
1136 main_execname
= execname
;
1139 /* Any nscd process is to ignore SIGPIPE */
1140 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) {
1142 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1143 (me
, "signal (SIGPIPE): %s\n", strerror(errnum
));
1147 keep_open_dns_socket();
1150 * the max number of server threads should be fixed now, so
1151 * set flag to indicate that no in-flight change is allowed
1153 max_servers_set
= 1;
1155 (void) thr_keycreate(&lookup_state_key
, NULL
);
1156 (void) sema_init(&common_sema
, frontend_cfg_g
.common_worker_threads
,
1159 /* Establish server thread pool */
1160 (void) door_server_create(server_create
);
1161 if (thr_keycreate(&server_key
, server_destroy
) != 0) {
1163 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1164 (me
, "thr_keycreate (server thread): %s\n",
1170 if ((fd
= door_create(switcher
, NAME_SERVICE_DOOR_COOKIE
,
1171 DOOR_UNREF
| DOOR_NO_CANCEL
)) < 0) {
1173 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1174 (me
, "door_create: %s\n", strerror(errnum
));
1178 /* if not main nscd, no more setup to do */
1179 if (_whoami
!= NSCD_MAIN
)
1182 /* bind to file system */
1183 if (stat(NAME_SERVICE_DOOR
, &buf
) < 0) {
1186 /* make sure the door will be readable by all */
1187 old_mask
= umask(0);
1188 if ((newfd
= creat(NAME_SERVICE_DOOR
, 0444)) < 0) {
1190 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1191 (me
, "Cannot create %s: %s\n", NAME_SERVICE_DOOR
,
1195 /* rstore the old file mode creation mask */
1196 (void) umask(old_mask
);
1197 (void) close(newfd
);
1200 if (bind_failed
== 1) {
1201 (void) door_revoke(fd
);
1205 if (fattach(fd
, NAME_SERVICE_DOOR
) < 0) {
1206 if ((errno
!= EBUSY
) ||
1207 (fdetach(NAME_SERVICE_DOOR
) < 0) ||
1208 (fattach(fd
, NAME_SERVICE_DOOR
) < 0)) {
1210 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1211 (me
, "fattach: %s\n", strerror(errnum
));
1212 (void) door_revoke(fd
);
1218 * kick off routing socket monitor thread
1220 if (thr_create(NULL
, 0,
1221 (void *(*)(void *))rts_mon
, 0, 0, NULL
) != 0) {
1223 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1224 (me
, "thr_create (routing socket monitor): %s\n",
1227 (void) door_revoke(fd
);
1232 * set up signal handler for SIGHUP
1234 action
.sa_handler
= dozip
;
1235 action
.sa_flags
= 0;
1236 (void) sigemptyset(&action
.sa_mask
);
1237 (void) sigemptyset(&myset
);
1238 (void) sigaddset(&myset
, SIGHUP
);
1240 if (sigaction(SIGHUP
, &action
, NULL
) < 0) {
1242 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1243 (me
, "sigaction (SIGHUP): %s\n", strerror(errnum
));
1245 (void) door_revoke(fd
);
1253 _nscd_setup_child_server(int did
)
1259 char *me
= "_nscd_setup_child_server";
1261 /* Re-establish our own server thread pool */
1262 (void) door_server_create(server_create
);
1263 if (thr_keycreate(&server_key
, server_destroy
) != 0) {
1265 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
1266 (me
, "thr_keycreate failed: %s", strerror(errnum
));
1271 * Create a new door.
1272 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork)
1275 if ((fd
= door_create(switcher
, NAME_SERVICE_DOOR_COOKIE
,
1276 DOOR_REFUSE_DESC
|DOOR_UNREF
|DOOR_NO_CANCEL
)) < 0) {
1278 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
1279 (me
, "door_create failed: %s", strerror(errnum
));
1284 * kick off routing socket monitor thread
1286 if (thr_create(NULL
, 0,
1287 (void *(*)(void *))rts_mon
, 0, 0, NULL
) != 0) {
1289 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1290 (me
, "thr_create (routing socket monitor): %s\n",
1292 (void) door_revoke(fd
);
1297 * start monitoring the states of the name service clients
1299 rc
= _nscd_init_smf_monitor();
1300 if (rc
!= NSCD_SUCCESS
) {
1301 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1302 (me
, "unable to start the SMF monitor (rc = %d)\n", rc
);
1304 (void) door_revoke(fd
);
1312 _nscd_alloc_frontend_cfg()
1314 frontend_cfg
= calloc(NSCD_NUM_DB
, sizeof (nscd_cfg_frontend_t
));
1315 if (frontend_cfg
== NULL
)
1316 return (NSCD_NO_MEMORY
);
1318 return (NSCD_SUCCESS
);
1324 _nscd_cfg_frontend_notify(
1326 struct nscd_cfg_param_desc
*pdesc
,
1327 nscd_cfg_id_t
*nswdb
,
1328 nscd_cfg_flag_t dflag
,
1329 nscd_cfg_error_t
**errorp
,
1335 * At init time, the whole group of config params are received.
1336 * At update time, group or individual parameter value could
1340 if (_nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_INIT
) ||
1341 _nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_GROUP
)) {
1343 * group data is received, copy in the
1346 if (_nscd_cfg_flag_is_set(pdesc
->pflag
, NSCD_CFG_PFLAG_GLOBAL
))
1347 frontend_cfg_g
= *(nscd_cfg_global_frontend_t
*)data
;
1349 frontend_cfg
[nswdb
->index
] =
1350 *(nscd_cfg_frontend_t
*)data
;
1354 * individual paramater is received: copy in the
1357 if (_nscd_cfg_flag_is_set(pdesc
->pflag
, NSCD_CFG_PFLAG_GLOBAL
))
1358 dp
= (char *)&frontend_cfg_g
+ pdesc
->p_offset
;
1360 dp
= (char *)&frontend_cfg
[nswdb
->index
] +
1362 (void) memcpy(dp
, data
, pdesc
->p_size
);
1365 return (NSCD_SUCCESS
);
1370 _nscd_cfg_frontend_verify(
1372 struct nscd_cfg_param_desc
*pdesc
,
1373 nscd_cfg_id_t
*nswdb
,
1374 nscd_cfg_flag_t dflag
,
1375 nscd_cfg_error_t
**errorp
,
1379 char *me
= "_nscd_cfg_frontend_verify";
1382 * if max. number of server threads is set and in effect,
1383 * don't allow changing of the frontend configuration
1385 if (max_servers_set
) {
1386 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_INFO
)
1387 (me
, "changing of the frontend configuration not allowed now");
1389 return (NSCD_CFG_CHANGE_NOT_ALLOWED
);
1392 return (NSCD_SUCCESS
);
1397 _nscd_cfg_frontend_get_stat(
1399 struct nscd_cfg_stat_desc
*sdesc
,
1400 nscd_cfg_id_t
*nswdb
,
1401 nscd_cfg_flag_t
*dflag
,
1402 void (**free_stat
)(void *stat
),
1403 nscd_cfg_error_t
**errorp
)
1405 return (NSCD_SUCCESS
);
1409 _nscd_init_cache_sema(sema_t
*sema
, char *cache_name
)
1414 if (max_servers
== 0)
1415 max_servers
= frontend_cfg_g
.common_worker_threads
+
1416 frontend_cfg_g
.cache_hit_threads
;
1418 for (i
= 0; i
< NSCD_NUM_DB
; i
++) {
1420 dbn
= NSCD_NSW_DB_NAME(i
);
1421 if (strcasecmp(dbn
, cache_name
) == 0) {
1422 j
= frontend_cfg
[i
].worker_thread_per_nsw_db
;
1423 (void) sema_init(sema
, j
, USYNC_THREAD
, 0);
1431 * Monitor the routing socket. Address lists stored in the ipnodes
1432 * cache are sorted based on destination address selection rules,
1433 * so when things change that could affect that sorting (interfaces
1434 * go up or down, flags change, etc.), we clear that cache so the
1435 * list will be re-ordered the next time the hostname is resolved.
1440 int rt_sock
, rdlen
, idx
;
1443 struct rt_msghdr rtm
;
1444 struct sockaddr_storage addrs
[RTA_NUMBITS
];
1446 struct if_msghdr ifm
;
1447 struct ifa_msghdr ifam
;
1449 struct ifa_msghdr
*ifam
= &mbuf
.ifam
;
1450 char *me
= "rts_mon";
1452 rt_sock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
1454 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1455 (me
, "Failed to open routing socket: %s\n", strerror(errno
));
1460 rdlen
= read(rt_sock
, &mbuf
, sizeof (mbuf
));
1462 if (rdlen
== 0 || (errno
!= EINTR
&& errno
!= EAGAIN
)) {
1463 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1464 NSCD_LOG_LEVEL_ERROR
)
1465 (me
, "routing socket read: %s\n",
1471 if (ifam
->ifam_version
!= RTM_VERSION
) {
1472 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1473 NSCD_LOG_LEVEL_ERROR
)
1474 (me
, "rx unknown version (%d) on "
1475 "routing socket.\n",
1476 ifam
->ifam_version
);
1479 switch (ifam
->ifam_type
) {
1482 /* if no ipnodes cache, then nothing to do */
1483 idx
= get_cache_idx("ipnodes");
1484 if (cache_ctx_p
[idx
] == NULL
||
1485 cache_ctx_p
[idx
]->reaper_on
!= nscd_true
)
1487 nsc_invalidate(cache_ctx_p
[idx
], NULL
, NULL
);
1505 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1506 (me
, "rx unknown msg type (%d) on routing socket.\n",
1514 keep_open_dns_socket(void)
1516 _res
.options
|= RES_STAYOPEN
; /* just keep this udp socket open */