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.
38 #include <sys/socket.h>
39 #include <net/route.h>
44 #include "nscd_common.h"
45 #include "nscd_door.h"
46 #include "nscd_config.h"
47 #include "nscd_switch.h"
49 #include "nscd_selfcred.h"
50 #include "nscd_frontend.h"
51 #include "nscd_admin.h"
53 static void rts_mon(void);
54 static void keep_open_dns_socket(void);
56 extern nsc_ctx_t
*cache_ctx_p
[];
59 * Current active Configuration data for the frontend component
61 static nscd_cfg_global_frontend_t frontend_cfg_g
;
62 static nscd_cfg_frontend_t
*frontend_cfg
;
64 static int max_servers
= 0;
65 static int max_servers_set
= 0;
66 static int per_user_is_on
= 1;
68 static char *main_execname
;
69 static char **main_argv
;
72 extern mutex_t activity_lock
;
74 static sema_t common_sema
;
76 static thread_key_t lookup_state_key
;
77 static mutex_t create_lock
= DEFAULTMUTEX
;
78 static int num_servers
= 0;
79 static thread_key_t server_key
;
82 * Bind a TSD value to a server thread. This enables the destructor to
83 * be called if/when this thread exits. This would be a programming
84 * error, but better safe than sorry.
88 server_tsd_bind(void *arg
)
90 static void *value
= 0;
92 /* disable cancellation to avoid hangs if server threads disappear */
93 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, NULL
);
94 (void) thr_setspecific(server_key
, value
);
95 (void) door_return(NULL
, 0, NULL
, 0);
102 * Server threads are created here.
106 server_create(door_info_t
*dip
)
108 (void) mutex_lock(&create_lock
);
109 if (++num_servers
> max_servers
) {
111 (void) mutex_unlock(&create_lock
);
114 (void) mutex_unlock(&create_lock
);
115 (void) thr_create(NULL
, 0, server_tsd_bind
, NULL
,
116 THR_BOUND
|THR_DETACHED
, NULL
);
120 * Server thread are destroyed here
124 server_destroy(void *arg
)
126 (void) mutex_lock(&create_lock
);
128 (void) mutex_unlock(&create_lock
);
135 _nscd_get_clearance(sema_t
*sema
) {
136 if (sema_trywait(&common_sema
) == 0) {
137 (void) thr_setspecific(lookup_state_key
, NULL
);
141 if (sema_trywait(sema
) == 0) {
142 (void) thr_setspecific(lookup_state_key
, (void*)1);
154 _nscd_release_clearance(sema_t
*sema
) {
157 (void) thr_getspecific(lookup_state_key
, (void**)&which
);
158 if (which
== 0) /* from common pool */ {
159 (void) sema_post(&common_sema
);
163 (void) sema_post(sema
);
174 * _nscd_restart_if_cfgfile_changed()
175 * Restart if modification times of nsswitch.conf or resolv.conf have changed.
177 * If nsswitch.conf has changed then it is possible that sources for
178 * various backends have changed and therefore the current cached
179 * data may not be consistent with the new data sources. By
180 * restarting the cache will be cleared and the new configuration will
183 * The check for resolv.conf is made as only the first call to
184 * res_gethostbyname() or res_getaddrbyname() causes a call to
185 * res_ninit() to occur which in turn parses resolv.conf. Therefore
186 * to benefit from changes to resolv.conf nscd must be restarted when
187 * resolv.conf is updated, removed or created. If res_getXbyY calls
188 * are removed from NSS then this check could be removed.
192 _nscd_restart_if_cfgfile_changed()
195 static mutex_t nsswitch_lock
= DEFAULTMUTEX
;
196 static timestruc_t last_nsswitch_check
= { 0 };
197 static timestruc_t last_nsswitch_modified
= { 0 };
198 static timestruc_t last_resolv_modified
= { -1, 0 };
199 static mutex_t restarting_lock
= DEFAULTMUTEX
;
200 static int restarting
= 0;
202 time_t now
= time(NULL
);
203 char *me
= "_nscd_restart_if_cfgfile_changed";
205 #define FLAG_RESTART_REQUIRED if (restarting == 0) {\
206 (void) mutex_lock(&restarting_lock);\
207 if (restarting == 0) {\
211 (void) mutex_unlock(&restarting_lock);\
217 if (now
- last_nsswitch_check
.tv_sec
< _NSC_FILE_CHECK_TIME
)
220 (void) mutex_lock(&nsswitch_lock
);
222 if (now
- last_nsswitch_check
.tv_sec
>= _NSC_FILE_CHECK_TIME
) {
226 last_nsswitch_check
.tv_sec
= now
;
227 last_nsswitch_check
.tv_nsec
= 0;
229 (void) mutex_unlock(&nsswitch_lock
); /* let others continue */
231 if (stat("/etc/nsswitch.conf", &nss_buf
) < 0) {
233 } else if (last_nsswitch_modified
.tv_sec
== 0) {
234 last_nsswitch_modified
= nss_buf
.st_mtim
;
237 if (last_nsswitch_modified
.tv_sec
< nss_buf
.st_mtim
.tv_sec
||
238 (last_nsswitch_modified
.tv_sec
== nss_buf
.st_mtim
.tv_sec
&&
239 last_nsswitch_modified
.tv_nsec
< nss_buf
.st_mtim
.tv_nsec
)) {
240 FLAG_RESTART_REQUIRED
;
244 if (stat("/etc/resolv.conf", &res_buf
) < 0) {
245 /* Unable to stat file, were we previously? */
246 if (last_resolv_modified
.tv_sec
> 0) {
247 /* Yes, it must have been removed. */
248 FLAG_RESTART_REQUIRED
;
249 } else if (last_resolv_modified
.tv_sec
== -1) {
250 /* No, then we've never seen it. */
251 last_resolv_modified
.tv_sec
= 0;
253 } else if (last_resolv_modified
.tv_sec
== -1) {
254 /* We've just started and file is present. */
255 last_resolv_modified
= res_buf
.st_mtim
;
256 } else if (last_resolv_modified
.tv_sec
== 0) {
257 /* Wasn't there at start-up. */
258 FLAG_RESTART_REQUIRED
;
259 } else if (last_resolv_modified
.tv_sec
<
260 res_buf
.st_mtim
.tv_sec
||
261 (last_resolv_modified
.tv_sec
==
262 res_buf
.st_mtim
.tv_sec
&&
263 last_resolv_modified
.tv_nsec
<
264 res_buf
.st_mtim
.tv_nsec
)) {
265 FLAG_RESTART_REQUIRED
;
273 * if in self cred mode, kill the forker and
276 if (_nscd_is_self_cred_on(0, NULL
)) {
278 _nscd_kill_all_children();
284 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_INFO
)
285 (me
, "nscd restart due to %s or %s change\n",
286 "/etc/nsswitch.conf", "resolv.conf");
288 * try to restart under smf
290 if ((fmri
= getenv("SMF_FMRI")) == NULL
) {
291 /* not running under smf - reexec */
292 (void) execv(main_execname
, main_argv
);
293 exit(1); /* just in case */
296 if (smf_restart_instance(fmri
) == 0)
297 (void) sleep(10); /* wait a bit */
298 exit(1); /* give up waiting for resurrection */
302 (void) mutex_unlock(&nsswitch_lock
);
306 _nscd_get_client_euid()
310 char *me
= "get_client_euid";
312 if (door_ucred(&uc
) != 0) {
313 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
314 (me
, "door_ucred: %s\n", strerror(errno
));
318 id
= ucred_geteuid(uc
);
324 * Check to see if the door client's euid is 0 or if it has required_priv
325 * privilege. Return 0 if yes, -1 otherwise.
326 * Supported values for required_priv are:
327 * - NSCD_ALL_PRIV: for all zones privileges
328 * - NSCD_READ_PRIV: for PRIV_FILE_DAC_READ privilege
331 _nscd_check_client_priv(int required_priv
)
335 const priv_set_t
*eset
;
336 char *me
= "_nscd_check_client_read_priv";
337 priv_set_t
*zs
; /* zone */
339 if (door_ucred(&uc
) != 0) {
340 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
341 (me
, "door_ucred: %s\n", strerror(errno
));
345 if (ucred_geteuid(uc
) == 0) {
350 eset
= ucred_getprivset(uc
, PRIV_EFFECTIVE
);
351 switch (required_priv
) {
353 zs
= priv_str_to_set("zone", ",", NULL
);
354 if (!priv_isequalset(eset
, zs
)) {
355 _NSCD_LOG(NSCD_LOG_FRONT_END
,
356 NSCD_LOG_LEVEL_ERROR
)
357 (me
, "missing all zones privileges\n");
363 if (!priv_ismember(eset
, PRIV_FILE_DAC_READ
))
367 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
368 (me
, "unknown required_priv: %d\n", required_priv
);
381 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
383 const priv_set_t
*eset
;
386 char *me
= "N2N_check_priv";
388 if (door_ucred(&uc
) != 0) {
390 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
391 (me
, "door_ucred: %s\n", strerror(errno
));
393 NSCD_SET_STATUS(phdr
, NSS_ERROR
, errnum
);
397 eset
= ucred_getprivset(uc
, PRIV_EFFECTIVE
);
398 zoneid
= ucred_getzoneid(uc
);
400 if ((zoneid
!= GLOBAL_ZONEID
&& zoneid
!= getzoneid()) ||
401 eset
!= NULL
? !priv_ismember(eset
, PRIV_SYS_ADMIN
) :
402 ucred_geteuid(uc
) != 0) {
404 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
)
405 (me
, "%s call failed(cred): caller pid %d, uid %d, "
406 "euid %d, zoneid %d\n", dc_str
, ucred_getpid(uc
),
407 ucred_getruid(uc
), ucred_geteuid(uc
), zoneid
);
410 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EACCES
);
414 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
415 (me
, "nscd received %s cmd from pid %d, uid %d, "
416 "euid %d, zoneid %d\n", dc_str
, ucred_getpid(uc
),
417 ucred_getruid(uc
), ucred_geteuid(uc
), zoneid
);
421 NSCD_SET_STATUS_SUCCESS(phdr
);
425 _nscd_APP_check_cred(
432 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
438 char *me
= "_nscd_APP_check_cred";
440 if (door_ucred(&uc
) != 0) {
442 _NSCD_LOG(log_comp
, NSCD_LOG_LEVEL_ERROR
)
443 (me
, "door_ucred: %s\n", strerror(errno
));
445 NSCD_SET_STATUS(phdr
, NSS_ERROR
, errnum
);
449 NSCD_SET_STATUS_SUCCESS(phdr
);
450 pid
= ucred_getpid(uc
);
451 if (NSS_PACKED_CRED_CHECK(buf
, ruid
= ucred_getruid(uc
),
452 euid
= ucred_geteuid(uc
))) {
454 if (*pidp
== (pid_t
)-1)
456 else if (*pidp
!= pid
) {
457 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EACCES
);
461 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EACCES
);
466 if (NSCD_STATUS_IS_NOT_OK(phdr
)) {
467 _NSCD_LOG(log_comp
, log_level
)
468 (me
, "%s call failed: caller pid %d (input pid = %d), ruid %d, "
469 "euid %d, header ruid %d, header euid %d\n", dc_str
,
470 pid
, (pidp
!= NULL
) ? *pidp
: -1, ruid
, euid
,
471 ((nss_pheader_t
*)(buf
))->p_ruid
,
472 ((nss_pheader_t
*)(buf
))->p_euid
);
476 /* log error and return -1 when an invalid packed buffer header is found */
478 pheader_error(nss_pheader_t
*phdr
, uint32_t call_number
)
482 switch (call_number
) {
484 call_num_str
= "NSCD_SEARCH";
487 call_num_str
= "NSCD_SETENT";
490 call_num_str
= "NSCD_GETENT";
493 call_num_str
= "NSCD_ENDENT";
496 call_num_str
= "NSCD_PUT";
499 call_num_str
= "NSCD_GETHINTS";
502 call_num_str
= "UNKNOWN";
506 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
)
507 ("pheader_error", "call number %s: invalid packed buffer header\n",
510 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EINVAL
);
515 * Validate the header of a getXbyY or setent/getent/endent request.
516 * Return 0 if good, -1 otherwise.
518 * A valid header looks like the following (size is arg_size, does
519 * not include the output area):
520 * +----------------------------------+ --
521 * | nss_pheader_t (header fixed part)| ^
523 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
524 * | data_off .... | |
526 * +----------------------------------+ <----- dbd_off
527 * | dbd (database description) | ^
528 * | nss_dbd_t + up to 3 strings | |
529 * | length = sizeof(nss_dbd_t) + | len = key_off - dbd_off
530 * | length of 3 strings + | |
531 * | length of padding | |
532 * | (total length in multiple of 4) | v
533 * +----------------------------------+ <----- key_off
535 * | nss_XbyY_key_t, content varies, | |
536 * | based on database and lookup op | len = data_off - key_off
537 * | length = data_off - key_off | |
538 * | including padding, multiple of 4 | v
539 * +----------------------------------+ <----- data_off (= arg_size)
541 * | area to hold results | |
542 * | | len = data_len (= pbufsiz -
545 * +----------------------------------+ <----- pbufsiz
551 uint32_t call_number
)
553 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
557 * current version is NSCD_HEADER_REV, length of the fixed part
558 * of the header must match the size of nss_pheader_t
560 if (phdr
->p_version
!= NSCD_HEADER_REV
||
561 phdr
->dbd_off
!= sizeof (nss_pheader_t
))
562 return (pheader_error(phdr
, call_number
));
565 * buffer size and offsets must be in multiple of 4
567 if ((arg_size
& 3) || (phdr
->dbd_off
& 3) || (phdr
->key_off
& 3) ||
568 (phdr
->data_off
& 3))
569 return (pheader_error(phdr
, call_number
));
572 * the input arg_size is the length of the request header
573 * and should be less than NSCD_PHDR_MAXLEN
575 if (phdr
->data_off
!= arg_size
|| arg_size
> NSCD_PHDR_MAXLEN
)
576 return (pheader_error(phdr
, call_number
));
578 /* get length of the dbd area */
579 l1
= phdr
->key_off
- phdr
-> dbd_off
;
582 * dbd area may contain padding, so length of dbd should
583 * not be less than the length of the actual data
585 if (l1
< phdr
->dbd_len
)
586 return (pheader_error(phdr
, call_number
));
588 /* get length of the key area */
589 l2
= phdr
->data_off
- phdr
->key_off
;
592 * key area may contain padding, so length of key area should
593 * not be less than the length of the actual data
595 if (l2
< phdr
->key_len
)
596 return (pheader_error(phdr
, call_number
));
599 * length of fixed part + lengths of dbd and key area = length of
602 if (sizeof (nss_pheader_t
) + l1
+ l2
!= phdr
->data_off
)
603 return (pheader_error(phdr
, call_number
));
605 /* header length + data length = buffer length */
606 if (phdr
->data_off
+ phdr
->data_len
!= phdr
->pbufsiz
)
607 return (pheader_error(phdr
, call_number
));
612 /* log error and return -1 when an invalid nscd to nscd buffer is found */
614 N2Nbuf_error(nss_pheader_t
*phdr
, uint32_t call_number
)
618 switch (call_number
) {
620 call_num_str
= "NSCD_PING";
624 call_num_str
= "NSCD_IMHERE";
628 call_num_str
= "NSCD_PULSE";
632 call_num_str
= "NSCD_FORK";
636 call_num_str
= "NSCD_KILL";
640 call_num_str
= "NSCD_REFRESH";
643 case NSCD_GETPUADMIN
:
644 call_num_str
= "NSCD_GETPUADMIN";
648 call_num_str
= "NSCD_GETADMIN";
652 call_num_str
= "NSCD_SETADMIN";
655 case NSCD_KILLSERVER
:
656 call_num_str
= "NSCD_KILLSERVER";
659 call_num_str
= "UNKNOWN";
663 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
)
664 ("N2Nbuf_error", "call number %s: invalid N2N buffer\n", call_num_str
);
666 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
667 NSCD_DOOR_BUFFER_CHECK_FAILED
);
673 * Validate the buffer of an nscd to nscd request.
674 * Return 0 if good, -1 otherwise.
676 * A valid buffer looks like the following (size is arg_size):
677 * +----------------------------------+ --
678 * | nss_pheader_t (header fixed part)| ^
680 * | pbufsiz, dbd,off, key_off, | len = sizeof(nss_pheader_t)
681 * | data_off .... | |
683 * +----------------------------------+ <---dbd_off = key_off = data_off
685 * | input data/output data | |
686 * | OR no data | len = data_len (= pbufsiz -
688 * | | | len could be zero
690 * +----------------------------------+ <--- pbufsiz
696 uint32_t call_number
)
698 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
701 * current version is NSCD_HEADER_REV, length of the fixed part
702 * of the header must match the size of nss_pheader_t
704 if (phdr
->p_version
!= NSCD_HEADER_REV
||
705 phdr
->dbd_off
!= sizeof (nss_pheader_t
))
706 return (N2Nbuf_error(phdr
, call_number
));
709 * There are no dbd and key data, so the dbd, key, data
710 * offsets should be equal
712 if (phdr
->dbd_off
!= phdr
->key_off
||
713 phdr
->dbd_off
!= phdr
->data_off
)
714 return (N2Nbuf_error(phdr
, call_number
));
717 * the input arg_size is the buffer length and should
718 * be less or equal than NSCD_N2NBUF_MAXLEN
720 if (phdr
->pbufsiz
!= arg_size
|| arg_size
> NSCD_N2NBUF_MAXLEN
)
721 return (N2Nbuf_error(phdr
, call_number
));
723 /* header length + data length = buffer length */
724 if (phdr
->data_off
+ phdr
->data_len
!= phdr
->pbufsiz
)
725 return (N2Nbuf_error(phdr
, call_number
));
731 lookup(char *argp
, size_t arg_size
)
733 nsc_lookup_args_t largs
;
734 char space
[NSCD_LOOKUP_BUFSIZE
];
735 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
737 NSCD_ALLOC_LOOKUP_BUFFER(argp
, arg_size
, phdr
, space
,
741 * make sure the first couple bytes of the data area is null,
742 * so that bad strings in the packed header stop here
744 (void) memset((char *)phdr
+ phdr
->data_off
, 0, 16);
746 (void) memset(&largs
, 0, sizeof (largs
));
748 largs
.bufsize
= arg_size
;
749 nsc_lookup(&largs
, 0);
752 * only the PUN needs to keep track of the
753 * activity count to determine when to
756 if (_whoami
== NSCD_CHILD
) {
757 (void) mutex_lock(&activity_lock
);
759 (void) mutex_unlock(&activity_lock
);
762 NSCD_SET_RETURN_ARG(phdr
, arg_size
);
763 (void) door_return(argp
, arg_size
, NULL
, 0);
767 getent(char *argp
, size_t arg_size
)
769 char space
[NSCD_LOOKUP_BUFSIZE
];
770 nss_pheader_t
*phdr
= (nss_pheader_t
*)(void *)argp
;
772 NSCD_ALLOC_LOOKUP_BUFFER(argp
, arg_size
, phdr
, space
, sizeof (space
));
774 nss_pgetent(argp
, arg_size
);
776 NSCD_SET_RETURN_ARG(phdr
, arg_size
);
777 (void) door_return(argp
, arg_size
, NULL
, 0);
781 is_db_per_user(void *buf
, char *dblist
)
783 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
788 /* copy db name into a temp buffer */
789 pdbd
= (nss_dbd_t
*)((void *)((char *)buf
+ phdr
->dbd_off
));
790 dbname
= (char *)pdbd
+ pdbd
->o_name
;
791 len
= strlen(dbname
);
792 dbn
= alloca(len
+ 2);
793 (void) memcpy(dbn
, dbname
, len
);
795 /* check if <dbname> + ',' can be found in the dblist string */
798 if (strstr(dblist
, dbn
) != NULL
)
802 * check if <dbname> can be found in the last part
803 * of the dblist string
806 if (strstr(dblist
, dbn
) != NULL
)
813 * Check to see if all conditions are met for processing per-user
814 * requests. Returns 1 if yes, -1 if backend is not configured,
818 need_per_user_door(void *buf
, int whoami
, uid_t uid
, char **dblist
)
820 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
822 NSCD_SET_STATUS_SUCCESS(phdr
);
824 /* if already a per-user nscd, no need to get per-user door */
825 if (whoami
== NSCD_CHILD
)
828 /* forker shouldn't be asked */
829 if (whoami
== NSCD_FORKER
) {
830 NSCD_SET_STATUS(phdr
, NSS_ERROR
, ENOTSUP
);
834 /* if door client is root, no need for a per-user door */
839 * if per-user lookup is not configured, no per-user
842 if (_nscd_is_self_cred_on(0, dblist
) == 0)
846 * if per-user lookup is not configured for the db,
849 if (is_db_per_user(phdr
, *dblist
) == 0)
856 if_selfcred_return_per_user_door(char *argp
, size_t arg_size
,
857 door_desc_t
*dp
, int whoami
)
859 nss_pheader_t
*phdr
= (nss_pheader_t
*)((void *)argp
);
868 * check to see if self-cred is configured and
869 * need to return an alternate PUN door
871 if (per_user_is_on
== 1) {
872 rc
= need_per_user_door(argp
, whoami
,
873 _nscd_get_client_euid(), &dblist
);
879 * self-cred not configured, and no error detected,
880 * return to continue the door call processing
882 if (NSCD_STATUS_IS_OK(phdr
))
886 * configured but error detected,
887 * stop the door call processing
889 (void) door_return(argp
, phdr
->data_off
, NULL
, 0);
892 /* get the alternate PUN door */
893 _nscd_proc_alt_get(argp
, &door
);
894 if (NSCD_GET_STATUS(phdr
) != NSS_ALTRETRY
) {
895 (void) door_return(argp
, phdr
->data_off
, NULL
, 0);
898 /* return the alternate door descriptor */
899 len
= strlen(dblist
) + 1;
900 space
= alloca(arg_size
+ len
);
901 phdr
->data_len
= len
;
902 (void) memcpy(space
, phdr
, arg_size
);
903 (void) strncpy((char *)space
+ arg_size
, dblist
, len
);
905 dp
->d_attributes
= DOOR_DESCRIPTOR
;
906 dp
->d_data
.d_desc
.d_descriptor
= door
;
908 (void) door_return(space
, arg_size
, dp
, 1);
913 switcher(void *cookie
, char *argp
, size_t arg_size
,
914 door_desc_t
*dp
, uint_t n_desc
)
918 nss_pheader_t
*phdr
= (nss_pheader_t
*)((void *)argp
);
923 char *me
= "switcher";
925 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
926 (me
, "switcher ...\n");
928 if (argp
== DOOR_UNREF_DATA
) {
929 (void) printf("Door Slam... exiting\n");
933 if (argp
== NULL
) { /* empty door call */
934 (void) door_return(NULL
, 0, 0, 0); /* return the favor */
938 * need to restart if main nscd and config file(s) changed
940 if (_whoami
== NSCD_MAIN
)
941 _nscd_restart_if_cfgfile_changed();
943 if ((phdr
->nsc_callnumber
& NSCDV2CATMASK
) == NSCD_CALLCAT_APP
) {
945 /* make sure the packed buffer header is good */
946 if (validate_pheader(argp
, arg_size
,
947 phdr
->nsc_callnumber
) == -1)
948 (void) door_return(argp
, arg_size
, NULL
, 0);
950 switch (phdr
->nsc_callnumber
) {
954 /* if a fallback to main nscd, skip per-user setup */
955 if (phdr
->p_status
!= NSS_ALTRETRY
)
956 if_selfcred_return_per_user_door(argp
, arg_size
,
958 lookup(argp
, arg_size
);
964 _nscd_APP_check_cred(argp
, &ent_pid
, "NSCD_SETENT",
965 NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ALERT
);
966 if (NSCD_STATUS_IS_OK(phdr
)) {
967 if_selfcred_return_per_user_door(argp
, arg_size
,
969 nss_psetent(argp
, arg_size
, ent_pid
);
975 getent(argp
, arg_size
);
980 nss_pendent(argp
, arg_size
);
985 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
986 (me
, "door call NSCD_PUT not supported yet\n");
988 NSCD_SET_STATUS(phdr
, NSS_ERROR
, ENOTSUP
);
993 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
994 (me
, "door call NSCD_GETHINTS not supported yet\n");
996 NSCD_SET_STATUS(phdr
, NSS_ERROR
, ENOTSUP
);
1001 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1002 (me
, "Unknown name service door call op %x\n",
1003 phdr
->nsc_callnumber
);
1005 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EINVAL
);
1009 (void) door_return(argp
, arg_size
, NULL
, 0);
1013 callnum
= phdr
->nsc_callnumber
& ~NSCD_WHOAMI
;
1014 if (callnum
== NSCD_IMHERE
||
1015 callnum
== NSCD_PULSE
|| callnum
== NSCD_FORK
)
1016 iam
= phdr
->nsc_callnumber
& NSCD_WHOAMI
;
1018 callnum
= phdr
->nsc_callnumber
;
1020 /* nscd -> nscd v2 calls */
1022 /* make sure the buffer is good */
1023 if (validate_N2Nbuf(argp
, arg_size
, callnum
) == -1)
1024 (void) door_return(argp
, arg_size
, NULL
, 0);
1029 NSCD_SET_STATUS_SUCCESS(phdr
);
1033 _nscd_proc_iamhere(argp
, dp
, n_desc
, iam
);
1037 N2N_check_priv(argp
, "NSCD_PULSE");
1038 if (NSCD_STATUS_IS_OK(phdr
))
1039 _nscd_proc_pulse(argp
, iam
);
1043 N2N_check_priv(argp
, "NSCD_FORK");
1044 if (NSCD_STATUS_IS_OK(phdr
))
1045 _nscd_proc_fork(argp
, iam
);
1049 N2N_check_priv(argp
, "NSCD_KILL");
1050 if (NSCD_STATUS_IS_OK(phdr
))
1055 N2N_check_priv(argp
, "NSCD_REFRESH");
1056 if (NSCD_STATUS_IS_OK(phdr
)) {
1057 if (_nscd_refresh() != NSCD_SUCCESS
)
1059 NSCD_SET_STATUS_SUCCESS(phdr
);
1063 case NSCD_GETPUADMIN
:
1065 if (_nscd_is_self_cred_on(0, NULL
)) {
1066 _nscd_peruser_getadmin(argp
, sizeof (nscd_admin_t
));
1068 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
1069 NSCD_SELF_CRED_NOT_CONFIGURED
);
1075 len
= _nscd_door_getadmin((void *)argp
);
1079 /* size of door buffer not big enough, allocate one */
1080 NSCD_ALLOC_DOORBUF(NSCD_GETADMIN
, len
, uptr
, buflen
);
1082 /* copy packed header */
1083 *(nss_pheader_t
*)uptr
= *(nss_pheader_t
*)((void *)argp
);
1085 /* set new buffer size */
1086 ((nss_pheader_t
*)uptr
)->pbufsiz
= buflen
;
1088 /* try one more time */
1089 (void) _nscd_door_getadmin((void *)uptr
);
1090 (void) door_return(uptr
, buflen
, NULL
, 0);
1094 N2N_check_priv(argp
, "NSCD_SETADMIN");
1095 if (NSCD_STATUS_IS_OK(phdr
))
1096 _nscd_door_setadmin(argp
);
1099 case NSCD_KILLSERVER
:
1100 N2N_check_priv(argp
, "NSCD_KILLSERVER");
1101 if (NSCD_STATUS_IS_OK(phdr
)) {
1102 /* also kill the forker nscd if one is running */
1103 _nscd_kill_forker();
1109 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1110 (me
, "Unknown name service door call op %d\n",
1111 phdr
->nsc_callnumber
);
1113 NSCD_SET_STATUS(phdr
, NSS_ERROR
, EINVAL
);
1115 (void) door_return(argp
, arg_size
, NULL
, 0);
1119 (void) door_return(argp
, arg_size
, NULL
, 0);
1123 _nscd_setup_server(char *execname
, char **argv
)
1128 int bind_failed
= 0;
1132 struct sigaction action
;
1133 char *me
= "_nscd_setup_server";
1135 main_execname
= execname
;
1138 /* Any nscd process is to ignore SIGPIPE */
1139 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) {
1141 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1142 (me
, "signal (SIGPIPE): %s\n", strerror(errnum
));
1146 keep_open_dns_socket();
1149 * the max number of server threads should be fixed now, so
1150 * set flag to indicate that no in-flight change is allowed
1152 max_servers_set
= 1;
1154 (void) thr_keycreate(&lookup_state_key
, NULL
);
1155 (void) sema_init(&common_sema
, frontend_cfg_g
.common_worker_threads
,
1158 /* Establish server thread pool */
1159 (void) door_server_create(server_create
);
1160 if (thr_keycreate(&server_key
, server_destroy
) != 0) {
1162 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1163 (me
, "thr_keycreate (server thread): %s\n",
1169 if ((fd
= door_create(switcher
, NAME_SERVICE_DOOR_COOKIE
,
1170 DOOR_UNREF
| DOOR_NO_CANCEL
)) < 0) {
1172 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1173 (me
, "door_create: %s\n", strerror(errnum
));
1177 /* if not main nscd, no more setup to do */
1178 if (_whoami
!= NSCD_MAIN
)
1181 /* bind to file system */
1182 if (is_system_labeled() && (getzoneid() == GLOBAL_ZONEID
)) {
1183 if (stat(TSOL_NAME_SERVICE_DOOR
, &buf
) < 0) {
1186 /* make sure the door will be readable by all */
1187 old_mask
= umask(0);
1188 if ((newfd
= creat(TSOL_NAME_SERVICE_DOOR
, 0444)) < 0) {
1190 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1191 NSCD_LOG_LEVEL_ERROR
)
1192 (me
, "Cannot create %s: %s\n",
1193 TSOL_NAME_SERVICE_DOOR
,
1197 /* rstore the old file mode creation mask */
1198 (void) umask(old_mask
);
1199 (void) close(newfd
);
1201 if (symlink(TSOL_NAME_SERVICE_DOOR
, NAME_SERVICE_DOOR
) != 0) {
1202 if (errno
!= EEXIST
) {
1204 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1205 NSCD_LOG_LEVEL_ERROR
)
1206 (me
, "Cannot symlink %s: %s\n",
1207 NAME_SERVICE_DOOR
, strerror(errnum
));
1211 } else if (stat(NAME_SERVICE_DOOR
, &buf
) < 0) {
1214 /* make sure the door will be readable by all */
1215 old_mask
= umask(0);
1216 if ((newfd
= creat(NAME_SERVICE_DOOR
, 0444)) < 0) {
1218 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1219 (me
, "Cannot create %s: %s\n", NAME_SERVICE_DOOR
,
1223 /* rstore the old file mode creation mask */
1224 (void) umask(old_mask
);
1225 (void) close(newfd
);
1228 if (bind_failed
== 1) {
1229 (void) door_revoke(fd
);
1233 if (fattach(fd
, NAME_SERVICE_DOOR
) < 0) {
1234 if ((errno
!= EBUSY
) ||
1235 (fdetach(NAME_SERVICE_DOOR
) < 0) ||
1236 (fattach(fd
, NAME_SERVICE_DOOR
) < 0)) {
1238 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1239 (me
, "fattach: %s\n", strerror(errnum
));
1240 (void) door_revoke(fd
);
1246 * kick off routing socket monitor thread
1248 if (thr_create(NULL
, NULL
,
1249 (void *(*)(void *))rts_mon
, 0, 0, NULL
) != 0) {
1251 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1252 (me
, "thr_create (routing socket monitor): %s\n",
1255 (void) door_revoke(fd
);
1260 * set up signal handler for SIGHUP
1262 action
.sa_handler
= dozip
;
1263 action
.sa_flags
= 0;
1264 (void) sigemptyset(&action
.sa_mask
);
1265 (void) sigemptyset(&myset
);
1266 (void) sigaddset(&myset
, SIGHUP
);
1268 if (sigaction(SIGHUP
, &action
, NULL
) < 0) {
1270 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1271 (me
, "sigaction (SIGHUP): %s\n", strerror(errnum
));
1273 (void) door_revoke(fd
);
1281 _nscd_setup_child_server(int did
)
1287 char *me
= "_nscd_setup_child_server";
1289 /* Re-establish our own server thread pool */
1290 (void) door_server_create(server_create
);
1291 if (thr_keycreate(&server_key
, server_destroy
) != 0) {
1293 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
1294 (me
, "thr_keycreate failed: %s", strerror(errnum
));
1299 * Create a new door.
1300 * Keep DOOR_REFUSE_DESC (self-cred nscds don't fork)
1303 if ((fd
= door_create(switcher
, NAME_SERVICE_DOOR_COOKIE
,
1304 DOOR_REFUSE_DESC
|DOOR_UNREF
|DOOR_NO_CANCEL
)) < 0) {
1306 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_DEBUG
)
1307 (me
, "door_create failed: %s", strerror(errnum
));
1312 * kick off routing socket monitor thread
1314 if (thr_create(NULL
, NULL
,
1315 (void *(*)(void *))rts_mon
, 0, 0, NULL
) != 0) {
1317 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1318 (me
, "thr_create (routing socket monitor): %s\n",
1320 (void) door_revoke(fd
);
1325 * start monitoring the states of the name service clients
1327 rc
= _nscd_init_smf_monitor();
1328 if (rc
!= NSCD_SUCCESS
) {
1329 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1330 (me
, "unable to start the SMF monitor (rc = %d)\n", rc
);
1332 (void) door_revoke(fd
);
1340 _nscd_alloc_frontend_cfg()
1342 frontend_cfg
= calloc(NSCD_NUM_DB
, sizeof (nscd_cfg_frontend_t
));
1343 if (frontend_cfg
== NULL
)
1344 return (NSCD_NO_MEMORY
);
1346 return (NSCD_SUCCESS
);
1352 _nscd_cfg_frontend_notify(
1354 struct nscd_cfg_param_desc
*pdesc
,
1355 nscd_cfg_id_t
*nswdb
,
1356 nscd_cfg_flag_t dflag
,
1357 nscd_cfg_error_t
**errorp
,
1363 * At init time, the whole group of config params are received.
1364 * At update time, group or individual parameter value could
1368 if (_nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_INIT
) ||
1369 _nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_GROUP
)) {
1371 * group data is received, copy in the
1374 if (_nscd_cfg_flag_is_set(pdesc
->pflag
, NSCD_CFG_PFLAG_GLOBAL
))
1375 frontend_cfg_g
= *(nscd_cfg_global_frontend_t
*)data
;
1377 frontend_cfg
[nswdb
->index
] =
1378 *(nscd_cfg_frontend_t
*)data
;
1382 * individual paramater is received: copy in the
1385 if (_nscd_cfg_flag_is_set(pdesc
->pflag
, NSCD_CFG_PFLAG_GLOBAL
))
1386 dp
= (char *)&frontend_cfg_g
+ pdesc
->p_offset
;
1388 dp
= (char *)&frontend_cfg
[nswdb
->index
] +
1390 (void) memcpy(dp
, data
, pdesc
->p_size
);
1393 return (NSCD_SUCCESS
);
1398 _nscd_cfg_frontend_verify(
1400 struct nscd_cfg_param_desc
*pdesc
,
1401 nscd_cfg_id_t
*nswdb
,
1402 nscd_cfg_flag_t dflag
,
1403 nscd_cfg_error_t
**errorp
,
1407 char *me
= "_nscd_cfg_frontend_verify";
1410 * if max. number of server threads is set and in effect,
1411 * don't allow changing of the frontend configuration
1413 if (max_servers_set
) {
1414 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_INFO
)
1415 (me
, "changing of the frontend configuration not allowed now");
1417 return (NSCD_CFG_CHANGE_NOT_ALLOWED
);
1420 return (NSCD_SUCCESS
);
1425 _nscd_cfg_frontend_get_stat(
1427 struct nscd_cfg_stat_desc
*sdesc
,
1428 nscd_cfg_id_t
*nswdb
,
1429 nscd_cfg_flag_t
*dflag
,
1430 void (**free_stat
)(void *stat
),
1431 nscd_cfg_error_t
**errorp
)
1433 return (NSCD_SUCCESS
);
1437 _nscd_init_cache_sema(sema_t
*sema
, char *cache_name
)
1442 if (max_servers
== 0)
1443 max_servers
= frontend_cfg_g
.common_worker_threads
+
1444 frontend_cfg_g
.cache_hit_threads
;
1446 for (i
= 0; i
< NSCD_NUM_DB
; i
++) {
1448 dbn
= NSCD_NSW_DB_NAME(i
);
1449 if (strcasecmp(dbn
, cache_name
) == 0) {
1450 j
= frontend_cfg
[i
].worker_thread_per_nsw_db
;
1451 (void) sema_init(sema
, j
, USYNC_THREAD
, 0);
1459 * Monitor the routing socket. Address lists stored in the ipnodes
1460 * cache are sorted based on destination address selection rules,
1461 * so when things change that could affect that sorting (interfaces
1462 * go up or down, flags change, etc.), we clear that cache so the
1463 * list will be re-ordered the next time the hostname is resolved.
1468 int rt_sock
, rdlen
, idx
;
1471 struct rt_msghdr rtm
;
1472 struct sockaddr_storage addrs
[RTA_NUMBITS
];
1474 struct if_msghdr ifm
;
1475 struct ifa_msghdr ifam
;
1477 struct ifa_msghdr
*ifam
= &mbuf
.ifam
;
1478 char *me
= "rts_mon";
1480 rt_sock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
1482 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1483 (me
, "Failed to open routing socket: %s\n", strerror(errno
));
1488 rdlen
= read(rt_sock
, &mbuf
, sizeof (mbuf
));
1490 if (rdlen
== 0 || (errno
!= EINTR
&& errno
!= EAGAIN
)) {
1491 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1492 NSCD_LOG_LEVEL_ERROR
)
1493 (me
, "routing socket read: %s\n",
1499 if (ifam
->ifam_version
!= RTM_VERSION
) {
1500 _NSCD_LOG(NSCD_LOG_FRONT_END
,
1501 NSCD_LOG_LEVEL_ERROR
)
1502 (me
, "rx unknown version (%d) on "
1503 "routing socket.\n",
1504 ifam
->ifam_version
);
1507 switch (ifam
->ifam_type
) {
1510 /* if no ipnodes cache, then nothing to do */
1511 idx
= get_cache_idx("ipnodes");
1512 if (cache_ctx_p
[idx
] == NULL
||
1513 cache_ctx_p
[idx
]->reaper_on
!= nscd_true
)
1515 nsc_invalidate(cache_ctx_p
[idx
], NULL
, NULL
);
1533 _NSCD_LOG(NSCD_LOG_FRONT_END
, NSCD_LOG_LEVEL_ERROR
)
1534 (me
, "rx unknown msg type (%d) on routing socket.\n",
1542 keep_open_dns_socket(void)
1544 _res
.options
|= RES_STAYOPEN
; /* just keep this udp socket open */