1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Milan Jurik. All rights reserved.
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <synch.h>
30 #include <thread.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <dlfcn.h>
34 #include <door.h>
35 #include <libscf.h>
36 #include <ucred.h>
37 #include <sys/varargs.h>
38 #include <signal.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <dirent.h>
42 #include <sys/proc.h>
43 #include <procfs.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <libscf.h>
47 #include "nscd_door.h"
48 #include "nscd_config.h"
49 #include "nscd_log.h"
50 #include "nscd_frontend.h"
51 #include "nscd_selfcred.h"
52 #include "nscd_admin.h"
53 #include "nscd_common.h"
54 #include "ns_sldap.h"
55
56 extern int _logfd;
57 static char *execpath;
58 static char **execargv;
59 static char *selfcred_dbs = NULL;
60
61 static void *get_smf_prop(const char *var, char type, void *def_val);
62
63 /* current self-cred configuration data being used */
64 static nscd_cfg_global_selfcred_t nscd_selfcred_cfg_g;
65
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;
70
71 static nscd_rc_t setup_ldap_backend();
72 static nscd_rc_t init_user_proc_monitor();
73
74 /*
75 * clild state
76 */
77 typedef enum {
78 CHILD_STATE_NONE = 0,
79 CHILD_STATE_UIDKNOWN,
80 CHILD_STATE_FORKSENT,
81 CHILD_STATE_PIDKNOWN
82 } child_state_t;
83
84
85 typedef struct _child {
86 int child_slot;
87 int child_door;
88 pid_t child_pid;
89 uid_t child_uid;
90 gid_t child_gid;
91 child_state_t child_state;
92 int next_open;
93 mutex_t *mutex;
94 cond_t *cond;
95 } child_t;
96
97 static child_t **child = NULL;
98 static mutex_t child_lock = DEFAULTMUTEX;
99 static int open_head;
100 static int open_tail;
101 static int used_slot;
102
103 /* nscd door id */
104 extern int _doorfd;
105 static pid_t main_uid = 0;
106
107 /* nscd id: main, forker, or child */
108 extern int _whoami;
109
110 /* forker nscd pid */
111 static pid_t forker_pid = 0;
112 static pid_t forker_uid = 0;
113
114 long activity = 0;
115 mutex_t activity_lock = DEFAULTMUTEX;
116
117 static int forking_door = -1;
118 static mutex_t forking_lock = DEFAULTMUTEX;
119
120 static void
free_slot(int s)121 free_slot(int s)
122 {
123 if (child[s] == NULL)
124 return;
125 free(child[s]->mutex);
126 free(child[s]->cond);
127 free(child[s]);
128 child[s] = NULL;
129 }
130
131 void
_nscd_free_cslots()132 _nscd_free_cslots()
133 {
134
135 int i;
136
137 (void) mutex_lock(&child_lock);
138
139 for (i = 0; i < max_pu_nscd; i++)
140 free_slot(i);
141
142 open_head = -1;
143 open_tail = -1;
144 used_slot = -1;
145
146 (void) mutex_unlock(&child_lock);
147
148 }
149
150 static int
init_slot(int s)151 init_slot(int s)
152 {
153 child_t *ch;
154 char *me = "init_slot";
155
156 if (child[s] == NULL) {
157 child[s] = (child_t *)calloc(1, sizeof (child_t));
158 if (child[s] == NULL)
159 return (-1);
160 ch = child[s];
161
162 if ((ch->mutex = (mutex_t *)calloc(1,
163 sizeof (mutex_t))) == NULL) {
164 free(ch);
165 return (-1);
166 }
167 (void) mutex_init(ch->mutex, USYNC_THREAD, NULL);
168
169 if ((ch->cond = (cond_t *)calloc(1,
170 sizeof (cond_t))) == NULL) {
171 free(ch->mutex);
172 free(ch);
173 return (-1);
174 }
175 (void) cond_init(ch->cond, USYNC_THREAD, NULL);
176
177 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
178 (me, "slot %d allocated\n", s);
179 } else
180 ch = child[s];
181
182 ch->child_slot = s;
183 ch->child_door = 0;
184 ch->child_state = CHILD_STATE_NONE;
185 ch->child_pid = 0;
186 ch->child_uid = 0;
187 ch->child_gid = 0;
188 ch->next_open = -1;
189
190 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
191 (me, "slot %d initialized\n", s);
192
193 return (0);
194 }
195
196 static int
_nscd_init_cslots()197 _nscd_init_cslots()
198 {
199 (void) mutex_lock(&child_lock);
200
201 child = (child_t **)calloc(max_pu_nscd, sizeof (child_t *));
202 if (child == NULL)
203 return (-1);
204
205 open_head = -1;
206 open_tail = -1;
207 used_slot = -1;
208
209 (void) mutex_unlock(&child_lock);
210
211 return (0);
212 }
213
214 static child_t *
get_cslot(uid_t uid,int no_alloc)215 get_cslot(
216 uid_t uid,
217 int no_alloc)
218 {
219 int i;
220 child_t *ch, *ret = NULL;
221 char *me = "get_cslot";
222
223 (void) mutex_lock(&child_lock);
224
225 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
226 (me, "looking for uid %d (slot used = %d)\n", uid, used_slot);
227
228 /* first find the slot with a matching uid */
229 for (i = 0; i <= used_slot; i++) {
230 ch = child[i];
231 if (ch->child_state >= CHILD_STATE_UIDKNOWN &&
232 ch->child_uid == uid) {
233 ret = ch;
234 (void) mutex_unlock(&child_lock);
235
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);
239
240 return (ret);
241 }
242 }
243
244 /* if no need to allocate a new slot, return NULL */
245 if (no_alloc == 1) {
246 (void) mutex_unlock(&child_lock);
247 return (ret);
248 }
249
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) {
254 child_t **tmp;
255 int newmax = max_pu_nscd + _NSCD_PUN_BLOCK;
256
257 tmp = (child_t **)calloc(newmax, sizeof (child_t *));
258 if (tmp == NULL) {
259 (void) mutex_unlock(&child_lock);
260 return (ret);
261 }
262 (void) memcpy(tmp, child, sizeof (child_t) *
263 max_pu_nscd);
264 free(child);
265 child = tmp;
266 max_pu_nscd = newmax;
267 }
268 used_slot++;
269 if (init_slot(used_slot) == -1) {
270 used_slot--;
271 (void) mutex_unlock(&child_lock);
272 return (ret);
273 }
274 ch = child[used_slot];
275 } else {
276 ch = child[open_head];
277 open_head = ch->next_open;
278 /* got last one ? reset tail */
279 if (open_head == -1)
280 open_tail = -1;
281 ch->next_open = -1;
282 }
283
284 ch->child_uid = uid;
285 ch->child_state = CHILD_STATE_UIDKNOWN;
286 ret = ch;
287
288 (void) mutex_unlock(&child_lock);
289
290 return (ret);
291 }
292
293 static void
return_cslot_nolock(child_t * ch)294 return_cslot_nolock(child_t *ch)
295 {
296
297 int slot = ch->child_slot;
298
299 /* have open slot ? add to and reset tail */
300 if (open_tail != -1) {
301 child[open_tail]->next_open = slot;
302 open_tail = slot;
303 } else {
304 /* no open slot ? make one */
305 open_head = open_tail = slot;
306 }
307
308 (void) init_slot(ch->child_slot);
309 }
310
311 static void
return_cslot(child_t * ch)312 return_cslot(child_t *ch)
313 {
314
315 char *me = "return_cslot";
316
317 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
318 (me, "returning slot %d\n", ch->child_slot);
319
320 /* return if the slot has been returned by another thread */
321 if (ch->child_state == CHILD_STATE_NONE)
322 return;
323
324 (void) mutex_lock(&child_lock);
325
326 /* check one more time */
327 if (ch->child_state == CHILD_STATE_NONE) {
328 (void) mutex_unlock(&child_lock);
329 return;
330 }
331
332 return_cslot_nolock(ch);
333
334 (void) mutex_unlock(&child_lock);
335 }
336
337 static int
selfcred_kill(int fd)338 selfcred_kill(
339 int fd)
340 {
341 int ret;
342 char *me = "selfcred_kill";
343
344 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
345 (me, "sending kill to door %d\n", fd);
346
347 if (fd != -1)
348 ret = _nscd_doorcall_fd(fd, NSCD_KILL, NULL, 0,
349 NULL, 0, NULL);
350 else
351 ret = _nscd_doorcall(NSCD_KILL);
352
353 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
354 (me, "kill request sent to door %d (rc = %d)\n", fd, ret);
355
356 return (ret);
357 }
358
359
360 void
_nscd_kill_forker()361 _nscd_kill_forker()
362 {
363 (void) mutex_lock(&forking_lock);
364 if (forking_door != -1)
365 (void) selfcred_kill(forking_door);
366 forking_door = -1;
367 (void) mutex_unlock(&forking_lock);
368 }
369
370 void
_nscd_kill_all_children()371 _nscd_kill_all_children()
372 {
373 int i;
374 int ret;
375 char *me = "_nscd_kill_all_children";
376
377 (void) mutex_lock(&child_lock);
378 for (i = 0; i <= used_slot; i++) {
379 if (child[i] == NULL)
380 continue;
381
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);
386
387 ret = selfcred_kill(child[i]->child_door);
388
389 if (ret != -1)
390 (void) kill(child[i]->child_pid, SIGTERM);
391 }
392 if (child[i]->child_state != CHILD_STATE_NONE)
393 (void) return_cslot_nolock(child[i]);
394 }
395 (void) mutex_unlock(&child_lock);
396 }
397 static int
selfcred_pulse(int fd)398 selfcred_pulse(
399 int fd)
400 {
401 int ret;
402 char *me = "selfcred_pulse";
403
404 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
405 (me, "start monitoring door %d\n", fd);
406
407 ret = _nscd_doorcall_fd(fd, NSCD_PULSE |(_whoami & NSCD_WHOAMI),
408 NULL, 0, NULL, 0, NULL);
409
410 /* Close door because the other side exited. */
411 (void) close(fd);
412
413 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
414 (me, "door (%d) monitor exited (rc = %d)\n", fd, ret);
415
416 return (ret);
417 }
418
419 /*ARGSUSED*/
420 static void *
forker_monitor(void * arg)421 forker_monitor(
422 void *arg)
423 {
424 pid_t fpid;
425 char *fmri;
426 char *me = "forker_monitor";
427
428 /* wait until forker exits */
429 fpid = forker_pid;
430 (void) selfcred_pulse(forking_door);
431
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);
435
436 (void) mutex_lock(&forking_lock);
437 forking_door = -1;
438 forker_pid = -1;
439 (void) mutex_unlock(&forking_lock);
440
441 /* forker exited/crashed, kill all the child processes */
442 _nscd_kill_all_children();
443
444 /* restart forker */
445 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
446 (me, "restarting the forker ...\n");
447
448 switch (fpid = fork1()) {
449 case (pid_t)-1:
450 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
451 (me, "unable to fork and start the forker ...\n");
452
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);
458 }
459 return ((void *)1);
460 case 0:
461 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
462 (me, "execv path = %s\n", execpath);
463
464 (void) execv(execpath, execargv);
465 exit(0);
466 default:
467 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
468 (me, "new forker's pid is %d\n", fpid);
469 forker_pid = fpid;
470 break;
471 }
472
473 return (NULL);
474 }
475
476 static void *
child_monitor(void * arg)477 child_monitor(
478 void *arg)
479 {
480 child_t *ch = (child_t *)arg;
481 pid_t cpid;
482 char *me = "child_monitor";
483
484 /* wait until child exits */
485 cpid = ch->child_pid;
486 (void) selfcred_pulse(ch->child_door);
487
488 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
489 (me, "child (pid = %d) exited or crashed ...\n", cpid);
490
491 /* return the slot used by the child */
492 return_cslot(ch);
493
494 return (NULL);
495 }
496
497
498 void
_nscd_proc_iamhere(void * buf,door_desc_t * dp,uint_t n_desc,int iam)499 _nscd_proc_iamhere(
500 void *buf,
501 door_desc_t *dp,
502 uint_t n_desc,
503 int iam)
504 {
505 int cslot;
506 child_t *ch;
507 int errnum;
508 ucred_t *uc = NULL;
509 uid_t uid;
510 nscd_imhere_t *ih;
511 nss_pheader_t *phdr = (nss_pheader_t *)buf;
512 char *me = "_nscd_proc_iamhere";
513
514
515 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
516 (me, "%d receives iamhere from %d\n", _whoami, iam);
517
518 if (door_ucred(&uc) != 0) {
519 errnum = errno;
520 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
521 (me, "door_ucred failed: %s\n", strerror(errnum));
522
523 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
524 NSCD_DOOR_UCRED_ERROR);
525 return;
526 }
527 uid = ucred_geteuid(uc);
528
529 switch (iam) {
530
531 case NSCD_MAIN:
532 if (_whoami == NSCD_MAIN || uid != main_uid) {
533 /*
534 * I'm main, or uid from door is not correct,
535 * this must be an imposter
536 */
537 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
538 (me, "MAIN IMPOSTER CAUGHT!\n");
539
540
541 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
542 NSCD_SELF_CRED_MAIN_IMPOSTER);
543 }
544 break;
545
546 case NSCD_FORKER:
547 if (_whoami == NSCD_FORKER || uid != forker_uid) {
548 /*
549 * I'm forker, or uid from door is not correct,
550 * this must be an imposter
551 */
552 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
553 (me, "FORKER IMPOSTER CAUGHT!\n");
554
555
556 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
557 NSCD_SELF_CRED_FORKER_IMPOSTER);
558 break;
559 }
560
561 /* only main needs to know the forker */
562 if (_whoami != NSCD_MAIN) {
563
564 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
565 NSCD_SELF_CRED_WRONG_NSCD);
566 break;
567 }
568
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);
573
574
575 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
576 NSCD_SELF_CRED_FORKER_IMPOSTER);
577 break;
578 }
579
580 if (n_desc < 1) {
581 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
582 (me, "BAD FORKER, NO DOOR!\n");
583
584
585 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
586 NSCD_SELF_CRED_NO_DOOR);
587 break;
588 }
589
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);
598
599 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
600 (me, "forking door is %d\n", forking_door);
601
602 NSCD_SET_STATUS_SUCCESS(phdr);
603 } else {
604 NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
605 break;
606 }
607
608 /* monitor the forker nscd */
609 (void) thr_create(NULL, 0, forker_monitor, NULL,
610 THR_DETACHED, NULL);
611
612 break;
613
614 case NSCD_CHILD:
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");
619
620 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
621 NSCD_SELF_CRED_CHILD_IMPOSTER);
622 break;
623 }
624
625 /* get the main nscd assigned slot number */
626 ih = NSCD_N2N_DOOR_DATA(nscd_imhere_t, buf);
627 cslot = ih->slot;
628 (void) mutex_lock(&child_lock);
629 if (cslot < 0 || cslot >= max_pu_nscd)
630 ch = NULL;
631 else
632 ch = child[cslot];
633 (void) mutex_unlock(&child_lock);
634
635 if (ch == NULL) {
636 /* Bad slot number */
637 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
638 (me, "bad slot number %d\n", cslot);
639
640 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
641 NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
642 break;
643 }
644
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",
648 uid, ch->child_uid);
649
650 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
651 NSCD_SELF_CRED_CHILD_IMPOSTER);
652 break;
653 }
654
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);
660
661 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
662 NSCD_SELF_CRED_INVALID_SLOT_STATE);
663 break;
664 }
665
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);
669
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);
682
683 /*
684 * let waiters know that the child is ready to
685 * serve
686 */
687 (void) cond_broadcast(ch->cond);
688 (void) mutex_unlock(ch->mutex);
689
690 /* monitor the child nscd */
691 (void) thr_create(NULL, 0, child_monitor,
692 ch, THR_DETACHED, NULL);
693 NSCD_SET_STATUS_SUCCESS(phdr);
694 break;
695 } else {
696 NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
697 }
698 break;
699 }
700
701 ucred_free(uc);
702 uc = NULL;
703 }
704
705 void
_nscd_proc_pulse(void * buf,int iam)706 _nscd_proc_pulse(
707 void *buf,
708 int iam)
709 {
710 long last_active;
711 int done = 0;
712 nss_pheader_t *phdr = (nss_pheader_t *)buf;
713 char *me = "_nscd_proc_pulse";
714
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);
719
720 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
721 NSCD_SELF_CRED_MAIN_IMPOSTER);
722 return;
723 }
724
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");
729
730 for (;;)
731 (void) pause();
732 }
733
734 /* remember the current activity sequence number */
735 (void) mutex_lock(&activity_lock);
736 last_active = activity;
737 (void) mutex_unlock(&activity_lock);
738
739 while (!done) {
740
741 /* allow per_user_nscd_ttl seconds of inactivity */
742 (void) sleep(pu_nscd_ttl);
743
744 (void) mutex_lock(&activity_lock);
745 if (last_active == activity)
746 done = 1;
747 else {
748 last_active = activity;
749 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
750 (me, "active, sleep again for %d seconds\n",
751 pu_nscd_ttl);
752 }
753 (void) mutex_unlock(&activity_lock);
754 }
755
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);
759 exit(0);
760 }
761
762 void
_nscd_proc_fork(void * buf,int iam)763 _nscd_proc_fork(
764 void *buf,
765 int iam)
766 {
767 int slot;
768 int ret;
769 char *fmri;
770 pid_t cid;
771 uid_t set2uid;
772 gid_t set2gid;
773 nss_pheader_t *phdr = (nss_pheader_t *)buf;
774 char *me = "_nscd_proc_fork";
775 nscd_fork_t *f;
776 nscd_imhere_t ih;
777
778 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
779 (me, "%d receives fork request from %d\n", _whoami, iam);
780
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);
785
786 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
787 NSCD_SELF_CRED_MAIN_IMPOSTER);
788 return;
789 }
790
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");
795
796 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
797 NSCD_SELF_CRED_WRONG_NSCD);
798 return;
799 }
800
801 /* fork a child for the slot assigned by the main nscd */
802 f = NSCD_N2N_DOOR_DATA(nscd_fork_t, buf);
803 slot = f->slot;
804 /* set the uid/gid as assigned by the main nscd */
805 set2uid = f->uid;
806 set2gid = f->gid;
807
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");
812
813 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
814 NSCD_SELF_CRED_INVALID_SLOT_NUMBER);
815 return;
816 }
817
818 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
819 (me, "before fork1() ...\n");
820
821 if ((cid = fork1()) == 0) {
822 _whoami = NSCD_CHILD;
823
824 /*
825 * remember when this child nscd starts
826 * (replace the forker start time)
827 */
828 _nscd_set_start_time(1);
829
830 /* close all except the log file */
831 if (_logfd > 0) {
832 int i;
833 for (i = 0; i < _logfd; i++)
834 (void) close(i);
835 closefrom(_logfd + 1);
836 } else
837 closefrom(0);
838
839 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
840 (me, "child %d\n", getpid());
841
842 (void) setgid(set2gid);
843 (void) setuid(set2uid);
844
845 /* set up the door and server thread pool */
846 if ((_doorfd = _nscd_setup_child_server(_doorfd)) == -1)
847 exit(-1);
848
849 /* tell libsldap to do self cred only */
850 (void) setup_ldap_backend();
851
852 /* notify main that child is active */
853 ih.slot = slot;
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);
858
859 NSCD_SET_STATUS_SUCCESS(phdr);
860 return;
861 } if (cid == (pid_t)-1) {
862 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
863 (me, "forker unable to fork ...\n");
864
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);
870 }
871 exit(0);
872 } else {
873 /*
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)
878 */
879 (void) init_user_proc_monitor();
880
881 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
882 (me, "child forked: parent pid = %d, child pid = %d\n",
883 getpid(), cid);
884
885 NSCD_SET_STATUS_SUCCESS(phdr);
886 }
887
888 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
889 (me, "after fork\n");
890 }
891
892 static void
selfcred_fork(void * buf,int doorfd,int cslot,uid_t uid,gid_t gid)893 selfcred_fork(
894 void *buf,
895 int doorfd,
896 int cslot,
897 uid_t uid,
898 gid_t gid)
899 {
900 int ret;
901 nscd_fork_t f;
902 nss_pheader_t *phdr = (nss_pheader_t *)buf;
903 char *me = "selfcred_fork";
904
905 /* if no door fd, do nothing */
906 if (doorfd == -1) {
907 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
908 NSCD_SELF_CRED_NO_DOOR);
909 }
910
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);
914
915 f.slot = cslot;
916 f.uid = uid;
917 f.gid = gid;
918
919 ret = _nscd_doorcall_fd(doorfd, NSCD_FORK|(_whoami&NSCD_WHOAMI),
920 &f, sizeof (f), NULL, 0, phdr);
921
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",
924 doorfd, cslot, ret);
925
926 if (NSCD_STATUS_IS_NOT_OK(phdr)) {
927
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));
934
935 }
936 }
937
938 void
_nscd_proc_alt_get(void * buf,int * door)939 _nscd_proc_alt_get(
940 void *buf,
941 int *door)
942 {
943 int errnum;
944 uid_t set2uid;
945 gid_t set2gid;
946 nss_pheader_t *phdr = (nss_pheader_t *)buf;
947 char *me = "_nscd_proc_alt_get";
948 ucred_t *uc = NULL;
949 child_t *ch;
950
951 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
952 (me, "getting an alternate door ...\n");
953
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");
958
959 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
960 NSCD_SELF_CRED_NO_FORKER);
961 return;
962 }
963
964 /* get door client's credential information */
965 if (door_ucred(&uc) != 0) {
966 errnum = errno;
967 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
968 (me, "door_ucred failed: %s\n", strerror(errnum));
969
970 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
971 NSCD_DOOR_UCRED_ERROR);
972 return;
973 }
974
975 /* get door client's effective uid and effective gid */
976 set2uid = ucred_geteuid(uc);
977 set2gid = ucred_getegid(uc);
978 ucred_free(uc);
979 uc = NULL;
980
981 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
982 (me, "child uid = %d, gid = %d\n", set2uid, set2gid);
983
984 /* is a slot available ? if not, no one to serve */
985 if (child == NULL || (ch = get_cslot(set2uid, 0)) == NULL) {
986
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);
990
991 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
992 NSCD_SELF_CRED_NO_CHILD_SLOT);
993 return;
994 }
995
996 /* create the per user nscd if necessary */
997 if (ch->child_state != CHILD_STATE_PIDKNOWN) {
998
999 nss_pheader_t phdr1;
1000 NSCD_CLEAR_STATUS(&phdr1);
1001
1002 (void) mutex_lock(ch->mutex);
1003 if (ch->child_state == CHILD_STATE_UIDKNOWN) {
1004
1005 /* ask forker to fork a new child */
1006 selfcred_fork(&phdr1, forking_door, ch->child_slot,
1007 set2uid, set2gid);
1008 if (NSCD_STATUS_IS_NOT_OK(&phdr1)) {
1009 (void) mutex_unlock(ch->mutex);
1010 NSCD_COPY_STATUS(phdr, &phdr1);
1011 return;
1012 }
1013 ch->child_state = CHILD_STATE_FORKSENT;
1014 }
1015
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);
1019
1020 /* wait for the per user nscd to become available */
1021 while (ch->child_state == CHILD_STATE_FORKSENT) {
1022 timestruc_t to;
1023 int err;
1024 int ttl = 5;
1025
1026 to.tv_sec = ttl;
1027 to.tv_nsec = 0;
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);
1031 if (err == ETIME) {
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",
1036 ch->child_slot);
1037 break;
1038 }
1039 }
1040 (void) mutex_unlock(ch->mutex);
1041 }
1042
1043 if (ch->child_state != CHILD_STATE_PIDKNOWN) {
1044
1045 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1046 NSCD_SELF_CRED_INVALID_SLOT_STATE);
1047 return;
1048 }
1049
1050 *door = ch->child_door;
1051
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);
1055
1056 NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0);
1057 }
1058
1059 static char **
cpargv(int argc,char ** inargv)1060 cpargv(
1061 int argc,
1062 char **inargv)
1063 {
1064 char **newargv;
1065 int c = 4;
1066 int i = 0, j, k = 0, n = 0;
1067
1068 newargv = (char **)calloc(c + 1, sizeof (char *));
1069 if (newargv == NULL)
1070 return (NULL);
1071
1072 newargv[n] = strdup(inargv[0]);
1073 if (newargv[n++] == NULL) {
1074 free(newargv);
1075 return (NULL);
1076 }
1077
1078 newargv[n] = strdup("-F");
1079 if (newargv[n++] == NULL) {
1080 free(newargv[0]);
1081 free(newargv);
1082 return (NULL);
1083 }
1084
1085 for (i = 1; i < argc; i++) {
1086 if (strcmp(inargv[i], "-f") == 0)
1087 k = 2;
1088 if (k == 0)
1089 continue;
1090
1091 newargv[n] = strdup(inargv[i]);
1092 if (newargv[n] == NULL) {
1093 for (j = 0; j < n; j++)
1094 free(newargv[j]);
1095 free(newargv);
1096 return (NULL);
1097 }
1098
1099 k--;
1100 n++;
1101 }
1102 return (newargv);
1103 }
1104
1105
1106 void
_nscd_start_forker(char * path,int argc,char ** argv)1107 _nscd_start_forker(
1108 char *path,
1109 int argc,
1110 char **argv)
1111 {
1112 pid_t cid;
1113
1114 /* if self cred is not configured, do nothing */
1115 if (!_nscd_is_self_cred_on(1, NULL))
1116 return;
1117
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)
1122 exit(1);
1123
1124 switch (cid = fork1()) {
1125 case (pid_t)-1:
1126 exit(1);
1127 break;
1128 case 0:
1129 /* start the forker nscd */
1130 (void) execv(path, execargv);
1131 exit(0);
1132 break;
1133 default:
1134 /* main nscd */
1135 /* remember process id of the forker */
1136 forker_pid = cid;
1137
1138 /* enable child nscd management */
1139 (void) _nscd_init_cslots();
1140 break;
1141 }
1142 }
1143
1144 static nscd_rc_t
get_ldap_funcs(char * name,void ** func_p)1145 get_ldap_funcs(
1146 char *name,
1147 void **func_p)
1148 {
1149 char *me = "get_ldap_funcs";
1150 static void *handle = NULL;
1151 void *sym;
1152
1153 if (name == NULL && handle != NULL) {
1154 (void) dlclose(handle);
1155 return (NSCD_SUCCESS);
1156 }
1157 /* no handle to close, it's OK */
1158 if (name == NULL)
1159 return (NSCD_SUCCESS);
1160
1161 if (handle == NULL) {
1162 handle = dlopen("libsldap.so.1", RTLD_LAZY);
1163 if (handle == NULL) {
1164
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);
1168 }
1169 }
1170
1171 if ((sym = dlsym(handle, name)) == NULL) {
1172
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);
1176 } else
1177 (void) memcpy(func_p, &sym, sizeof (void *));
1178
1179 return (NSCD_SUCCESS);
1180 }
1181
1182
1183 int
_nscd_is_self_cred_on(int recheck,char ** dblist)1184 _nscd_is_self_cred_on(int recheck, char **dblist)
1185 {
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 */
1190 int ldap_on = 0;
1191
1192 char *ldap_sc_func = "__ns_ldap_self_gssapi_config";
1193 ns_ldap_self_gssapi_config_t ldap_config;
1194
1195 if (checked && !recheck) {
1196 if (is_on && dblist != NULL)
1197 *dblist = selfcred_dbs;
1198 return (is_on);
1199 }
1200
1201 if (selfcred_dbs != NULL)
1202 free(selfcred_dbs);
1203 selfcred_dbs = _nscd_srcs_in_db_nsw_policy(1, &srcs);
1204
1205 if (selfcred_dbs == NULL) {
1206 is_on = 0;
1207 checked = 1;
1208 return (0);
1209 }
1210
1211 /*
1212 * also check the ldap backend to see if
1213 * the configuration there is good for
1214 * doing self credentialing
1215 */
1216 if (ldap_func == NULL)
1217 (void) get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1218 if (ldap_func != NULL) {
1219 if (ldap_func(&ldap_config) == NS_LDAP_SUCCESS &&
1220 ldap_config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE)
1221 ldap_on = 1;
1222 }
1223
1224 is_on = (pu_nscd_enabled == nscd_true) && ldap_on;
1225
1226 checked = 1;
1227
1228 if (is_on && dblist != NULL)
1229 *dblist = selfcred_dbs;
1230
1231 return (is_on);
1232 }
1233
1234 static nscd_rc_t
setup_ldap_backend()1235 setup_ldap_backend()
1236 {
1237 nscd_rc_t rc;
1238 static void (*ldap_func)();
1239 char *ldap_sc_func = "__ns_ldap_self_gssapi_only_set";
1240 if (ldap_func == NULL)
1241 rc = get_ldap_funcs(ldap_sc_func, (void **)&ldap_func);
1242 if (ldap_func != NULL) {
1243 ldap_func(1);
1244 return (NSCD_SUCCESS);
1245 }
1246 return (rc);
1247 }
1248
1249 /*ARGSUSED*/
1250 void
_nscd_peruser_getadmin(void * buf,int buf_size)1251 _nscd_peruser_getadmin(
1252 void *buf,
1253 int buf_size)
1254 {
1255 void *result_mn = NSCD_N2N_DOOR_DATA(void, buf);
1256 int errnum = 0;
1257 int ret;
1258 uid_t uid;
1259 nss_pheader_t *phdr = (nss_pheader_t *)buf;
1260 char *me = "_nscd_peruser_getadmin";
1261 ucred_t *uc = NULL;
1262 child_t *ch;
1263
1264 /* get door client's credential information */
1265 if (door_ucred(&uc) != 0) {
1266 errnum = errno;
1267 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1268 (me, "door_ucred failed: %s\n", strerror(errnum));
1269
1270 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum,
1271 NSCD_DOOR_UCRED_ERROR);
1272 return;
1273 }
1274
1275 /* get door client's effective uid */
1276 uid = ucred_geteuid(uc);
1277 ucred_free(uc);
1278 uc = NULL;
1279
1280 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1281 (me, "per user get admin ... (uid = %d)\n", uid);
1282
1283 /* is the per-user nscd running ? if not, no one to serve */
1284 ch = get_cslot(uid, 1);
1285 if (ch == NULL) {
1286 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0,
1287 NSCD_SELF_CRED_NO_CHILD_SLOT);
1288 return;
1289 }
1290
1291 ret = _nscd_doorcall_fd(ch->child_door, NSCD_GETADMIN,
1292 NULL, sizeof (nscd_admin_t), result_mn,
1293 sizeof (nscd_admin_t), phdr);
1294
1295 if (ret == NSS_SUCCESS) {
1296 phdr->data_len = sizeof (nscd_admin_t);
1297 return;
1298 }
1299 }
1300
1301 static void
set_selfcred_cfg(char param,void * data)1302 set_selfcred_cfg(
1303 char param,
1304 void *data)
1305 {
1306 int64_t prop_int;
1307 uint8_t prop_boolean;
1308 char *me = "set_selfcred_cfg";
1309
1310 if (param == 'e') {
1311 prop_boolean = *(uint8_t *)data;
1312 pu_nscd_enabled = *(uint8_t *)get_smf_prop(
1313 "enable_per_user_lookup", 'b', &prop_boolean);
1314
1315 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1316 (me, "self cred config: enabled = %d\n", pu_nscd_enabled);
1317 }
1318
1319 if (param == 't') {
1320 prop_int = *(int *)data;
1321 pu_nscd_ttl = *(int64_t *)get_smf_prop(
1322 "per_user_nscd_time_to_live", 'i', &prop_int);
1323
1324 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1325 (me, "self cred config: PUN TTL = %d\n", pu_nscd_ttl);
1326 }
1327 }
1328
1329 /* ARGSUSED */
1330 nscd_rc_t
_nscd_cfg_selfcred_notify(void * data,struct nscd_cfg_param_desc * pdesc,nscd_cfg_id_t * nswdb,nscd_cfg_flag_t dflag,nscd_cfg_error_t ** errorp,void * cookie)1331 _nscd_cfg_selfcred_notify(
1332 void *data,
1333 struct nscd_cfg_param_desc *pdesc,
1334 nscd_cfg_id_t *nswdb,
1335 nscd_cfg_flag_t dflag,
1336 nscd_cfg_error_t **errorp,
1337 void *cookie)
1338 {
1339
1340 nscd_cfg_global_selfcred_t *sc_cfg = &nscd_selfcred_cfg_g;
1341 int off;
1342
1343 /*
1344 * At init time, the whole group of config params are received.
1345 * At update time, group or individual parameter value could
1346 * be received.
1347 */
1348
1349 if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
1350
1351 *sc_cfg = *(nscd_cfg_global_selfcred_t *)data;
1352
1353 off = offsetof(nscd_cfg_global_selfcred_t,
1354 enable_selfcred);
1355 set_selfcred_cfg('e', (char *)data + off);
1356
1357 off = offsetof(nscd_cfg_global_selfcred_t,
1358 per_user_nscd_ttl);
1359 set_selfcred_cfg('t', (char *)data + off);
1360
1361 return (NSCD_SUCCESS);
1362 }
1363
1364 /*
1365 * individual config parameter
1366 */
1367 off = offsetof(nscd_cfg_global_selfcred_t, enable_selfcred);
1368 if (pdesc->p_offset == off) {
1369 sc_cfg->enable_selfcred = *(nscd_bool_t *)data;
1370 set_selfcred_cfg('e', data);
1371 return (NSCD_SUCCESS);
1372 }
1373
1374 off = offsetof(nscd_cfg_global_selfcred_t, per_user_nscd_ttl);
1375 if (pdesc->p_offset == off) {
1376 sc_cfg->per_user_nscd_ttl = *(int *)data;
1377 set_selfcred_cfg('t', data);
1378 return (NSCD_SUCCESS);
1379 }
1380
1381 return (NSCD_SUCCESS);
1382 }
1383
1384 /* ARGSUSED */
1385 nscd_rc_t
_nscd_cfg_selfcred_verify(void * data,struct nscd_cfg_param_desc * pdesc,nscd_cfg_id_t * nswdb,nscd_cfg_flag_t dflag,nscd_cfg_error_t ** errorp,void ** cookie)1386 _nscd_cfg_selfcred_verify(
1387 void *data,
1388 struct nscd_cfg_param_desc *pdesc,
1389 nscd_cfg_id_t *nswdb,
1390 nscd_cfg_flag_t dflag,
1391 nscd_cfg_error_t **errorp,
1392 void **cookie)
1393 {
1394
1395 return (NSCD_SUCCESS);
1396 }
1397
1398 /* ARGSUSED */
1399 nscd_rc_t
_nscd_cfg_selfcred_get_stat(void ** stat,struct nscd_cfg_stat_desc * sdesc,nscd_cfg_id_t * nswdb,nscd_cfg_flag_t * dflag,void (** free_stat)(void * stat),nscd_cfg_error_t ** errorp)1400 _nscd_cfg_selfcred_get_stat(
1401 void **stat,
1402 struct nscd_cfg_stat_desc *sdesc,
1403 nscd_cfg_id_t *nswdb,
1404 nscd_cfg_flag_t *dflag,
1405 void (**free_stat)(void *stat),
1406 nscd_cfg_error_t **errorp)
1407 {
1408 return (NSCD_SUCCESS);
1409 }
1410
1411 static int
check_uid(char * pid_name)1412 check_uid(char *pid_name)
1413 {
1414 char pname[PATH_MAX];
1415 static pid_t pid = 0;
1416 static uid_t uid = 0;
1417 static uid_t euid = 0;
1418 int pfd; /* file descriptor for /proc/<pid>/psinfo */
1419 psinfo_t info; /* process information from /proc */
1420
1421 if (uid == 0) {
1422 pid = getpid();
1423 uid = getuid();
1424 euid = geteuid();
1425 }
1426
1427 (void) snprintf(pname, sizeof (pname), "/proc/%s/psinfo", pid_name);
1428 retry:
1429 if ((pfd = open(pname, O_RDONLY)) == -1) {
1430 /* Process may have exited */
1431 return (1);
1432 }
1433
1434 /*
1435 * Get the info structure for the process and close quickly.
1436 */
1437 if (read(pfd, (char *)&info, sizeof (info)) < 0) {
1438 int saverr = errno;
1439
1440 (void) close(pfd);
1441 if (saverr == EAGAIN)
1442 goto retry;
1443 if (saverr != ENOENT)
1444 return (1);
1445 }
1446 (void) close(pfd);
1447
1448 if (info.pr_pid != pid &&
1449 info.pr_uid == uid && info.pr_euid == euid)
1450 return (0);
1451 else
1452 return (1);
1453 }
1454
1455
1456 /*
1457 * FUNCTION: check_user_process
1458 */
1459 /*ARGSUSED*/
1460 static void *
check_user_process(void * arg)1461 check_user_process(void *arg)
1462 {
1463
1464 DIR *dp;
1465 struct dirent *ep;
1466 int found;
1467 char *me = "check_user_process";
1468
1469 for (;;) {
1470 (void) sleep(60);
1471
1472 found = 0;
1473
1474 /*
1475 * search the /proc directory and look at each process
1476 */
1477 if ((dp = opendir("/proc")) == NULL) {
1478 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1479 (me, "unable to open the /proc directory\n");
1480 continue;
1481 }
1482
1483 /* for each active process */
1484 while (ep = readdir(dp)) {
1485 if (ep->d_name[0] == '.') /* skip . and .. */
1486 continue;
1487 if (check_uid(ep->d_name) == 0) {
1488 found = 1;
1489 break;
1490 }
1491 }
1492
1493 /*
1494 * if no process running as the PUN uid found, exit
1495 * to kill this PUN
1496 */
1497 if (found == 0) {
1498 (void) closedir(dp);
1499 exit(1);
1500 }
1501 (void) closedir(dp);
1502 }
1503 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
1504 }
1505
1506 static nscd_rc_t
init_user_proc_monitor()1507 init_user_proc_monitor() {
1508
1509 int errnum;
1510 char *me = "init_user_proc_monitor";
1511
1512 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1513 (me, "initializing the user process monitor\n");
1514
1515 /*
1516 * start a thread to make sure there is at least a process
1517 * running as the PUN user. If not, terminate this PUN.
1518 */
1519 if (thr_create(NULL, NULL, check_user_process,
1520 NULL, THR_DETACHED, NULL) != 0) {
1521 errnum = errno;
1522 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1523 (me, "thr_create: %s\n", strerror(errnum));
1524 return (NSCD_THREAD_CREATE_ERROR);
1525 }
1526
1527 return (NSCD_SUCCESS);
1528 }
1529
1530 static void *
get_smf_prop(const char * var,char type,void * def_val)1531 get_smf_prop(const char *var, char type, void *def_val)
1532 {
1533 scf_simple_prop_t *prop;
1534 void *val;
1535 char *me = "get_smf_prop";
1536
1537 prop = scf_simple_prop_get(NULL, NULL, "config", var);
1538 if (prop) {
1539 switch (type) {
1540 case 'b':
1541 val = scf_simple_prop_next_boolean(prop);
1542 if (val != NULL)
1543 (void) memcpy(def_val, val, sizeof (uint8_t));
1544 break;
1545
1546 case 'i':
1547 val = scf_simple_prop_next_integer(prop);
1548 if (val != NULL)
1549 (void) memcpy(def_val, val, sizeof (int64_t));
1550 break;
1551 }
1552 scf_simple_prop_free(prop);
1553 }
1554
1555 if (prop == NULL || val == NULL) {
1556 char vs[64];
1557
1558 switch (type) {
1559 case 'b':
1560 if (*(uint8_t *)def_val)
1561 (void) strcpy(vs, "yes");
1562 else
1563 (void) strcpy(vs, "no");
1564
1565 break;
1566
1567 case 'i':
1568 (void) sprintf(vs, "%lld", *(int64_t *)def_val);
1569 break;
1570
1571 }
1572 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ALERT)
1573 (me, "no value for config/%s (%s). "
1574 "Using default \"%s\"\n", var,
1575 scf_strerror(scf_error()), vs);
1576 }
1577
1578 return (def_val);
1579 }
1580