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.
25 * Copyright 2018 Joyent, Inc.
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 (void) thr_setname(thr_self(), "server_tsd_bind");
95 /* disable cancellation to avoid hangs if server threads disappear */
96 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
97 (void) thr_setspecific(server_key
, value
);
98 (void) door_return(NULL
, 0, NULL
, 0);
100 /* make lint happy */
105 * Server threads are created here.
109 server_create(door_info_t
*dip
)
111 (void) mutex_lock(&create_lock
);
112 if (++num_servers
> max_servers
) {
114 (void) mutex_unlock(&create_lock
);
117 (void) mutex_unlock(&create_lock
);
118 (void) thr_create(NULL
, 0, server_tsd_bind
, NULL
,
119 THR_BOUND
|THR_DETACHED
, NULL
);
123 * Server thread are destroyed here
127 server_destroy(void *arg
)
129 (void) mutex_lock(&create_lock
);
131 (void) mutex_unlock(&create_lock
);
138 _nscd_get_clearance(sema_t
*sema
)
140 if (sema_trywait(&common_sema
) == 0) {
141 (void) thr_setspecific(lookup_state_key
, NULL
);
145 if (sema_trywait(sema
) == 0) {
146 (void) thr_setspecific(lookup_state_key
, (void*)1);
158 _nscd_release_clearance(sema_t
*sema
)
162 (void) thr_getspecific(lookup_state_key
, (void**)&which
);
163 if (which
== 0) /* from common pool */ {
164 (void) sema_post(&common_sema
);
168 (void) sema_post(sema
);
179 * _nscd_restart_if_cfgfile_changed()
180 * Restart if modification times of nsswitch.conf or resolv.conf have changed.
182 * If nsswitch.conf has changed then it is possible that sources for
183 * various backends have changed and therefore the current cached
184 * data may not be consistent with the new data sources. By
185 * restarting the cache will be cleared and the new configuration will
188 * The check for resolv.conf is made as only the first call to
189 * res_gethostbyname() or res_getaddrbyname() causes a call to
190 * res_ninit() to occur which in turn parses resolv.conf. Therefore
191 * to benefit from changes to resolv.conf nscd must be restarted when
192 * resolv.conf is updated, removed or created. If res_getXbyY calls
193 * are removed from NSS then this check could be removed.
197 _nscd_restart_if_cfgfile_changed()
200 static mutex_t nsswitch_lock
= DEFAULTMUTEX
;
201 static timestruc_t last_nsswitch_check
= { 0 };
202 static timestruc_t last_nsswitch_modified
= { 0 };
203 static timestruc_t last_resolv_modified
= { -1, 0 };
204 static mutex_t restarting_lock
= DEFAULTMUTEX
;
205 static int restarting
= 0;
207 time_t now
= time(NULL
);
208 char *me
= "_nscd_restart_if_cfgfile_changed";
210 #define FLAG_RESTART_REQUIRED if (restarting == 0) {\
211 (void) mutex_lock(&restarting_lock);\
212 if (restarting == 0) {\
216 (void) mutex_unlock(&restarting_lock);\
222 if (now
- last_nsswitch_check
.tv_sec
< _NSC_FILE_CHECK_TIME
)
225 (void) mutex_lock(&nsswitch_lock
);
227 if (now
- last_nsswitch_check
.tv_sec
>= _NSC_FILE_CHECK_TIME
) {
231 last_nsswitch_check
.tv_sec
= now
;
232 last_nsswitch_check
.tv_nsec
= 0;
234 (void) mutex_unlock(&nsswitch_lock
); /* let others continue */
236 if (stat("/etc/nsswitch.conf", &nss_buf
) < 0) {
238 } else if (last_nsswitch_modified
.tv_sec
== 0) {
239 last_nsswitch_modified
= nss_buf
.st_mtim
;
242 if (last_nsswitch_modified
.tv_sec
< nss_buf
.st_mtim
.tv_sec
||
243 (last_nsswitch_modified
.tv_sec
== nss_buf
.st_mtim
.tv_sec
&&
244 last_nsswitch_modified
.tv_nsec
< nss_buf
.st_mtim
.tv_nsec
)) {
245 FLAG_RESTART_REQUIRED
;
249 if (stat("/etc/resolv.conf", &res_buf
) < 0) {
250 /* Unable to stat file, were we previously? */
251 if (last_resolv_modified
.tv_sec
> 0) {
252 /* Yes, it must have been removed. */
253 FLAG_RESTART_REQUIRED
;
254 } else if (last_resolv_modified
.tv_sec
== -1) {
255 /* No, then we've never seen it. */
256 last_resolv_modified
.tv_sec
= 0;
258 } else if (last_resolv_modified
.tv_sec
== -1) {
259 /* We've just started and file is present. */
260 last_resolv_modified
= res_buf
.st_mtim
;
261 } else if (last_resolv_modified
.tv_sec
== 0) {
262 /* Wasn't there at start-up. */
263 FLAG_RESTART_REQUIRED
;
264 } else if (last_resolv_modified
.tv_sec
<
265 res_buf
.st_mtim
.tv_sec
||
266 (last_resolv_modified
.tv_sec
==
267 res_buf
.st_mtim
.tv_sec
&&
268 last_resolv_modified
.tv_nsec
<
269 res_buf
.st_mtim
.tv_nsec
)) {
270 FLAG_RESTART_REQUIRED
;
278 * if in self cred mode, kill the forker and
281 if (_nscd_is_self_cred_on(0, NULL
)) {
283 _nscd_kill_all_children();
289 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_INFO
)
290 (me
, "nscd restart due to %s or %s change\n",
291 "/etc/nsswitch.conf", "resolv.conf");
293 * try to restart under smf
295 if ((fmri
= getenv("SMF_FMRI")) == NULL
) {
296 /* not running under smf - reexec */
297 (void) execv(main_execname
, main_argv
);
298 exit(1); /* just in case */
301 if (smf_restart_instance(fmri
) == 0)
302 (void) sleep(10); /* wait a bit */
303 exit(1); /* give up waiting for resurrection */
307 (void) mutex_unlock(&nsswitch_lock
);
311 _nscd_get_client_euid()
315 char *me
= "get_client_euid";
317 if (door_ucred(&uc
) != 0) {
318 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
319 (me
, "door_ucred: %s\n", strerror(errno
));
323 id
= ucred_geteuid(uc
);
329 * Check to see if the door client's euid is 0 or if it has required_priv
330 * privilege. Return 0 if yes, -1 otherwise.
331 * Supported values for required_priv are:
332 * - NSCD_ALL_PRIV: for all zones privileges
333 * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege
336 _nscd_check_client_priv(int required_priv
)
340 const priv_set_t
*eset
;
341 char *me
= "_nscd_check_client_read_priv";
342 priv_set_t
*zs
; /* zone */
344 if (door_ucred(&uc
) != 0) {
345 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
346 (me
, "door_ucred: %s\n", strerror(errno
));
350 if (ucred_geteuid(uc
) == 0) {
355 eset
= ucred_getprivset(uc
, PRIV_EFFECTIVE
);
356 switch (required_priv
) {
358 zs
= priv_str_to_set("zone", ",", NULL
);
359 if (!priv_isequalset(eset
, zs
)) {
360 _NSCD_LOG(NSCD_LOG_FRONT_END
,
361 NSCD_LOG_LEVEL_ERROR
)
362 (me
, "missing all zones privileges\n");
368 if (!priv_ismember(eset
, PRIV_FILE_DAC_READ
))
372 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
373 (me
, "unknown required_priv: %d\n", required_priv
);
386 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
388 const priv_set_t
*eset
;
391 char *me
= "N2N_check_priv";
393 if (door_ucred(&uc
) != 0) {
395 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
396 (me
, "door_ucred: %s\n", strerror(errno
));
398 NSCD_SET_STATUS(phdr
, NSS_ERROR
, errnum
);
402 eset
= ucred_getprivset(uc
, PRIV_EFFECTIVE
);
403 zoneid
= ucred_getzoneid(uc
);
405 if ((zoneid
!= GLOBAL_ZONEID
&& zoneid
!= getzoneid()) ||
406 eset
!= NULL
? !priv_ismember(eset
, PRIV_SYS_ADMIN
) :
407 ucred_geteuid(uc
) != 0) {
409 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
)
410 (me
, "%s call failed(cred): caller pid %d, uid %d, "
411 "euid %d, zoneid %d\n", dc_str
, ucred_getpid(uc
),
412 ucred_getruid(uc
), ucred_geteuid(uc
), zoneid
);
415 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EACCES
);
419 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
420 (me
, "nscd received %s cmd from pid %d, uid %d, "
421 "euid %d, zoneid %d\n", dc_str
, ucred_getpid(uc
),
422 ucred_getruid(uc
), ucred_geteuid(uc
), zoneid
);
426 NSCD_SET_STATUS_SUCCESS(phdr
);
430 _nscd_APP_check_cred(
437 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
443 char *me
= "_nscd_APP_check_cred";
445 if (door_ucred(&uc
) != 0) {
447 _NSCD_LOG(log_comp
, NSCD_LOG_LEVEL_ERROR
)
448 (me
, "door_ucred: %s\n", strerror(errno
));
450 NSCD_SET_STATUS(phdr
, NSS_ERROR
, errnum
);
454 NSCD_SET_STATUS_SUCCESS(phdr
);
455 pid
= ucred_getpid(uc
);
456 if (NSS_PACKED_CRED_CHECK(buf
, ruid
= ucred_getruid(uc
),
457 euid
= ucred_geteuid(uc
))) {
459 if (*pidp
== (pid_t
)-1)
461 else if (*pidp
!= pid
) {
462 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EACCES
);
466 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EACCES
);
471 if (NSCD_STATUS_IS_NOT_OK(phdr
)) {
472 _NSCD_LOG(log_comp
, log_level
)
473 (me
, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
474 "euid %d, header ruid %d, header euid %d\n", dc_str
,
475 pid
, (pidp
!= NULL
) ? *pidp
: -1, ruid
, euid
,
476 ((nss_pheader_t
*)(buf
))->p_ruid
,
477 ((nss_pheader_t
*)(buf
))->p_euid
);
481 /* log error and return -1 when an invalid packed buffer header is found */
483 pheader_error(nss_pheader_t
*phdr
, uint32_t call_number
)
487 switch (call_number
) {
489 call_num_str
= "NSCD_SEARCH";
492 call_num_str
= "NSCD_SETENT";
495 call_num_str
= "NSCD_GETENT";
498 call_num_str
= "NSCD_ENDENT";
501 call_num_str
= "NSCD_PUT";
504 call_num_str
= "NSCD_GETHINTS";
507 call_num_str
= "UNKNOWN";
511 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
)
512 ("pheader_error", "call number %s: invalid packed buffer header\n",
515 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EINVAL
);
520 * Validate the header of a getXbyY or setent/getent/endent request.
521 * Return 0 if good, -1 otherwise.
523 * A valid header looks like the following (size is arg_size, does
524 * not include the output area):
525 * +----------------------------------+ --
526 * | nss_pheader_t (header fixed part)| ^
528 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
529 * | data_off .... | |
531 * +----------------------------------+ <----- dbd_off
532 * | dbd (database description) | ^
533 * | nss_dbd_t + up to 3 strings | |
534 * | length = sizeof(nss_dbd_t) + | len = key_off - dbd_off
535 * | length of 3 strings + | |
536 * | length of padding | |
537 * | (total length in multiple of 4) | v
538 * +----------------------------------+ <----- key_off
540 * | nss_XbyY_key_t, content varies, | |
541 * | based on database and lookup op | len = data_off - key_off
542 * | length = data_off - key_off | |
543 * | including padding, multiple of 4 | v
544 * +----------------------------------+ <----- data_off (= arg_size)
546 * | area to hold results | |
547 * | | len = data_len (= pbufsiz -
550 * +----------------------------------+ <----- pbufsiz
556 uint32_t call_number
)
558 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
562 * current version is NSCD_HEADER_REV, length of the fixed part
563 * of the header must match the size of nss_pheader_t
565 if (phdr
->p_version
!= NSCD_HEADER_REV
||
566 phdr
->dbd_off
!= sizeof (nss_pheader_t
))
567 return (pheader_error(phdr
, call_number
));
570 * buffer size and offsets must be in multiple of 4
572 if ((arg_size
& 3) || (phdr
->dbd_off
& 3) || (phdr
->key_off
& 3) ||
573 (phdr
->data_off
& 3))
574 return (pheader_error(phdr
, call_number
));
577 * the input arg_size is the length of the request header
578 * and should be less than NSCD_PHDR_MAXLEN
580 if (phdr
->data_off
!= arg_size
|| arg_size
> NSCD_PHDR_MAXLEN
)
581 return (pheader_error(phdr
, call_number
));
583 /* get length of the dbd area */
584 l1
= phdr
->key_off
- phdr
-> dbd_off
;
587 * dbd area may contain padding, so length of dbd should
588 * not be less than the length of the actual data
590 if (l1
< phdr
->dbd_len
)
591 return (pheader_error(phdr
, call_number
));
593 /* get length of the key area */
594 l2
= phdr
->data_off
- phdr
->key_off
;
597 * key area may contain padding, so length of key area should
598 * not be less than the length of the actual data
600 if (l2
< phdr
->key_len
)
601 return (pheader_error(phdr
, call_number
));
604 * length of fixed part + lengths of dbd and key area = length of
607 if (sizeof (nss_pheader_t
) + l1
+ l2
!= phdr
->data_off
)
608 return (pheader_error(phdr
, call_number
));
610 /* header length + data length = buffer length */
611 if (phdr
->data_off
+ phdr
->data_len
!= phdr
->pbufsiz
)
612 return (pheader_error(phdr
, call_number
));
617 /* log error and return -1 when an invalid nscd to nscd buffer is found */
619 N2Nbuf_error(nss_pheader_t
*phdr
, uint32_t call_number
)
623 switch (call_number
) {
625 call_num_str
= "NSCD_PING";
629 call_num_str
= "NSCD_IMHERE";
633 call_num_str
= "NSCD_PULSE";
637 call_num_str
= "NSCD_FORK";
641 call_num_str
= "NSCD_KILL";
645 call_num_str
= "NSCD_REFRESH";
648 case NSCD_GETPUADMIN
:
649 call_num_str
= "NSCD_GETPUADMIN";
653 call_num_str
= "NSCD_GETADMIN";
657 call_num_str
= "NSCD_SETADMIN";
660 case NSCD_KILLSERVER
:
661 call_num_str
= "NSCD_KILLSERVER";
664 call_num_str
= "UNKNOWN";
668 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
)
669 ("N2Nbuf_error", "call number %s: invalid N2N buffer\n", call_num_str
);
671 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
672 NSCD_DOOR_BUFFER_CHECK_FAILED
);
678 * Validate the buffer of an nscd to nscd request.
679 * Return 0 if good, -1 otherwise.
681 * A valid buffer looks like the following (size is arg_size):
682 * +----------------------------------+ --
683 * | nss_pheader_t (header fixed part)| ^
685 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
686 * | data_off .... | |
688 * +----------------------------------+ <---dbd_off = key_off = data_off
690 * | input data/output data | |
691 * | OR no data | len = data_len (= pbufsiz -
693 * | | | len could be zero
695 * +----------------------------------+ <--- pbufsiz
701 uint32_t call_number
)
703 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
706 * current version is NSCD_HEADER_REV, length of the fixed part
707 * of the header must match the size of nss_pheader_t
709 if (phdr
->p_version
!= NSCD_HEADER_REV
||
710 phdr
->dbd_off
!= sizeof (nss_pheader_t
))
711 return (N2Nbuf_error(phdr
, call_number
));
714 * There are no dbd and key data, so the dbd, key, data
715 * offsets should be equal
717 if (phdr
->dbd_off
!= phdr
->key_off
||
718 phdr
->dbd_off
!= phdr
->data_off
)
719 return (N2Nbuf_error(phdr
, call_number
));
722 * the input arg_size is the buffer length and should
723 * be less or equal than NSCD_N2NBUF_MAXLEN
725 if (phdr
->pbufsiz
!= arg_size
|| arg_size
> NSCD_N2NBUF_MAXLEN
)
726 return (N2Nbuf_error(phdr
, call_number
));
728 /* header length + data length = buffer length */
729 if (phdr
->data_off
+ phdr
->data_len
!= phdr
->pbufsiz
)
730 return (N2Nbuf_error(phdr
, call_number
));
736 lookup(char *argp
, size_t arg_size
)
738 nsc_lookup_args_t largs
;
739 char space
[NSCD_LOOKUP_BUFSIZE
];
740 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
742 NSCD_ALLOC_LOOKUP_BUFFER(argp
, arg_size
, phdr
, space
,
746 * make sure the first couple bytes of the data area is null,
747 * so that bad strings in the packed header stop here
749 (void) memset((char *)phdr
+ phdr
->data_off
, 0, 16);
751 (void) memset(&largs
, 0, sizeof (largs
));
753 largs
.bufsize
= arg_size
;
754 nsc_lookup(&largs
, 0);
757 * only the PUN needs to keep track of the
758 * activity count to determine when to
761 if (_whoami
== NSCD_CHILD
) {
762 (void) mutex_lock(&activity_lock
);
764 (void) mutex_unlock(&activity_lock
);
767 NSCD_SET_RETURN_ARG(phdr
, arg_size
);
768 (void) door_return(argp
, arg_size
, NULL
, 0);
772 getent(char *argp
, size_t arg_size
)
774 char space
[NSCD_LOOKUP_BUFSIZE
];
775 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
777 NSCD_ALLOC_LOOKUP_BUFFER(argp
, arg_size
, phdr
, space
, sizeof (space
));
779 nss_pgetent(argp
, arg_size
);
781 NSCD_SET_RETURN_ARG(phdr
, arg_size
);
782 (void) door_return(argp
, arg_size
, NULL
, 0);
786 is_db_per_user(void *buf
, char *dblist
)
788 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
793 /* copy db name into a temp buffer */
794 pdbd
= (nss_dbd_t
*)((void *)((char *)buf
+ phdr
->dbd_off
));
795 dbname
= (char *)pdbd
+ pdbd
->o_name
;
796 len
= strlen(dbname
);
797 dbn
= alloca(len
+ 2);
798 (void) memcpy(dbn
, dbname
, len
);
800 /* check if <dbname> + ',' can be found in the dblist string */
803 if (strstr(dblist
, dbn
) != NULL
)
807 * check if <dbname> can be found in the last part
808 * of the dblist string
811 if (strstr(dblist
, dbn
) != NULL
)
818 * Check to see if all conditions are met for processing per-user
819 * requests. Returns 1 if yes, -1 if backend is not configured,
823 need_per_user_door(void *buf
, int whoami
, uid_t uid
, char **dblist
)
825 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
827 NSCD_SET_STATUS_SUCCESS(phdr
);
829 /* if already a per-user nscd, no need to get per-user door */
830 if (whoami
== NSCD_CHILD
)
833 /* forker shouldn't be asked */
834 if (whoami
== NSCD_FORKER
) {
835 NSCD_SET_STATUS(phdr
, NSS_ERROR
, ENOTSUP
);
839 /* if door client is root, no need for a per-user door */
844 * if per-user lookup is not configured, no per-user
847 if (_nscd_is_self_cred_on(0, dblist
) == 0)
851 * if per-user lookup is not configured for the db,
854 if (is_db_per_user(phdr
, *dblist
) == 0)
861 if_selfcred_return_per_user_door(char *argp
, size_t arg_size
,
862 door_desc_t
*dp
, int whoami
)
864 nss_pheader_t
*phdr
= (nss_pheader_t
*)((void *)argp
);
873 * check to see if self-cred is configured and
874 * need to return an alternate PUN door
876 if (per_user_is_on
== 1) {
877 rc
= need_per_user_door(argp
, whoami
,
878 _nscd_get_client_euid(), &dblist
);
884 * self-cred not configured, and no error detected,
885 * return to continue the door call processing
887 if (NSCD_STATUS_IS_OK(phdr
))
891 * configured but error detected,
892 * stop the door call processing
894 (void) door_return(argp
, phdr
->data_off
, NULL
, 0);
897 /* get the alternate PUN door */
898 _nscd_proc_alt_get(argp
, &door
);
899 if (NSCD_GET_STATUS(phdr
) != NSS_ALTRETRY
) {
900 (void) door_return(argp
, phdr
->data_off
, NULL
, 0);
903 /* return the alternate door descriptor */
904 len
= strlen(dblist
) + 1;
905 space
= alloca(arg_size
+ len
);
906 phdr
->data_len
= len
;
907 (void) memcpy(space
, phdr
, arg_size
);
908 (void) strncpy((char *)space
+ arg_size
, dblist
, len
);
910 dp
->d_attributes
= DOOR_DESCRIPTOR
;
911 dp
->d_data
.d_desc
.d_descriptor
= door
;
913 (void) door_return(space
, arg_size
, dp
, 1);
918 switcher(void *cookie
, char *argp
, size_t arg_size
,
919 door_desc_t
*dp
, uint_t n_desc
)
923 nss_pheader_t
*phdr
= (nss_pheader_t
*)((void *)argp
);
928 char *me
= "switcher";
930 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
931 (me
, "switcher ...\n");
933 if (argp
== DOOR_UNREF_DATA
) {
934 (void) printf("Door Slam... exiting\n");
938 if (argp
== NULL
) { /* empty door call */
939 (void) door_return(NULL
, 0, 0, 0); /* return the favor */
943 * need to restart if main nscd and config file(s) changed
945 if (_whoami
== NSCD_MAIN
)
946 _nscd_restart_if_cfgfile_changed();
948 if ((phdr
->nsc_callnumber
& NSCDV2CATMASK
) == NSCD_CALLCAT_APP
) {
950 /* make sure the packed buffer header is good */
951 if (validate_pheader(argp
, arg_size
,
952 phdr
->nsc_callnumber
) == -1)
953 (void) door_return(argp
, arg_size
, NULL
, 0);
955 switch (phdr
->nsc_callnumber
) {
959 /* if a fallback to main nscd, skip per-user setup */
960 if (phdr
->p_status
!= NSS_ALTRETRY
)
961 if_selfcred_return_per_user_door(argp
, arg_size
,
963 lookup(argp
, arg_size
);
969 _nscd_APP_check_cred(argp
, &ent_pid
, "NSCD_SETENT",
970 NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
);
971 if (NSCD_STATUS_IS_OK(phdr
)) {
972 if_selfcred_return_per_user_door(argp
, arg_size
,
974 nss_psetent(argp
, arg_size
, ent_pid
);
980 getent(argp
, arg_size
);
985 nss_pendent(argp
, arg_size
);
990 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
991 (me
, "door call NSCD_PUT not supported yet\n");
993 NSCD_SET_STATUS(phdr
, NSS_ERROR
, ENOTSUP
);
998 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
999 (me
, "door call NSCD_GETHINTS not supported yet\n");
1001 NSCD_SET_STATUS(phdr
, NSS_ERROR
, ENOTSUP
);
1006 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1007 (me
, "Unknown name service door call op %x\n",
1008 phdr
->nsc_callnumber
);
1010 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EINVAL
);
1014 (void) door_return(argp
, arg_size
, NULL
, 0);
1018 callnum
= phdr
->nsc_callnumber
& ~NSCD_WHOAMI
;
1019 if (callnum
== NSCD_IMHERE
||
1020 callnum
== NSCD_PULSE
|| callnum
== NSCD_FORK
)
1021 iam
= phdr
->nsc_callnumber
& NSCD_WHOAMI
;
1023 callnum
= phdr
->nsc_callnumber
;
1025 /* nscd -> nscd v2 calls */
1027 /* make sure the buffer is good */
1028 if (validate_N2Nbuf(argp
, arg_size
, callnum
) == -1)
1029 (void) door_return(argp
, arg_size
, NULL
, 0);
1034 NSCD_SET_STATUS_SUCCESS(phdr
);
1038 _nscd_proc_iamhere(argp
, dp
, n_desc
, iam
);
1042 N2N_check_priv(argp
, "NSCD_PULSE");
1043 if (NSCD_STATUS_IS_OK(phdr
))
1044 _nscd_proc_pulse(argp
, iam
);
1048 N2N_check_priv(argp
, "NSCD_FORK");
1049 if (NSCD_STATUS_IS_OK(phdr
))
1050 _nscd_proc_fork(argp
, iam
);
1054 N2N_check_priv(argp
, "NSCD_KILL");
1055 if (NSCD_STATUS_IS_OK(phdr
))
1060 N2N_check_priv(argp
, "NSCD_REFRESH");
1061 if (NSCD_STATUS_IS_OK(phdr
)) {
1062 if (_nscd_refresh() != NSCD_SUCCESS
)
1064 NSCD_SET_STATUS_SUCCESS(phdr
);
1068 case NSCD_GETPUADMIN
:
1070 if (_nscd_is_self_cred_on(0, NULL
)) {
1071 _nscd_peruser_getadmin(argp
, sizeof (nscd_admin_t
));
1073 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
1074 NSCD_SELF_CRED_NOT_CONFIGURED
);
1080 len
= _nscd_door_getadmin((void *)argp
);
1084 /* size of door buffer not big enough, allocate one */
1085 NSCD_ALLOC_DOORBUF(NSCD_GETADMIN
, len
, uptr
, buflen
);
1087 /* copy packed header */
1088 *(nss_pheader_t
*)uptr
= *(nss_pheader_t
*)((void *)argp
);
1090 /* set new buffer size */
1091 ((nss_pheader_t
*)uptr
)->pbufsiz
= buflen
;
1093 /* try one more time */
1094 (void) _nscd_door_getadmin((void *)uptr
);
1095 (void) door_return(uptr
, buflen
, NULL
, 0);
1099 N2N_check_priv(argp
, "NSCD_SETADMIN");
1100 if (NSCD_STATUS_IS_OK(phdr
))
1101 _nscd_door_setadmin(argp
);
1104 case NSCD_KILLSERVER
:
1105 N2N_check_priv(argp
, "NSCD_KILLSERVER");
1106 if (NSCD_STATUS_IS_OK(phdr
)) {
1107 /* also kill the forker nscd if one is running */
1108 _nscd_kill_forker();
1114 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1115 (me
, "Unknown name service door call op %d\n",
1116 phdr
->nsc_callnumber
);
1118 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EINVAL
);
1120 (void) door_return(argp
, arg_size
, NULL
, 0);
1124 (void) door_return(argp
, arg_size
, NULL
, 0);
1128 _nscd_setup_server(char *execname
, char **argv
)
1133 int bind_failed
= 0;
1137 struct sigaction action
;
1138 char *me
= "_nscd_setup_server";
1140 main_execname
= execname
;
1143 /* Any nscd process is to ignore SIGPIPE */
1144 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) {
1146 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1147 (me
, "signal (SIGPIPE): %s\n", strerror(errnum
));
1151 keep_open_dns_socket();
1154 * the max number of server threads should be fixed now, so
1155 * set flag to indicate that no in-flight change is allowed
1157 max_servers_set
= 1;
1159 (void) thr_keycreate(&lookup_state_key
, NULL
);
1160 (void) sema_init(&common_sema
, frontend_cfg_g
.common_worker_threads
,
1163 /* Establish server thread pool */
1164 (void) door_server_create(server_create
);
1165 if (thr_keycreate(&server_key
, server_destroy
) != 0) {
1167 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1168 (me
, "thr_keycreate (server thread): %s\n",
1174 if ((fd
= door_create(switcher
, NAME_SERVICE_DOOR_COOKIE
,
1175 DOOR_UNREF
| DOOR_NO_CANCEL
)) < 0) {
1177 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1178 (me
, "door_create: %s\n", strerror(errnum
));
1182 /* if not main nscd, no more setup to do */
1183 if (_whoami
!= NSCD_MAIN
)
1186 /* bind to file system */
1187 if (is_system_labeled() && (getzoneid() == GLOBAL_ZONEID
)) {
1188 if (stat(TSOL_NAME_SERVICE_DOOR
, &buf
) < 0) {
1191 /* make sure the door will be readable by all */
1192 old_mask
= umask(0);
1193 if ((newfd
= creat(TSOL_NAME_SERVICE_DOOR
, 0444)) < 0) {
1195 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1196 NSCD_LOG_LEVEL_ERROR
)
1197 (me
, "Cannot create %s: %s\n",
1198 TSOL_NAME_SERVICE_DOOR
,
1202 /* rstore the old file mode creation mask */
1203 (void) umask(old_mask
);
1204 (void) close(newfd
);
1206 if (symlink(TSOL_NAME_SERVICE_DOOR
, NAME_SERVICE_DOOR
) != 0) {
1207 if (errno
!= EEXIST
) {
1209 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1210 NSCD_LOG_LEVEL_ERROR
)
1211 (me
, "Cannot symlink %s: %s\n",
1212 NAME_SERVICE_DOOR
, strerror(errnum
));
1216 } else if (stat(NAME_SERVICE_DOOR
, &buf
) < 0) {
1219 /* make sure the door will be readable by all */
1220 old_mask
= umask(0);
1221 if ((newfd
= creat(NAME_SERVICE_DOOR
, 0444)) < 0) {
1223 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1224 (me
, "Cannot create %s: %s\n", NAME_SERVICE_DOOR
,
1228 /* rstore the old file mode creation mask */
1229 (void) umask(old_mask
);
1230 (void) close(newfd
);
1233 if (bind_failed
== 1) {
1234 (void) door_revoke(fd
);
1238 if (fattach(fd
, NAME_SERVICE_DOOR
) < 0) {
1239 if ((errno
!= EBUSY
) ||
1240 (fdetach(NAME_SERVICE_DOOR
) < 0) ||
1241 (fattach(fd
, NAME_SERVICE_DOOR
) < 0)) {
1243 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1244 (me
, "fattach: %s\n", strerror(errnum
));
1245 (void) door_revoke(fd
);
1251 * kick off routing socket monitor thread
1253 if (thr_create(NULL
, NULL
,
1254 (void *(*)(void *))rts_mon
, 0, 0, NULL
) != 0) {
1256 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1257 (me
, "thr_create (routing socket monitor): %s\n",
1260 (void) door_revoke(fd
);
1265 * set up signal handler for SIGHUP
1267 action
.sa_handler
= dozip
;
1268 action
.sa_flags
= 0;
1269 (void) sigemptyset(&action
.sa_mask
);
1270 (void) sigemptyset(&myset
);
1271 (void) sigaddset(&myset
, SIGHUP
);
1273 if (sigaction(SIGHUP
, &action
, NULL
) < 0) {
1275 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1276 (me
, "sigaction (SIGHUP): %s\n", strerror(errnum
));
1278 (void) door_revoke(fd
);
1286 _nscd_setup_child_server(int did
)
1292 char *me
= "_nscd_setup_child_server";
1294 /* Re-establish our own server thread pool */
1295 (void) door_server_create(server_create
);
1296 if (thr_keycreate(&server_key
, server_destroy
) != 0) {
1298 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
1299 (me
, "thr_keycreate failed: %s", strerror(errnum
));
1304 * Create a new door.
1305 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork)
1308 if ((fd
= door_create(switcher
, NAME_SERVICE_DOOR_COOKIE
,
1309 DOOR_REFUSE_DESC
|DOOR_UNREF
|DOOR_NO_CANCEL
)) < 0) {
1311 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
1312 (me
, "door_create failed: %s", strerror(errnum
));
1317 * kick off routing socket monitor thread
1319 if (thr_create(NULL
, NULL
,
1320 (void *(*)(void *))rts_mon
, 0, 0, NULL
) != 0) {
1322 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1323 (me
, "thr_create (routing socket monitor): %s\n",
1325 (void) door_revoke(fd
);
1330 * start monitoring the states of the name service clients
1332 rc
= _nscd_init_smf_monitor();
1333 if (rc
!= NSCD_SUCCESS
) {
1334 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1335 (me
, "unable to start the SMF monitor (rc = %d)\n", rc
);
1337 (void) door_revoke(fd
);
1345 _nscd_alloc_frontend_cfg()
1347 frontend_cfg
= calloc(NSCD_NUM_DB
, sizeof (nscd_cfg_frontend_t
));
1348 if (frontend_cfg
== NULL
)
1349 return (NSCD_NO_MEMORY
);
1351 return (NSCD_SUCCESS
);
1357 _nscd_cfg_frontend_notify(
1359 struct nscd_cfg_param_desc
*pdesc
,
1360 nscd_cfg_id_t
*nswdb
,
1361 nscd_cfg_flag_t dflag
,
1362 nscd_cfg_error_t
**errorp
,
1368 * At init time, the whole group of config params are received.
1369 * At update time, group or individual parameter value could
1373 if (_nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_INIT
) ||
1374 _nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_GROUP
)) {
1376 * group data is received, copy in the
1379 if (_nscd_cfg_flag_is_set(pdesc
->pflag
, NSCD_CFG_PFLAG_GLOBAL
))
1380 frontend_cfg_g
= *(nscd_cfg_global_frontend_t
*)data
;
1382 frontend_cfg
[nswdb
->index
] =
1383 *(nscd_cfg_frontend_t
*)data
;
1387 * individual paramater is received: copy in the
1390 if (_nscd_cfg_flag_is_set(pdesc
->pflag
, NSCD_CFG_PFLAG_GLOBAL
))
1391 dp
= (char *)&frontend_cfg_g
+ pdesc
->p_offset
;
1393 dp
= (char *)&frontend_cfg
[nswdb
->index
] +
1395 (void) memcpy(dp
, data
, pdesc
->p_size
);
1398 return (NSCD_SUCCESS
);
1403 _nscd_cfg_frontend_verify(
1405 struct nscd_cfg_param_desc
*pdesc
,
1406 nscd_cfg_id_t
*nswdb
,
1407 nscd_cfg_flag_t dflag
,
1408 nscd_cfg_error_t
**errorp
,
1412 char *me
= "_nscd_cfg_frontend_verify";
1415 * if max. number of server threads is set and in effect,
1416 * don't allow changing of the frontend configuration
1418 if (max_servers_set
) {
1419 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_INFO
)
1420 (me
, "changing of the frontend configuration not allowed now");
1422 return (NSCD_CFG_CHANGE_NOT_ALLOWED
);
1425 return (NSCD_SUCCESS
);
1430 _nscd_cfg_frontend_get_stat(
1432 struct nscd_cfg_stat_desc
*sdesc
,
1433 nscd_cfg_id_t
*nswdb
,
1434 nscd_cfg_flag_t
*dflag
,
1435 void (**free_stat
)(void *stat
),
1436 nscd_cfg_error_t
**errorp
)
1438 return (NSCD_SUCCESS
);
1442 _nscd_init_cache_sema(sema_t
*sema
, char *cache_name
)
1447 if (max_servers
== 0)
1448 max_servers
= frontend_cfg_g
.common_worker_threads
+
1449 frontend_cfg_g
.cache_hit_threads
;
1451 for (i
= 0; i
< NSCD_NUM_DB
; i
++) {
1453 dbn
= NSCD_NSW_DB_NAME(i
);
1454 if (strcasecmp(dbn
, cache_name
) == 0) {
1455 j
= frontend_cfg
[i
].worker_thread_per_nsw_db
;
1456 (void) sema_init(sema
, j
, USYNC_THREAD
, 0);
1464 * Monitor the routing socket. Address lists stored in the ipnodes
1465 * cache are sorted based on destination address selection rules,
1466 * so when things change that could affect that sorting (interfaces
1467 * go up or down, flags change, etc.), we clear that cache so the
1468 * list will be re-ordered the next time the hostname is resolved.
1473 int rt_sock
, rdlen
, idx
;
1476 struct rt_msghdr rtm
;
1477 struct sockaddr_storage addrs
[RTA_NUMBITS
];
1479 struct if_msghdr ifm
;
1480 struct ifa_msghdr ifam
;
1482 struct ifa_msghdr
*ifam
= &mbuf
.ifam
;
1483 char *me
= "rts_mon";
1485 (void) thr_setname(thr_self(), me
);
1487 rt_sock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
1489 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1490 (me
, "Failed to open routing socket: %s\n", strerror(errno
));
1495 rdlen
= read(rt_sock
, &mbuf
, sizeof (mbuf
));
1497 if (rdlen
== 0 || (errno
!= EINTR
&& errno
!= EAGAIN
)) {
1498 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1499 NSCD_LOG_LEVEL_ERROR
)
1500 (me
, "routing socket read: %s\n",
1506 if (ifam
->ifam_version
!= RTM_VERSION
) {
1507 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1508 NSCD_LOG_LEVEL_ERROR
)
1509 (me
, "rx unknown version (%d) on "
1510 "routing socket.\n",
1511 ifam
->ifam_version
);
1514 switch (ifam
->ifam_type
) {
1517 /* if no ipnodes cache, then nothing to do */
1518 idx
= get_cache_idx("ipnodes");
1519 if (cache_ctx_p
[idx
] == NULL
||
1520 cache_ctx_p
[idx
]->reaper_on
!= nscd_true
)
1522 nsc_invalidate(cache_ctx_p
[idx
], NULL
, NULL
);
1540 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1541 (me
, "rx unknown msg type (%d) on routing socket.\n",
1549 keep_open_dns_socket(void)
1551 _res
.options
|= RES_STAYOPEN
; /* just keep this udp socket open */