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