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