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
 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
 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
 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
 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 *
 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
 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
 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
 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
 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
 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
 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 *
 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 *
 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
 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
 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
 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
 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
 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 **
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
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
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
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
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
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
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
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
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
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
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 *
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
1512 init_user_proc_monitor() {
1513 
1514         int     errnum;
1515         char    *me = "init_user_proc_monitor";
1516 
1517         _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG)
1518         (me, "initializing the user process monitor\n");
1519 
1520         /*
1521          * start a thread to make sure there is at least a process
1522          * running as the PUN user. If not, terminate this PUN.
1523          */
1524         if (thr_create(NULL, NULL, check_user_process,
1525                 NULL, THR_DETACHED, NULL) != 0) {
1526                 errnum = errno;
1527                 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR)
1528                 (me, "thr_create: %s\n", strerror(errnum));
1529                 return (NSCD_THREAD_CREATE_ERROR);
1530         }
1531 
1532         return (NSCD_SUCCESS);
1533 }
1534 
1535 static void *
1536 get_smf_prop(const char *var, char type, void *def_val)
1537 {
1538         scf_simple_prop_t       *prop;
1539         void                    *val;
1540         char                    *me = "get_smf_prop";
1541 
1542         prop = scf_simple_prop_get(NULL, NULL, "config", var);
1543         if (prop) {
1544                 switch (type) {
1545                 case 'b':
1546                         val = scf_simple_prop_next_boolean(prop);
1547                         if (val != NULL)
1548                                 (void) memcpy(def_val, val, sizeof (uint8_t));
1549                         break;
1550 
1551                 case 'i':
1552                         val = scf_simple_prop_next_integer(prop);
1553                         if (val != NULL)
1554                                 (void) memcpy(def_val, val, sizeof (int64_t));
1555                         break;
1556                 }
1557                 scf_simple_prop_free(prop);
1558         }
1559 
1560         if (prop == NULL || val == NULL) {
1561                 char    vs[64];
1562 
1563                 switch (type) {
1564                 case 'b':
1565                         if (*(uint8_t *)def_val)
1566                                 (void) strcpy(vs, "yes");
1567                         else
1568                                 (void) strcpy(vs, "no");
1569 
1570                         break;
1571 
1572                 case 'i':
1573                         (void) sprintf(vs, "%lld", *(int64_t *)def_val);
1574                         break;
1575 
1576                 }
1577                 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ALERT)
1578                 (me, "no value for config/%s (%s). "
1579                     "Using default \"%s\"\n", var,
1580                     scf_strerror(scf_error()), vs);
1581         }
1582 
1583         return (def_val);
1584 }