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.
37 #include <sys/varargs.h>
40 #include <sys/types.h>
47 #include "nscd_door.h"
48 #include "nscd_config.h"
50 #include "nscd_frontend.h"
51 #include "nscd_selfcred.h"
52 #include "nscd_admin.h"
53 #include "nscd_common.h"
57 static char *execpath
;
58 static char **execargv
;
59 static char *selfcred_dbs
= NULL
;
61 static void *get_smf_prop(const char *var
, char type
, void *def_val
);
63 /* current self-cred configuration data being used */
64 static nscd_cfg_global_selfcred_t nscd_selfcred_cfg_g
;
66 #define _NSCD_PUN_BLOCK 1024
67 static uint8_t pu_nscd_enabled
;
68 static int max_pu_nscd
= _NSCD_PUN_BLOCK
;
69 static int pu_nscd_ttl
;
71 static nscd_rc_t
setup_ldap_backend();
72 static nscd_rc_t
init_user_proc_monitor();
85 typedef struct _child
{
91 child_state_t child_state
;
97 static child_t
**child
= NULL
;
98 static mutex_t child_lock
= DEFAULTMUTEX
;
100 static int open_tail
;
101 static int used_slot
;
105 static pid_t main_uid
= 0;
107 /* nscd id: main, forker, or child */
110 /* forker nscd pid */
111 static pid_t forker_pid
= 0;
112 static pid_t forker_uid
= 0;
115 mutex_t activity_lock
= DEFAULTMUTEX
;
117 static int forking_door
= -1;
118 static mutex_t forking_lock
= DEFAULTMUTEX
;
123 if (child
[s
] == NULL
)
125 free(child
[s
]->mutex
);
126 free(child
[s
]->cond
);
137 (void) mutex_lock(&child_lock
);
139 for (i
= 0; i
< max_pu_nscd
; i
++)
146 (void) mutex_unlock(&child_lock
);
154 char *me
= "init_slot";
156 if (child
[s
] == NULL
) {
157 child
[s
] = (child_t
*)calloc(1, sizeof (child_t
));
158 if (child
[s
] == NULL
)
162 if ((ch
->mutex
= (mutex_t
*)calloc(1,
163 sizeof (mutex_t
))) == NULL
) {
167 (void) mutex_init(ch
->mutex
, USYNC_THREAD
, NULL
);
169 if ((ch
->cond
= (cond_t
*)calloc(1,
170 sizeof (cond_t
))) == NULL
) {
175 (void) cond_init(ch
->cond
, USYNC_THREAD
, NULL
);
177 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
178 (me
, "slot %d allocated\n", s
);
184 ch
->child_state
= CHILD_STATE_NONE
;
190 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
191 (me
, "slot %d initialized\n", s
);
199 (void) mutex_lock(&child_lock
);
201 child
= (child_t
**)calloc(max_pu_nscd
, sizeof (child_t
*));
209 (void) mutex_unlock(&child_lock
);
220 child_t
*ch
, *ret
= NULL
;
221 char *me
= "get_cslot";
223 (void) mutex_lock(&child_lock
);
225 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
226 (me
, "looking for uid %d (slot used = %d)\n", uid
, used_slot
);
228 /* first find the slot with a matching uid */
229 for (i
= 0; i
<= used_slot
; i
++) {
231 if (ch
->child_state
>= CHILD_STATE_UIDKNOWN
&&
232 ch
->child_uid
== uid
) {
234 (void) mutex_unlock(&child_lock
);
236 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
237 (me
, "slot %d found with uid %d\n",
238 ret
->child_slot
, ret
->child_uid
);
244 /* if no need to allocate a new slot, return NULL */
246 (void) mutex_unlock(&child_lock
);
250 /* no open slot ? get a new one */
251 if (open_head
== -1) {
252 /* if no slot available, allocate more */
253 if (used_slot
>= max_pu_nscd
- 1) {
255 int newmax
= max_pu_nscd
+ _NSCD_PUN_BLOCK
;
257 tmp
= (child_t
**)calloc(newmax
, sizeof (child_t
*));
259 (void) mutex_unlock(&child_lock
);
262 (void) memcpy(tmp
, child
, sizeof (child_t
) *
266 max_pu_nscd
= newmax
;
269 if (init_slot(used_slot
) == -1) {
271 (void) mutex_unlock(&child_lock
);
274 ch
= child
[used_slot
];
276 ch
= child
[open_head
];
277 open_head
= ch
->next_open
;
278 /* got last one ? reset tail */
285 ch
->child_state
= CHILD_STATE_UIDKNOWN
;
288 (void) mutex_unlock(&child_lock
);
294 return_cslot_nolock(child_t
*ch
)
297 int slot
= ch
->child_slot
;
299 /* have open slot ? add to and reset tail */
300 if (open_tail
!= -1) {
301 child
[open_tail
]->next_open
= slot
;
304 /* no open slot ? make one */
305 open_head
= open_tail
= slot
;
308 (void) init_slot(ch
->child_slot
);
312 return_cslot(child_t
*ch
)
315 char *me
= "return_cslot";
317 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
318 (me
, "returning slot %d\n", ch
->child_slot
);
320 /* return if the slot has been returned by another thread */
321 if (ch
->child_state
== CHILD_STATE_NONE
)
324 (void) mutex_lock(&child_lock
);
326 /* check one more time */
327 if (ch
->child_state
== CHILD_STATE_NONE
) {
328 (void) mutex_unlock(&child_lock
);
332 return_cslot_nolock(ch
);
334 (void) mutex_unlock(&child_lock
);
342 char *me
= "selfcred_kill";
344 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
345 (me
, "sending kill to door %d\n", fd
);
348 ret
= _nscd_doorcall_fd(fd
, NSCD_KILL
, NULL
, 0,
351 ret
= _nscd_doorcall(NSCD_KILL
);
353 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
354 (me
, "kill request sent to door %d (rc = %d)\n", fd
, ret
);
363 (void) mutex_lock(&forking_lock
);
364 if (forking_door
!= -1)
365 (void) selfcred_kill(forking_door
);
367 (void) mutex_unlock(&forking_lock
);
371 _nscd_kill_all_children()
375 char *me
= "_nscd_kill_all_children";
377 (void) mutex_lock(&child_lock
);
378 for (i
= 0; i
<= used_slot
; i
++) {
379 if (child
[i
] == NULL
)
382 if (child
[i
]->child_state
>= CHILD_STATE_PIDKNOWN
) {
383 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
384 (me
, "killing child process %d (doorfd %d)\n",
385 child
[i
]->child_pid
, child
[i
]->child_door
);
387 ret
= selfcred_kill(child
[i
]->child_door
);
390 (void) kill(child
[i
]->child_pid
, SIGTERM
);
392 if (child
[i
]->child_state
!= CHILD_STATE_NONE
)
393 (void) return_cslot_nolock(child
[i
]);
395 (void) mutex_unlock(&child_lock
);
402 char *me
= "selfcred_pulse";
404 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
405 (me
, "start monitoring door %d\n", fd
);
407 ret
= _nscd_doorcall_fd(fd
, NSCD_PULSE
|(_whoami
& NSCD_WHOAMI
),
408 NULL
, 0, NULL
, 0, NULL
);
410 /* Close door because the other side exited. */
413 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
414 (me
, "door (%d) monitor exited (rc = %d)\n", fd
, ret
);
426 char *me
= "forker_monitor";
428 /* wait until forker exits */
430 (void) selfcred_pulse(forking_door
);
432 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
433 (me
, "forker (pid = %d) exited or crashed, "
434 "killing all child processes\n", fpid
);
436 (void) mutex_lock(&forking_lock
);
439 (void) mutex_unlock(&forking_lock
);
441 /* forker exited/crashed, kill all the child processes */
442 _nscd_kill_all_children();
445 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
446 (me
, "restarting the forker ...\n");
448 switch (fpid
= fork1()) {
450 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
451 (me
, "unable to fork and start the forker ...\n");
453 /* enter the maintenance mode */
454 if ((fmri
= getenv("SMF_FMRI")) != NULL
) {
455 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
456 (me
, "entering maintenance mode ...\n");
457 (void) smf_maintain_instance(fmri
, SMF_TEMPORARY
);
461 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
462 (me
, "execv path = %s\n", execpath
);
464 (void) execv(execpath
, execargv
);
467 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
468 (me
, "new forker's pid is %d\n", fpid
);
480 child_t
*ch
= (child_t
*)arg
;
482 char *me
= "child_monitor";
484 /* wait until child exits */
485 cpid
= ch
->child_pid
;
486 (void) selfcred_pulse(ch
->child_door
);
488 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
489 (me
, "child (pid = %d) exited or crashed ...\n", cpid
);
491 /* return the slot used by the child */
511 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
512 char *me
= "_nscd_proc_iamhere";
515 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
516 (me
, "%d receives iamhere from %d\n", _whoami
, iam
);
518 if (door_ucred(&uc
) != 0) {
520 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
521 (me
, "door_ucred failed: %s\n", strerror(errnum
));
523 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, errnum
,
524 NSCD_DOOR_UCRED_ERROR
);
527 uid
= ucred_geteuid(uc
);
532 if (_whoami
== NSCD_MAIN
|| uid
!= main_uid
) {
534 * I'm main, or uid from door is not correct,
535 * this must be an imposter
537 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
538 (me
, "MAIN IMPOSTER CAUGHT!\n");
541 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
542 NSCD_SELF_CRED_MAIN_IMPOSTER
);
547 if (_whoami
== NSCD_FORKER
|| uid
!= forker_uid
) {
549 * I'm forker, or uid from door is not correct,
550 * this must be an imposter
552 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
553 (me
, "FORKER IMPOSTER CAUGHT!\n");
556 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
557 NSCD_SELF_CRED_FORKER_IMPOSTER
);
561 /* only main needs to know the forker */
562 if (_whoami
!= NSCD_MAIN
) {
564 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
565 NSCD_SELF_CRED_WRONG_NSCD
);
569 if (ucred_getpid(uc
) != forker_pid
) {
570 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
571 (me
, "FORKER IMPOSTER CAUGHT: pid = %d should be %d\n",
572 ucred_getpid(uc
), forker_pid
);
575 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
576 NSCD_SELF_CRED_FORKER_IMPOSTER
);
581 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
582 (me
, "BAD FORKER, NO DOOR!\n");
585 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
586 NSCD_SELF_CRED_NO_DOOR
);
590 if ((dp
->d_attributes
& DOOR_DESCRIPTOR
) &&
591 dp
->d_data
.d_desc
.d_descriptor
> 0 &&
592 dp
->d_data
.d_desc
.d_id
!= 0) {
593 (void) mutex_lock(&forking_lock
);
594 if (forking_door
!= -1)
595 (void) close(forking_door
);
596 forking_door
= dp
->d_data
.d_desc
.d_descriptor
;
597 (void) mutex_unlock(&forking_lock
);
599 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
600 (me
, "forking door is %d\n", forking_door
);
602 NSCD_SET_STATUS_SUCCESS(phdr
);
604 NSCD_SET_STATUS(phdr
, NSS_ALTRETRY
, 0);
608 /* monitor the forker nscd */
609 (void) thr_create(NULL
, 0, forker_monitor
, NULL
,
615 if (_whoami
!= NSCD_MAIN
) {
616 /* child nscd can only talk to the main nscd */
617 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
618 (me
, "CHILD IMPOSTER CAUGHT!\n");
620 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
621 NSCD_SELF_CRED_CHILD_IMPOSTER
);
625 /* get the main nscd assigned slot number */
626 ih
= NSCD_N2N_DOOR_DATA(nscd_imhere_t
, buf
);
628 (void) mutex_lock(&child_lock
);
629 if (cslot
< 0 || cslot
>= max_pu_nscd
)
633 (void) mutex_unlock(&child_lock
);
636 /* Bad slot number */
637 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
638 (me
, "bad slot number %d\n", cslot
);
640 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
641 NSCD_SELF_CRED_INVALID_SLOT_NUMBER
);
645 if (uid
!= ch
->child_uid
) {
646 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
647 (me
, "CHILD IMPOSTER CAUGHT: uid = %d should be %d\n",
650 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
651 NSCD_SELF_CRED_CHILD_IMPOSTER
);
655 if (ch
->child_state
!= CHILD_STATE_UIDKNOWN
&&
656 ch
->child_state
!= CHILD_STATE_FORKSENT
) {
657 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
658 (me
, "invalid slot/child state (%d) for uid %d\n",
659 ch
->child_state
, uid
);
661 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
662 NSCD_SELF_CRED_INVALID_SLOT_STATE
);
666 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
667 (me
, "d_descriptor = %d, d_id = %lld\n",
668 dp
->d_data
.d_desc
.d_descriptor
, dp
->d_data
.d_desc
.d_id
);
670 if ((dp
->d_attributes
& DOOR_DESCRIPTOR
) &&
671 dp
->d_data
.d_desc
.d_descriptor
> 0 &&
672 dp
->d_data
.d_desc
.d_id
!= 0) {
673 (void) mutex_lock(ch
->mutex
);
674 if (ch
->child_door
!= -1)
675 (void) close(ch
->child_door
);
676 ch
->child_door
= dp
->d_data
.d_desc
.d_descriptor
;
677 ch
->child_pid
= ucred_getpid(uc
);
678 ch
->child_state
= CHILD_STATE_PIDKNOWN
;
679 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
680 (me
, "child in slot %d has door %d\n",
681 cslot
, ch
->child_door
);
684 * let waiters know that the child is ready to
687 (void) cond_broadcast(ch
->cond
);
688 (void) mutex_unlock(ch
->mutex
);
690 /* monitor the child nscd */
691 (void) thr_create(NULL
, 0, child_monitor
,
692 ch
, THR_DETACHED
, NULL
);
693 NSCD_SET_STATUS_SUCCESS(phdr
);
696 NSCD_SET_STATUS(phdr
, NSS_ALTRETRY
, 0);
712 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
713 char *me
= "_nscd_proc_pulse";
715 /* only main nscd sends pulse */
716 if (iam
!= NSCD_MAIN
) {
717 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
718 (me
, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam
);
720 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
721 NSCD_SELF_CRED_MAIN_IMPOSTER
);
725 /* forker doesn't return stats, it just pauses */
726 if (_whoami
== NSCD_FORKER
) {
727 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
728 (me
, "forker ready to pause ...\n");
734 /* remember the current activity sequence number */
735 (void) mutex_lock(&activity_lock
);
736 last_active
= activity
;
737 (void) mutex_unlock(&activity_lock
);
741 /* allow per_user_nscd_ttl seconds of inactivity */
742 (void) sleep(pu_nscd_ttl
);
744 (void) mutex_lock(&activity_lock
);
745 if (last_active
== activity
)
748 last_active
= activity
;
749 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
750 (me
, "active, sleep again for %d seconds\n",
753 (void) mutex_unlock(&activity_lock
);
756 /* no activity in the specified seconds, exit and disconnect */
757 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
758 (me
, "no activity in the last %d seconds, exit\n", pu_nscd_ttl
);
773 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
774 char *me
= "_nscd_proc_fork";
778 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
779 (me
, "%d receives fork request from %d\n", _whoami
, iam
);
781 /* only main nscd sends fork requests */
782 if (iam
!= NSCD_MAIN
) {
783 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
784 (me
, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam
);
786 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
787 NSCD_SELF_CRED_MAIN_IMPOSTER
);
791 /* only forker handles fork requests */
792 if (_whoami
!= NSCD_FORKER
) {
793 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
794 (me
, "MAIN IMPOSTER CAUGHT! I AM NOT FORKER!\n");
796 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
797 NSCD_SELF_CRED_WRONG_NSCD
);
801 /* fork a child for the slot assigned by the main nscd */
802 f
= NSCD_N2N_DOOR_DATA(nscd_fork_t
, buf
);
804 /* set the uid/gid as assigned by the main nscd */
808 /* ignore bad slot number */
809 if (slot
< 0 || slot
>= max_pu_nscd
) {
810 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
811 (me
, "bas slot number\n");
813 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
814 NSCD_SELF_CRED_INVALID_SLOT_NUMBER
);
818 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
819 (me
, "before fork1() ...\n");
821 if ((cid
= fork1()) == 0) {
822 _whoami
= NSCD_CHILD
;
825 * remember when this child nscd starts
826 * (replace the forker start time)
828 _nscd_set_start_time(1);
830 /* close all except the log file */
833 for (i
= 0; i
< _logfd
; i
++)
835 closefrom(_logfd
+ 1);
839 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
840 (me
, "child %d\n", getpid());
842 (void) setgid(set2gid
);
843 (void) setuid(set2uid
);
845 /* set up the door and server thread pool */
846 if ((_doorfd
= _nscd_setup_child_server(_doorfd
)) == -1)
849 /* tell libsldap to do self cred only */
850 (void) setup_ldap_backend();
852 /* notify main that child is active */
854 for (ret
= NSS_ALTRETRY
; ret
== NSS_ALTRETRY
; )
855 ret
= _nscd_doorcall_sendfd(_doorfd
,
856 NSCD_IMHERE
| (NSCD_CHILD
& NSCD_WHOAMI
),
857 &ih
, sizeof (ih
), NULL
);
859 NSCD_SET_STATUS_SUCCESS(phdr
);
861 } if (cid
== (pid_t
)-1) {
862 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
863 (me
, "forker unable to fork ...\n");
865 /* enter the maintenance mode */
866 if ((fmri
= getenv("SMF_FMRI")) != NULL
) {
867 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
868 (me
, "entering maintenance mode ...\n");
869 (void) smf_maintain_instance(fmri
, SMF_TEMPORARY
);
874 * start the monitor so as to exit as early as
875 * possible if no other processes are running
876 * with the same PUN uid (i.e., this PUN is
877 * not needed any more)
879 (void) init_user_proc_monitor();
881 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
882 (me
, "child forked: parent pid = %d, child pid = %d\n",
885 NSCD_SET_STATUS_SUCCESS(phdr
);
888 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
889 (me
, "after fork\n");
902 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
903 char *me
= "selfcred_fork";
905 /* if no door fd, do nothing */
907 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
908 NSCD_SELF_CRED_NO_DOOR
);
911 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
912 (me
, "sending fork request to door %d for slot %d "
913 "(uid = %d, gid = %d)\n", doorfd
, cslot
, uid
, gid
);
919 ret
= _nscd_doorcall_fd(doorfd
, NSCD_FORK
|(_whoami
&NSCD_WHOAMI
),
920 &f
, sizeof (f
), NULL
, 0, phdr
);
922 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
923 (me
, "fork request sent to door %d for slot %d (rc = %d)\n",
926 if (NSCD_STATUS_IS_NOT_OK(phdr
)) {
928 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
929 (me
, "fork request sent to door %d for slot %d failed: "
930 "status = %d, errno = %s, nscd status = %d\n", doorfd
,
931 cslot
, NSCD_GET_STATUS(phdr
),
932 strerror(NSCD_GET_ERRNO(phdr
)),
933 NSCD_GET_NSCD_STATUS(phdr
));
946 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
947 char *me
= "_nscd_proc_alt_get";
951 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
952 (me
, "getting an alternate door ...\n");
954 /* make sure there is a door to talk to the forker */
955 if (forking_door
== -1) {
956 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
957 (me
, "no door to talk to the forker\n");
959 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
960 NSCD_SELF_CRED_NO_FORKER
);
964 /* get door client's credential information */
965 if (door_ucred(&uc
) != 0) {
967 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
968 (me
, "door_ucred failed: %s\n", strerror(errnum
));
970 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, errnum
,
971 NSCD_DOOR_UCRED_ERROR
);
975 /* get door client's effective uid and effective gid */
976 set2uid
= ucred_geteuid(uc
);
977 set2gid
= ucred_getegid(uc
);
981 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
982 (me
, "child uid = %d, gid = %d\n", set2uid
, set2gid
);
984 /* is a slot available ? if not, no one to serve */
985 if (child
== NULL
|| (ch
= get_cslot(set2uid
, 0)) == NULL
) {
987 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
988 (me
, "no child slot available (child array = %p, slot = %d)\n",
989 child
, ch
->child_slot
);
991 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
992 NSCD_SELF_CRED_NO_CHILD_SLOT
);
996 /* create the per user nscd if necessary */
997 if (ch
->child_state
!= CHILD_STATE_PIDKNOWN
) {
1000 NSCD_CLEAR_STATUS(&phdr1
);
1002 (void) mutex_lock(ch
->mutex
);
1003 if (ch
->child_state
== CHILD_STATE_UIDKNOWN
) {
1005 /* ask forker to fork a new child */
1006 selfcred_fork(&phdr1
, forking_door
, ch
->child_slot
,
1008 if (NSCD_STATUS_IS_NOT_OK(&phdr1
)) {
1009 (void) mutex_unlock(ch
->mutex
);
1010 NSCD_COPY_STATUS(phdr
, &phdr1
);
1013 ch
->child_state
= CHILD_STATE_FORKSENT
;
1016 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1017 (me
, "waiting for door (slot = %d, uid = %d, gid = %d)\n",
1018 ch
->child_slot
, set2uid
, set2gid
);
1020 /* wait for the per user nscd to become available */
1021 while (ch
->child_state
== CHILD_STATE_FORKSENT
) {
1028 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1029 (me
, "cond_reltimedwait %d seconds\n", ttl
);
1030 err
= cond_reltimedwait(ch
->cond
, ch
->mutex
, &to
);
1032 ch
->child_state
= CHILD_STATE_UIDKNOWN
;
1033 _NSCD_LOG(NSCD_LOG_SELF_CRED
,
1034 NSCD_LOG_LEVEL_DEBUG
)
1035 (me
, "door wait timedout (slot = %d)\n",
1040 (void) mutex_unlock(ch
->mutex
);
1043 if (ch
->child_state
!= CHILD_STATE_PIDKNOWN
) {
1045 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
1046 NSCD_SELF_CRED_INVALID_SLOT_STATE
);
1050 *door
= ch
->child_door
;
1052 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1053 (me
, "returning door %d for slot %d, uid %d, gid = %d\n",
1054 *door
, ch
->child_slot
, set2uid
, set2gid
);
1056 NSCD_SET_STATUS(phdr
, NSS_ALTRETRY
, 0);
1066 int i
= 0, j
, k
= 0, n
= 0;
1068 newargv
= (char **)calloc(c
+ 1, sizeof (char *));
1069 if (newargv
== NULL
)
1072 newargv
[n
] = strdup(inargv
[0]);
1073 if (newargv
[n
++] == NULL
) {
1078 newargv
[n
] = strdup("-F");
1079 if (newargv
[n
++] == NULL
) {
1085 for (i
= 1; i
< argc
; i
++) {
1086 if (strcmp(inargv
[i
], "-f") == 0)
1091 newargv
[n
] = strdup(inargv
[i
]);
1092 if (newargv
[n
] == NULL
) {
1093 for (j
= 0; j
< n
; j
++)
1114 /* if self cred is not configured, do nothing */
1115 if (!_nscd_is_self_cred_on(1, NULL
))
1118 /* save pathname and generate the new argv for the forker */
1119 execpath
= strdup(path
);
1120 execargv
= cpargv(argc
, argv
);
1121 if (execpath
== NULL
|| execargv
== NULL
)
1124 switch (cid
= fork1()) {
1129 /* start the forker nscd */
1130 (void) execv(path
, execargv
);
1135 /* remember process id of the forker */
1138 /* enable child nscd management */
1139 (void) _nscd_init_cslots();
1149 char *me
= "get_ldap_funcs";
1150 static void *handle
= NULL
;
1153 if (name
== NULL
&& handle
!= NULL
) {
1154 (void) dlclose(handle
);
1155 return (NSCD_SUCCESS
);
1157 /* no handle to close, it's OK */
1159 return (NSCD_SUCCESS
);
1161 if (handle
== NULL
) {
1162 handle
= dlopen("libsldap.so.1", RTLD_LAZY
);
1163 if (handle
== NULL
) {
1165 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
1166 (me
, "unable to dlopen libsldap.so.1");
1167 return (NSCD_CFG_DLOPEN_ERROR
);
1171 if ((sym
= dlsym(handle
, name
)) == NULL
) {
1173 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
1174 (me
, "unable to find symbol %s", name
);
1175 return (NSCD_CFG_DLSYM_ERROR
);
1177 (void) memcpy(func_p
, &sym
, sizeof (void *));
1179 return (NSCD_SUCCESS
);
1184 _nscd_is_self_cred_on(int recheck
, char **dblist
)
1186 static int checked
= 0;
1187 static int is_on
= 0;
1188 static int (*ldap_func
)();
1189 char *srcs
= "ldap"; /* only ldap support self cred */
1192 char *ldap_sc_func
= "__ns_ldap_self_gssapi_config";
1193 ns_ldap_self_gssapi_config_t ldap_config
;
1195 if (checked
&& !recheck
) {
1196 if (is_on
&& dblist
!= NULL
)
1197 *dblist
= selfcred_dbs
;
1202 selfcred_dbs
= _nscd_srcs_in_db_nsw_policy(1, &srcs
);
1204 if (selfcred_dbs
== NULL
) {
1211 * also check the ldap backend to see if
1212 * the configuration there is good for
1213 * doing self credentialing
1215 if (ldap_func
== NULL
)
1216 (void) get_ldap_funcs(ldap_sc_func
, (void **)&ldap_func
);
1217 if (ldap_func
!= NULL
) {
1218 if (ldap_func(&ldap_config
) == NS_LDAP_SUCCESS
&&
1219 ldap_config
!= NS_LDAP_SELF_GSSAPI_CONFIG_NONE
)
1223 is_on
= (pu_nscd_enabled
== nscd_true
) && ldap_on
;
1227 if (is_on
&& dblist
!= NULL
)
1228 *dblist
= selfcred_dbs
;
1234 setup_ldap_backend()
1237 static void (*ldap_func
)();
1238 char *ldap_sc_func
= "__ns_ldap_self_gssapi_only_set";
1239 if (ldap_func
== NULL
)
1240 rc
= get_ldap_funcs(ldap_sc_func
, (void **)&ldap_func
);
1241 if (ldap_func
!= NULL
) {
1243 return (NSCD_SUCCESS
);
1250 _nscd_peruser_getadmin(
1254 void *result_mn
= NSCD_N2N_DOOR_DATA(void, buf
);
1258 nss_pheader_t
*phdr
= (nss_pheader_t
*)buf
;
1259 char *me
= "_nscd_peruser_getadmin";
1263 /* get door client's credential information */
1264 if (door_ucred(&uc
) != 0) {
1266 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1267 (me
, "door_ucred failed: %s\n", strerror(errnum
));
1269 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, errnum
,
1270 NSCD_DOOR_UCRED_ERROR
);
1274 /* get door client's effective uid */
1275 uid
= ucred_geteuid(uc
);
1279 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1280 (me
, "per user get admin ... (uid = %d)\n", uid
);
1282 /* is the per-user nscd running ? if not, no one to serve */
1283 ch
= get_cslot(uid
, 1);
1285 NSCD_SET_N2N_STATUS(phdr
, NSS_NSCD_PRIV
, 0,
1286 NSCD_SELF_CRED_NO_CHILD_SLOT
);
1290 ret
= _nscd_doorcall_fd(ch
->child_door
, NSCD_GETADMIN
,
1291 NULL
, sizeof (nscd_admin_t
), result_mn
,
1292 sizeof (nscd_admin_t
), phdr
);
1294 if (ret
== NSS_SUCCESS
) {
1295 phdr
->data_len
= sizeof (nscd_admin_t
);
1306 uint8_t prop_boolean
;
1307 char *me
= "set_selfcred_cfg";
1310 prop_boolean
= *(uint8_t *)data
;
1311 pu_nscd_enabled
= *(uint8_t *)get_smf_prop(
1312 "enable_per_user_lookup", 'b', &prop_boolean
);
1314 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1315 (me
, "self cred config: enabled = %d\n", pu_nscd_enabled
);
1319 prop_int
= *(int *)data
;
1320 pu_nscd_ttl
= *(int64_t *)get_smf_prop(
1321 "per_user_nscd_time_to_live", 'i', &prop_int
);
1323 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1324 (me
, "self cred config: PUN TTL = %d\n", pu_nscd_ttl
);
1330 _nscd_cfg_selfcred_notify(
1332 struct nscd_cfg_param_desc
*pdesc
,
1333 nscd_cfg_id_t
*nswdb
,
1334 nscd_cfg_flag_t dflag
,
1335 nscd_cfg_error_t
**errorp
,
1339 nscd_cfg_global_selfcred_t
*sc_cfg
= &nscd_selfcred_cfg_g
;
1343 * At init time, the whole group of config params are received.
1344 * At update time, group or individual parameter value could
1348 if (_nscd_cfg_flag_is_set(dflag
, NSCD_CFG_DFLAG_GROUP
)) {
1350 *sc_cfg
= *(nscd_cfg_global_selfcred_t
*)data
;
1352 off
= offsetof(nscd_cfg_global_selfcred_t
,
1354 set_selfcred_cfg('e', (char *)data
+ off
);
1356 off
= offsetof(nscd_cfg_global_selfcred_t
,
1358 set_selfcred_cfg('t', (char *)data
+ off
);
1360 return (NSCD_SUCCESS
);
1364 * individual config parameter
1366 off
= offsetof(nscd_cfg_global_selfcred_t
, enable_selfcred
);
1367 if (pdesc
->p_offset
== off
) {
1368 sc_cfg
->enable_selfcred
= *(nscd_bool_t
*)data
;
1369 set_selfcred_cfg('e', data
);
1370 return (NSCD_SUCCESS
);
1373 off
= offsetof(nscd_cfg_global_selfcred_t
, per_user_nscd_ttl
);
1374 if (pdesc
->p_offset
== off
) {
1375 sc_cfg
->per_user_nscd_ttl
= *(int *)data
;
1376 set_selfcred_cfg('t', data
);
1377 return (NSCD_SUCCESS
);
1380 return (NSCD_SUCCESS
);
1385 _nscd_cfg_selfcred_verify(
1387 struct nscd_cfg_param_desc
*pdesc
,
1388 nscd_cfg_id_t
*nswdb
,
1389 nscd_cfg_flag_t dflag
,
1390 nscd_cfg_error_t
**errorp
,
1394 return (NSCD_SUCCESS
);
1399 _nscd_cfg_selfcred_get_stat(
1401 struct nscd_cfg_stat_desc
*sdesc
,
1402 nscd_cfg_id_t
*nswdb
,
1403 nscd_cfg_flag_t
*dflag
,
1404 void (**free_stat
)(void *stat
),
1405 nscd_cfg_error_t
**errorp
)
1407 return (NSCD_SUCCESS
);
1411 check_uid(char *pid_name
)
1413 char pname
[PATH_MAX
];
1414 static pid_t pid
= 0;
1415 static uid_t uid
= 0;
1416 static uid_t euid
= 0;
1417 int pfd
; /* file descriptor for /proc/<pid>/psinfo */
1418 psinfo_t info
; /* process information from /proc */
1426 (void) snprintf(pname
, sizeof (pname
), "/proc/%s/psinfo", pid_name
);
1428 if ((pfd
= open(pname
, O_RDONLY
)) == -1) {
1429 /* Process may have exited */
1434 * Get the info structure for the process and close quickly.
1436 if (read(pfd
, (char *)&info
, sizeof (info
)) < 0) {
1440 if (saverr
== EAGAIN
)
1442 if (saverr
!= ENOENT
)
1447 if (info
.pr_pid
!= pid
&&
1448 info
.pr_uid
== uid
&& info
.pr_euid
== euid
)
1456 * FUNCTION: check_user_process
1460 check_user_process(void *arg
)
1466 char *me
= "check_user_process";
1474 * search the /proc directory and look at each process
1476 if ((dp
= opendir("/proc")) == NULL
) {
1477 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
1478 (me
, "unable to open the /proc directory\n");
1482 /* for each active process */
1483 while (ep
= readdir(dp
)) {
1484 if (ep
->d_name
[0] == '.') /* skip . and .. */
1486 if (check_uid(ep
->d_name
) == 0) {
1493 * if no process running as the PUN uid found, exit
1497 (void) closedir(dp
);
1500 (void) closedir(dp
);
1502 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
1506 init_user_proc_monitor() {
1509 char *me
= "init_user_proc_monitor";
1511 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_DEBUG
)
1512 (me
, "initializing the user process monitor\n");
1515 * start a thread to make sure there is at least a process
1516 * running as the PUN user. If not, terminate this PUN.
1518 if (thr_create(NULL
, 0, check_user_process
,
1519 NULL
, THR_DETACHED
, NULL
) != 0) {
1521 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ERROR
)
1522 (me
, "thr_create: %s\n", strerror(errnum
));
1523 return (NSCD_THREAD_CREATE_ERROR
);
1526 return (NSCD_SUCCESS
);
1530 get_smf_prop(const char *var
, char type
, void *def_val
)
1532 scf_simple_prop_t
*prop
;
1534 char *me
= "get_smf_prop";
1536 prop
= scf_simple_prop_get(NULL
, NULL
, "config", var
);
1540 val
= scf_simple_prop_next_boolean(prop
);
1542 (void) memcpy(def_val
, val
, sizeof (uint8_t));
1546 val
= scf_simple_prop_next_integer(prop
);
1548 (void) memcpy(def_val
, val
, sizeof (int64_t));
1551 scf_simple_prop_free(prop
);
1554 if (prop
== NULL
|| val
== NULL
) {
1559 if (*(uint8_t *)def_val
)
1560 (void) strcpy(vs
, "yes");
1562 (void) strcpy(vs
, "no");
1567 (void) sprintf(vs
, "%lld", *(int64_t *)def_val
);
1571 _NSCD_LOG(NSCD_LOG_SELF_CRED
, NSCD_LOG_LEVEL_ALERT
)
1572 (me
, "no value for config/%s (%s). "
1573 "Using default \"%s\"\n", var
,
1574 scf_strerror(scf_error()), vs
);