4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 * Copyright 2018 Joyent Inc.
38 #include <sys/varargs.h>
41 #include <sys/types.h>
48 #include "nscd_door.h"
49 #include "nscd_config.h"
51 #include "nscd_frontend.h"
52 #include "nscd_selfcred.h"
53 #include "nscd_admin.h"
54 #include "nscd_common.h"
58 static char *execpath
;
59 static char **execargv
;
60 static char *selfcred_dbs
= NULL
;
62 static void *get_smf_prop(const char *var
, char type
, void *def_val
);
64 /* current self-cred configuration data being used */
65 static nscd_cfg_global_selfcred_t nscd_selfcred_cfg_g
;
67 #define _NSCD_PUN_BLOCK 1024
68 static uint8_t pu_nscd_enabled
;
69 static int max_pu_nscd
= _NSCD_PUN_BLOCK
;
70 static int pu_nscd_ttl
;
72 static nscd_rc_t
setup_ldap_backend();
73 static nscd_rc_t
init_user_proc_monitor();
86 typedef struct _child
{
92 child_state_t child_state
;
98 static child_t
**child
= NULL
;
99 static mutex_t child_lock
= DEFAULTMUTEX
;
100 static int open_head
;
101 static int open_tail
;
102 static int used_slot
;
106 static pid_t main_uid
= 0;
108 /* nscd id: main, forker, or child */
111 /* forker nscd pid */
112 static pid_t forker_pid
= 0;
113 static pid_t forker_uid
= 0;
116 mutex_t activity_lock
= DEFAULTMUTEX
;
118 static int forking_door
= -1;
119 static mutex_t forking_lock
= DEFAULTMUTEX
;
124 if (child
[s
] == NULL
)
126 free(child
[s
]->mutex
);
127 free(child
[s
]->cond
);
138 (void) mutex_lock(&child_lock
);
140 for (i
= 0; i
< max_pu_nscd
; i
++)
147 (void) mutex_unlock(&child_lock
);
155 char *me
= "init_slot";
157 if (child
[s
] == NULL
) {
158 child
[s
] = (child_t
*)calloc(1, sizeof (child_t
));
159 if (child
[s
] == NULL
)
163 if ((ch
->mutex
= (mutex_t
*)calloc(1,
164 sizeof (mutex_t
))) == NULL
) {
168 (void) mutex_init(ch
->mutex
, USYNC_THREAD
, NULL
);
170 if ((ch
->cond
= (cond_t
*)calloc(1,
171 sizeof (cond_t
))) == NULL
) {
176 (void) cond_init(ch
->cond
, USYNC_THREAD
, NULL
);
178 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
179 (me
, "slot %d allocated\n", s
);
185 ch
->child_state
= CHILD_STATE_NONE
;
191 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
192 (me
, "slot %d initialized\n", s
);
200 (void) mutex_lock(&child_lock
);
202 child
= (child_t
**)calloc(max_pu_nscd
, sizeof (child_t
*));
210 (void) mutex_unlock(&child_lock
);
221 child_t
*ch
, *ret
= NULL
;
222 char *me
= "get_cslot";
224 (void) mutex_lock(&child_lock
);
226 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
227 (me
, "looking for uid %d (slot used = %d)\n", uid
, used_slot
);
229 /* first find the slot with a matching uid */
230 for (i
= 0; i
<= used_slot
; i
++) {
232 if (ch
->child_state
>= CHILD_STATE_UIDKNOWN
&&
233 ch
->child_uid
== uid
) {
235 (void) mutex_unlock(&child_lock
);
237 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
238 (me
, "slot %d found with uid %d\n",
239 ret
->child_slot
, ret
->child_uid
);
245 /* if no need to allocate a new slot, return NULL */
247 (void) mutex_unlock(&child_lock
);
251 /* no open slot ? get a new one */
252 if (open_head
== -1) {
253 /* if no slot available, allocate more */
254 if (used_slot
>= max_pu_nscd
- 1) {
256 int newmax
= max_pu_nscd
+ _NSCD_PUN_BLOCK
;
258 tmp
= (child_t
**)calloc(newmax
, sizeof (child_t
*));
260 (void) mutex_unlock(&child_lock
);
263 (void) memcpy(tmp
, child
, sizeof (child_t
) *
267 max_pu_nscd
= newmax
;
270 if (init_slot(used_slot
) == -1) {
272 (void) mutex_unlock(&child_lock
);
275 ch
= child
[used_slot
];
277 ch
= child
[open_head
];
278 open_head
= ch
->next_open
;
279 /* got last one ? reset tail */
286 ch
->child_state
= CHILD_STATE_UIDKNOWN
;
289 (void) mutex_unlock(&child_lock
);
295 return_cslot_nolock(child_t
*ch
)
298 int slot
= ch
->child_slot
;
300 /* have open slot ? add to and reset tail */
301 if (open_tail
!= -1) {
302 child
[open_tail
]->next_open
= slot
;
305 /* no open slot ? make one */
306 open_head
= open_tail
= slot
;
309 (void) init_slot(ch
->child_slot
);
313 return_cslot(child_t
*ch
)
316 char *me
= "return_cslot";
318 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
319 (me
, "returning slot %d\n", ch
->child_slot
);
321 /* return if the slot has been returned by another thread */
322 if (ch
->child_state
== CHILD_STATE_NONE
)
325 (void) mutex_lock(&child_lock
);
327 /* check one more time */
328 if (ch
->child_state
== CHILD_STATE_NONE
) {
329 (void) mutex_unlock(&child_lock
);
333 return_cslot_nolock(ch
);
335 (void) mutex_unlock(&child_lock
);
343 char *me
= "selfcred_kill";
345 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
346 (me
, "sending kill to door %d\n", fd
);
349 ret
= _nscd_doorcall_fd(fd
, NSCD_KILL
, NULL
, 0,
352 ret
= _nscd_doorcall(NSCD_KILL
);
354 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
355 (me
, "kill request sent to door %d (rc = %d)\n", fd
, ret
);
364 (void) mutex_lock(&forking_lock
);
365 if (forking_door
!= -1)
366 (void) selfcred_kill(forking_door
);
368 (void) mutex_unlock(&forking_lock
);
372 _nscd_kill_all_children()
376 char *me
= "_nscd_kill_all_children";
378 (void) mutex_lock(&child_lock
);
379 for (i
= 0; i
<= used_slot
; i
++) {
380 if (child
[i
] == NULL
)
383 if (child
[i
]->child_state
>= CHILD_STATE_PIDKNOWN
) {
384 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
385 (me
, "killing child process %d (doorfd %d)\n",
386 child
[i
]->child_pid
, child
[i
]->child_door
);
388 ret
= selfcred_kill(child
[i
]->child_door
);
391 (void) kill(child
[i
]->child_pid
, SIGTERM
);
393 if (child
[i
]->child_state
!= CHILD_STATE_NONE
)
394 (void) return_cslot_nolock(child
[i
]);
396 (void) mutex_unlock(&child_lock
);
403 char *me
= "selfcred_pulse";
405 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
406 (me
, "start monitoring door %d\n", fd
);
408 ret
= _nscd_doorcall_fd(fd
, NSCD_PULSE
|(_whoami
& NSCD_WHOAMI
),
409 NULL
, 0, NULL
, 0, NULL
);
411 /* Close door because the other side exited. */
414 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
415 (me
, "door (%d) monitor exited (rc = %d)\n", fd
, ret
);
427 char *me
= "forker_monitor";
429 (void) thr_setname(thr_self(), me
);
431 /* wait until forker exits */
433 (void) selfcred_pulse(forking_door
);
435 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
436 (me
, "forker (pid = %d) exited or crashed, "
437 "killing all child processes\n", fpid
);
439 (void) mutex_lock(&forking_lock
);
442 (void) mutex_unlock(&forking_lock
);
444 /* forker exited/crashed, kill all the child processes */
445 _nscd_kill_all_children();
448 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
449 (me
, "restarting the forker ...\n");
451 switch (fpid
= fork1()) {
453 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
454 (me
, "unable to fork and start the forker ...\n");
456 /* enter the maintenance mode */
457 if ((fmri
= getenv("SMF_FMRI")) != NULL
) {
458 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
459 (me
, "entering maintenance mode ...\n");
460 (void) smf_maintain_instance(fmri
, SMF_TEMPORARY
);
464 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
465 (me
, "execv path = %s\n", execpath
);
467 (void) execv(execpath
, execargv
);
470 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
471 (me
, "new forker's pid is %d\n", fpid
);
483 child_t
*ch
= (child_t
*)arg
;
485 char *me
= "child_monitor";
487 /* wait until child exits */
488 cpid
= ch
->child_pid
;
489 (void) selfcred_pulse(ch
->child_door
);
491 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
492 (me
, "child (pid = %d) exited or crashed ...\n", cpid
);
494 /* return the slot used by the child */
514 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
515 char *me
= "_nscd_proc_iamhere";
518 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
519 (me
, "%d receives iamhere from %d\n", _whoami
, iam
);
521 if (door_ucred(&uc
) != 0) {
523 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
524 (me
, "door_ucred failed: %s\n", strerror(errnum
));
526 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, errnum
,
527 NSCD_DOOR_UCRED_ERROR
);
530 uid
= ucred_geteuid(uc
);
535 if (_whoami
== NSCD_MAIN
|| uid
!= main_uid
) {
537 * I'm main, or uid from door is not correct,
538 * this must be an imposter
540 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
541 (me
, "MAIN IMPOSTER CAUGHT!\n");
544 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
545 NSCD_SELF_CRED_MAIN_IMPOSTER
);
550 if (_whoami
== NSCD_FORKER
|| uid
!= forker_uid
) {
552 * I'm forker, or uid from door is not correct,
553 * this must be an imposter
555 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
556 (me
, "FORKER IMPOSTER CAUGHT!\n");
559 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
560 NSCD_SELF_CRED_FORKER_IMPOSTER
);
564 /* only main needs to know the forker */
565 if (_whoami
!= NSCD_MAIN
) {
567 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
568 NSCD_SELF_CRED_WRONG_NSCD
);
572 if (ucred_getpid(uc
) != forker_pid
) {
573 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
574 (me
, "FORKER IMPOSTER CAUGHT: pid = %d should be %d\n",
575 ucred_getpid(uc
), forker_pid
);
578 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
579 NSCD_SELF_CRED_FORKER_IMPOSTER
);
584 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
585 (me
, "BAD FORKER, NO DOOR!\n");
588 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
589 NSCD_SELF_CRED_NO_DOOR
);
593 if ((dp
->d_attributes
& DOOR_DESCRIPTOR
) &&
594 dp
->d_data
.d_desc
.d_descriptor
> 0 &&
595 dp
->d_data
.d_desc
.d_id
!= 0) {
596 (void) mutex_lock(&forking_lock
);
597 if (forking_door
!= -1)
598 (void) close(forking_door
);
599 forking_door
= dp
->d_data
.d_desc
.d_descriptor
;
600 (void) mutex_unlock(&forking_lock
);
602 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
603 (me
, "forking door is %d\n", forking_door
);
605 NSCD_SET_STATUS_SUCCESS(phdr
);
607 NSCD_SET_STATUS(phdr
, NSS_ALTRETRY
, 0);
611 /* monitor the forker nscd */
612 (void) thr_create(NULL
, 0, forker_monitor
, NULL
,
618 if (_whoami
!= NSCD_MAIN
) {
619 /* child nscd can only talk to the main nscd */
620 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
621 (me
, "CHILD IMPOSTER CAUGHT!\n");
623 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
624 NSCD_SELF_CRED_CHILD_IMPOSTER
);
628 /* get the main nscd assigned slot number */
629 ih
= NSCD_N2N_DOOR_DATA(nscd_imhere_t
, buf
);
631 (void) mutex_lock(&child_lock
);
632 if (cslot
< 0 || cslot
>= max_pu_nscd
)
636 (void) mutex_unlock(&child_lock
);
639 /* Bad slot number */
640 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
641 (me
, "bad slot number %d\n", cslot
);
643 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
644 NSCD_SELF_CRED_INVALID_SLOT_NUMBER
);
648 if (uid
!= ch
->child_uid
) {
649 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
650 (me
, "CHILD IMPOSTER CAUGHT: uid = %d should be %d\n",
653 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
654 NSCD_SELF_CRED_CHILD_IMPOSTER
);
658 if (ch
->child_state
!= CHILD_STATE_UIDKNOWN
&&
659 ch
->child_state
!= CHILD_STATE_FORKSENT
) {
660 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
661 (me
, "invalid slot/child state (%d) for uid %d\n",
662 ch
->child_state
, uid
);
664 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
665 NSCD_SELF_CRED_INVALID_SLOT_STATE
);
669 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
670 (me
, "d_descriptor = %d, d_id = %lld\n",
671 dp
->d_data
.d_desc
.d_descriptor
, dp
->d_data
.d_desc
.d_id
);
673 if ((dp
->d_attributes
& DOOR_DESCRIPTOR
) &&
674 dp
->d_data
.d_desc
.d_descriptor
> 0 &&
675 dp
->d_data
.d_desc
.d_id
!= 0) {
676 (void) mutex_lock(ch
->mutex
);
677 if (ch
->child_door
!= -1)
678 (void) close(ch
->child_door
);
679 ch
->child_door
= dp
->d_data
.d_desc
.d_descriptor
;
680 ch
->child_pid
= ucred_getpid(uc
);
681 ch
->child_state
= CHILD_STATE_PIDKNOWN
;
682 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
683 (me
, "child in slot %d has door %d\n",
684 cslot
, ch
->child_door
);
687 * let waiters know that the child is ready to
690 (void) cond_broadcast(ch
->cond
);
691 (void) mutex_unlock(ch
->mutex
);
693 /* monitor the child nscd */
694 (void) thr_create(NULL
, 0, child_monitor
,
695 ch
, THR_DETACHED
, NULL
);
696 NSCD_SET_STATUS_SUCCESS(phdr
);
699 NSCD_SET_STATUS(phdr
, NSS_ALTRETRY
, 0);
715 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
716 char *me
= "_nscd_proc_pulse";
718 /* only main nscd sends pulse */
719 if (iam
!= NSCD_MAIN
) {
720 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
721 (me
, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam
);
723 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
724 NSCD_SELF_CRED_MAIN_IMPOSTER
);
728 /* forker doesn't return stats, it just pauses */
729 if (_whoami
== NSCD_FORKER
) {
730 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
731 (me
, "forker ready to pause ...\n");
737 /* remember the current activity sequence number */
738 (void) mutex_lock(&activity_lock
);
739 last_active
= activity
;
740 (void) mutex_unlock(&activity_lock
);
744 /* allow per_user_nscd_ttl seconds of inactivity */
745 (void) sleep(pu_nscd_ttl
);
747 (void) mutex_lock(&activity_lock
);
748 if (last_active
== activity
)
751 last_active
= activity
;
752 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
753 (me
, "active, sleep again for %d seconds\n",
756 (void) mutex_unlock(&activity_lock
);
759 /* no activity in the specified seconds, exit and disconnect */
760 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
761 (me
, "no activity in the last %d seconds, exit\n", pu_nscd_ttl
);
776 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
777 char *me
= "_nscd_proc_fork";
781 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
782 (me
, "%d receives fork request from %d\n", _whoami
, iam
);
784 /* only main nscd sends fork requests */
785 if (iam
!= NSCD_MAIN
) {
786 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
787 (me
, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam
);
789 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
790 NSCD_SELF_CRED_MAIN_IMPOSTER
);
794 /* only forker handles fork requests */
795 if (_whoami
!= NSCD_FORKER
) {
796 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
797 (me
, "MAIN IMPOSTER CAUGHT! I AM NOT FORKER!\n");
799 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
800 NSCD_SELF_CRED_WRONG_NSCD
);
804 /* fork a child for the slot assigned by the main nscd */
805 f
= NSCD_N2N_DOOR_DATA(nscd_fork_t
, buf
);
807 /* set the uid/gid as assigned by the main nscd */
811 /* ignore bad slot number */
812 if (slot
< 0 || slot
>= max_pu_nscd
) {
813 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
814 (me
, "bas slot number\n");
816 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
817 NSCD_SELF_CRED_INVALID_SLOT_NUMBER
);
821 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
822 (me
, "before fork1() ...\n");
824 if ((cid
= fork1()) == 0) {
825 _whoami
= NSCD_CHILD
;
828 * remember when this child nscd starts
829 * (replace the forker start time)
831 _nscd_set_start_time(1);
833 /* close all except the log file */
836 for (i
= 0; i
< _logfd
; i
++)
838 closefrom(_logfd
+ 1);
842 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
843 (me
, "child %d\n", getpid());
845 (void) setgid(set2gid
);
846 (void) setuid(set2uid
);
848 /* set up the door and server thread pool */
849 if ((_doorfd
= _nscd_setup_child_server(_doorfd
)) == -1)
852 /* tell libsldap to do self cred only */
853 (void) setup_ldap_backend();
855 /* notify main that child is active */
857 for (ret
= NSS_ALTRETRY
; ret
== NSS_ALTRETRY
; )
858 ret
= _nscd_doorcall_sendfd(_doorfd
,
859 NSCD_IMHERE
| (NSCD_CHILD
& NSCD_WHOAMI
),
860 &ih
, sizeof (ih
), NULL
);
862 NSCD_SET_STATUS_SUCCESS(phdr
);
864 } if (cid
== (pid_t
)-1) {
865 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
866 (me
, "forker unable to fork ...\n");
868 /* enter the maintenance mode */
869 if ((fmri
= getenv("SMF_FMRI")) != NULL
) {
870 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
871 (me
, "entering maintenance mode ...\n");
872 (void) smf_maintain_instance(fmri
, SMF_TEMPORARY
);
877 * start the monitor so as to exit as early as
878 * possible if no other processes are running
879 * with the same PUN uid (i.e., this PUN is
880 * not needed any more)
882 (void) init_user_proc_monitor();
884 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
885 (me
, "child forked: parent pid = %d, child pid = %d\n",
888 NSCD_SET_STATUS_SUCCESS(phdr
);
891 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
892 (me
, "after fork\n");
905 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
906 char *me
= "selfcred_fork";
908 /* if no door fd, do nothing */
910 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
911 NSCD_SELF_CRED_NO_DOOR
);
914 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
915 (me
, "sending fork request to door %d for slot %d "
916 "(uid = %d, gid = %d)\n", doorfd
, cslot
, uid
, gid
);
922 ret
= _nscd_doorcall_fd(doorfd
, NSCD_FORK
|(_whoami
&NSCD_WHOAMI
),
923 &f
, sizeof (f
), NULL
, 0, phdr
);
925 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
926 (me
, "fork request sent to door %d for slot %d (rc = %d)\n",
929 if (NSCD_STATUS_IS_NOT_OK(phdr
)) {
931 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
932 (me
, "fork request sent to door %d for slot %d failed: "
933 "status = %d, errno = %s, nscd status = %d\n", doorfd
,
934 cslot
, NSCD_GET_STATUS(phdr
),
935 strerror(NSCD_GET_ERRNO(phdr
)),
936 NSCD_GET_NSCD_STATUS(phdr
));
949 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
950 char *me
= "_nscd_proc_alt_get";
954 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
955 (me
, "getting an alternate door ...\n");
957 /* make sure there is a door to talk to the forker */
958 if (forking_door
== -1) {
959 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
960 (me
, "no door to talk to the forker\n");
962 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
963 NSCD_SELF_CRED_NO_FORKER
);
967 /* get door client's credential information */
968 if (door_ucred(&uc
) != 0) {
970 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
971 (me
, "door_ucred failed: %s\n", strerror(errnum
));
973 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, errnum
,
974 NSCD_DOOR_UCRED_ERROR
);
978 /* get door client's effective uid and effective gid */
979 set2uid
= ucred_geteuid(uc
);
980 set2gid
= ucred_getegid(uc
);
984 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
985 (me
, "child uid = %d, gid = %d\n", set2uid
, set2gid
);
987 /* is a slot available ? if not, no one to serve */
988 if (child
== NULL
|| (ch
= get_cslot(set2uid
, 0)) == NULL
) {
990 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
991 (me
, "no child slot available (child array = %p, slot = %d)\n",
992 child
, ch
->child_slot
);
994 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
995 NSCD_SELF_CRED_NO_CHILD_SLOT
);
999 /* create the per user nscd if necessary */
1000 if (ch
->child_state
!= CHILD_STATE_PIDKNOWN
) {
1002 nss_pheader_t phdr1
;
1003 NSCD_CLEAR_STATUS(&phdr1
);
1005 (void) mutex_lock(ch
->mutex
);
1006 if (ch
->child_state
== CHILD_STATE_UIDKNOWN
) {
1008 /* ask forker to fork a new child */
1009 selfcred_fork(&phdr1
, forking_door
, ch
->child_slot
,
1011 if (NSCD_STATUS_IS_NOT_OK(&phdr1
)) {
1012 (void) mutex_unlock(ch
->mutex
);
1013 NSCD_COPY_STATUS(phdr
, &phdr1
);
1016 ch
->child_state
= CHILD_STATE_FORKSENT
;
1019 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1020 (me
, "waiting for door (slot = %d, uid = %d, gid = %d)\n",
1021 ch
->child_slot
, set2uid
, set2gid
);
1023 /* wait for the per user nscd to become available */
1024 while (ch
->child_state
== CHILD_STATE_FORKSENT
) {
1031 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1032 (me
, "cond_reltimedwait %d seconds\n", ttl
);
1033 err
= cond_reltimedwait(ch
->cond
, ch
->mutex
, &to
);
1035 ch
->child_state
= CHILD_STATE_UIDKNOWN
;
1036 _NSCD_LOG(NSCD_LOG_SELF_CRED
,
1037 NSCD_LOG_LEVEL_DEBUG
)
1038 (me
, "door wait timedout (slot = %d)\n",
1043 (void) mutex_unlock(ch
->mutex
);
1046 if (ch
->child_state
!= CHILD_STATE_PIDKNOWN
) {
1048 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
1049 NSCD_SELF_CRED_INVALID_SLOT_STATE
);
1053 *door
= ch
->child_door
;
1055 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1056 (me
, "returning door %d for slot %d, uid %d, gid = %d\n",
1057 *door
, ch
->child_slot
, set2uid
, set2gid
);
1059 NSCD_SET_STATUS(phdr
, NSS_ALTRETRY
, 0);
1069 int i
= 0, j
, k
= 0, n
= 0;
1071 newargv
= (char **)calloc(c
+ 1, sizeof (char *));
1072 if (newargv
== NULL
)
1075 newargv
[n
] = strdup(inargv
[0]);
1076 if (newargv
[n
++] == NULL
) {
1081 newargv
[n
] = strdup("-F");
1082 if (newargv
[n
++] == NULL
) {
1088 for (i
= 1; i
< argc
; i
++) {
1089 if (strcmp(inargv
[i
], "-f") == 0)
1094 newargv
[n
] = strdup(inargv
[i
]);
1095 if (newargv
[n
] == NULL
) {
1096 for (j
= 0; j
< n
; j
++)
1117 /* if self cred is not configured, do nothing */
1118 if (!_nscd_is_self_cred_on(1, NULL
))
1121 /* save pathname and generate the new argv for the forker */
1122 execpath
= strdup(path
);
1123 execargv
= cpargv(argc
, argv
);
1124 if (execpath
== NULL
|| execargv
== NULL
)
1127 switch (cid
= fork1()) {
1132 /* start the forker nscd */
1133 (void) execv(path
, execargv
);
1138 /* remember process id of the forker */
1141 /* enable child nscd management */
1142 (void) _nscd_init_cslots();
1152 char *me
= "get_ldap_funcs";
1153 static void *handle
= NULL
;
1156 if (name
== NULL
&& handle
!= NULL
) {
1157 (void) dlclose(handle
);
1158 return (NSCD_SUCCESS
);
1160 /* no handle to close, it's OK */
1162 return (NSCD_SUCCESS
);
1164 if (handle
== NULL
) {
1165 handle
= dlopen("libsldap.so.1", RTLD_LAZY
);
1166 if (handle
== NULL
) {
1168 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
1169 (me
, "unable to dlopen libsldap.so.1");
1170 return (NSCD_CFG_DLOPEN_ERROR
);
1174 if ((sym
= dlsym(handle
, name
)) == NULL
) {
1176 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
1177 (me
, "unable to find symbol %s", name
);
1178 return (NSCD_CFG_DLSYM_ERROR
);
1180 (void) memcpy(func_p
, &sym
, sizeof (void *));
1182 return (NSCD_SUCCESS
);
1187 _nscd_is_self_cred_on(int recheck
, char **dblist
)
1189 static int checked
= 0;
1190 static int is_on
= 0;
1191 static int (*ldap_func
)();
1192 char *srcs
= "ldap"; /* only ldap support self cred */
1195 char *ldap_sc_func
= "__ns_ldap_self_gssapi_config";
1196 ns_ldap_self_gssapi_config_t ldap_config
;
1198 if (checked
&& !recheck
) {
1199 if (is_on
&& dblist
!= NULL
)
1200 *dblist
= selfcred_dbs
;
1204 if (selfcred_dbs
!= NULL
)
1206 selfcred_dbs
= _nscd_srcs_in_db_nsw_policy(1, &srcs
);
1208 if (selfcred_dbs
== NULL
) {
1215 * also check the ldap backend to see if
1216 * the configuration there is good for
1217 * doing self credentialing
1219 if (ldap_func
== NULL
)
1220 (void) get_ldap_funcs(ldap_sc_func
, (void **)&ldap_func
);
1221 if (ldap_func
!= NULL
) {
1222 if (ldap_func(&ldap_config
) == NS_LDAP_SUCCESS
&&
1223 ldap_config
!= NS_LDAP_SELF_GSSAPI_CONFIG_NONE
)
1227 is_on
= (pu_nscd_enabled
== nscd_true
) && ldap_on
;
1231 if (is_on
&& dblist
!= NULL
)
1232 *dblist
= selfcred_dbs
;
1238 setup_ldap_backend()
1241 static void (*ldap_func
)();
1242 char *ldap_sc_func
= "__ns_ldap_self_gssapi_only_set";
1243 if (ldap_func
== NULL
)
1244 rc
= get_ldap_funcs(ldap_sc_func
, (void **)&ldap_func
);
1245 if (ldap_func
!= NULL
) {
1247 return (NSCD_SUCCESS
);
1254 _nscd_peruser_getadmin(
1258 void *result_mn
= NSCD_N2N_DOOR_DATA(void, buf
);
1262 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
1263 char *me
= "_nscd_peruser_getadmin";
1267 /* get door client's credential information */
1268 if (door_ucred(&uc
) != 0) {
1270 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1271 (me
, "door_ucred failed: %s\n", strerror(errnum
));
1273 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, errnum
,
1274 NSCD_DOOR_UCRED_ERROR
);
1278 /* get door client's effective uid */
1279 uid
= ucred_geteuid(uc
);
1283 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1284 (me
, "per user get admin ... (uid = %d)\n", uid
);
1286 /* is the per-user nscd running ? if not, no one to serve */
1287 ch
= get_cslot(uid
, 1);
1289 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
1290 NSCD_SELF_CRED_NO_CHILD_SLOT
);
1294 ret
= _nscd_doorcall_fd(ch
->child_door
, NSCD_GETADMIN
,
1295 NULL
, sizeof (nscd_admin_t
), result_mn
,
1296 sizeof (nscd_admin_t
), phdr
);
1298 if (ret
== NSS_SUCCESS
) {
1299 phdr
->data_len
= sizeof (nscd_admin_t
);
1310 uint8_t prop_boolean
;
1311 char *me
= "set_selfcred_cfg";
1314 prop_boolean
= *(uint8_t *)data
;
1315 pu_nscd_enabled
= *(uint8_t *)get_smf_prop(
1316 "enable_per_user_lookup", 'b', &prop_boolean
);
1318 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1319 (me
, "self cred config: enabled = %d\n", pu_nscd_enabled
);
1323 prop_int
= *(int *)data
;
1324 pu_nscd_ttl
= *(int64_t *)get_smf_prop(
1325 "per_user_nscd_time_to_live", 'i', &prop_int
);
1327 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1328 (me
, "self cred config: PUN TTL = %d\n", pu_nscd_ttl
);
1334 _nscd_cfg_selfcred_notify(
1336 struct nscd_cfg_param_desc
*pdesc
,
1337 nscd_cfg_id_t
*nswdb
,
1338 nscd_cfg_flag_t dflag
,
1339 nscd_cfg_error_t
**errorp
,
1343 nscd_cfg_global_selfcred_t
*sc_cfg
= &nscd_selfcred_cfg_g
;
1347 * At init time, the whole group of config params are received.
1348 * At update time, group or individual parameter value could
1352 if (_nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_GROUP
)) {
1354 *sc_cfg
= *(nscd_cfg_global_selfcred_t
*)data
;
1356 off
= offsetof(nscd_cfg_global_selfcred_t
,
1358 set_selfcred_cfg('e', (char *)data
+ off
);
1360 off
= offsetof(nscd_cfg_global_selfcred_t
,
1362 set_selfcred_cfg('t', (char *)data
+ off
);
1364 return (NSCD_SUCCESS
);
1368 * individual config parameter
1370 off
= offsetof(nscd_cfg_global_selfcred_t
, enable_selfcred
);
1371 if (pdesc
->p_offset
== off
) {
1372 sc_cfg
->enable_selfcred
= *(nscd_bool_t
*)data
;
1373 set_selfcred_cfg('e', data
);
1374 return (NSCD_SUCCESS
);
1377 off
= offsetof(nscd_cfg_global_selfcred_t
, per_user_nscd_ttl
);
1378 if (pdesc
->p_offset
== off
) {
1379 sc_cfg
->per_user_nscd_ttl
= *(int *)data
;
1380 set_selfcred_cfg('t', data
);
1381 return (NSCD_SUCCESS
);
1384 return (NSCD_SUCCESS
);
1389 _nscd_cfg_selfcred_verify(
1391 struct nscd_cfg_param_desc
*pdesc
,
1392 nscd_cfg_id_t
*nswdb
,
1393 nscd_cfg_flag_t dflag
,
1394 nscd_cfg_error_t
**errorp
,
1398 return (NSCD_SUCCESS
);
1403 _nscd_cfg_selfcred_get_stat(
1405 struct nscd_cfg_stat_desc
*sdesc
,
1406 nscd_cfg_id_t
*nswdb
,
1407 nscd_cfg_flag_t
*dflag
,
1408 void (**free_stat
)(void *stat
),
1409 nscd_cfg_error_t
**errorp
)
1411 return (NSCD_SUCCESS
);
1415 check_uid(char *pid_name
)
1417 char pname
[PATH_MAX
];
1418 static pid_t pid
= 0;
1419 static uid_t uid
= 0;
1420 static uid_t euid
= 0;
1421 int pfd
; /* file descriptor for /proc/<pid>/psinfo */
1422 psinfo_t info
; /* process information from /proc */
1430 (void) snprintf(pname
, sizeof (pname
), "/proc/%s/psinfo", pid_name
);
1432 if ((pfd
= open(pname
, O_RDONLY
)) == -1) {
1433 /* Process may have exited */
1438 * Get the info structure for the process and close quickly.
1440 if (read(pfd
, (char *)&info
, sizeof (info
)) < 0) {
1444 if (saverr
== EAGAIN
)
1446 if (saverr
!= ENOENT
)
1451 if (info
.pr_pid
!= pid
&&
1452 info
.pr_uid
== uid
&& info
.pr_euid
== euid
)
1460 * FUNCTION: check_user_process
1464 check_user_process(void *arg
)
1470 char *me
= "check_user_process";
1472 (void) thr_setname(thr_self(), me
);
1480 * search the /proc directory and look at each process
1482 if ((dp
= opendir("/proc")) == NULL
) {
1483 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
1484 (me
, "unable to open the /proc directory\n");
1488 /* for each active process */
1489 while (ep
= readdir(dp
)) {
1490 if (ep
->d_name
[0] == '.') /* skip . and .. */
1492 if (check_uid(ep
->d_name
) == 0) {
1499 * if no process running as the PUN uid found, exit
1503 (void) closedir(dp
);
1506 (void) closedir(dp
);
1508 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
1512 init_user_proc_monitor() {
1515 char *me
= "init_user_proc_monitor";
1517 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1518 (me
, "initializing the user process monitor\n");
1521 * start a thread to make sure there is at least a process
1522 * running as the PUN user. If not, terminate this PUN.
1524 if (thr_create(NULL
, NULL
, check_user_process
,
1525 NULL
, THR_DETACHED
, NULL
) != 0) {
1527 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
1528 (me
, "thr_create: %s\n", strerror(errnum
));
1529 return (NSCD_THREAD_CREATE_ERROR
);
1532 return (NSCD_SUCCESS
);
1536 get_smf_prop(const char *var
, char type
, void *def_val
)
1538 scf_simple_prop_t
*prop
;
1540 char *me
= "get_smf_prop";
1542 prop
= scf_simple_prop_get(NULL
, NULL
, "config", var
);
1546 val
= scf_simple_prop_next_boolean(prop
);
1548 (void) memcpy(def_val
, val
, sizeof (uint8_t));
1552 val
= scf_simple_prop_next_integer(prop
);
1554 (void) memcpy(def_val
, val
, sizeof (int64_t));
1557 scf_simple_prop_free(prop
);
1560 if (prop
== NULL
|| val
== NULL
) {
1565 if (*(uint8_t *)def_val
)
1566 (void) strcpy(vs
, "yes");
1568 (void) strcpy(vs
, "no");
1573 (void) sprintf(vs
, "%lld", *(int64_t *)def_val
);
1577 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ALERT
)
1578 (me
, "no value for config/%s (%s). "
1579 "Using default \"%s\"\n", var
,
1580 scf_strerror(scf_error()), vs
);