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