Print this page
    
NEX-19665 Several door servers don't properly handle exiting threads
Review by: Gordon Ross <gordon.ross@nexenta.com>
Review by: Evan Layton <evan.layton@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/ldapcachemgr/cachemgr.c
          +++ new/usr/src/cmd/ldapcachemgr/cachemgr.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
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  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   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + * Copyright 2019 Nexenta Systems, Inc.
  24   25   */
  25   26  
  26   27  /*
  27   28   * Simple doors ldap cache daemon
  28   29   */
  29   30  
  30   31  #include <stdio.h>
  31   32  #include <stdlib.h>
  32   33  #include <signal.h>
  33   34  #include <door.h>
  34   35  #include <time.h>
  35   36  #include <string.h>
  36   37  #include <strings.h>
  37   38  #include <libintl.h>
  38   39  #include <sys/stat.h>
  39   40  #include <sys/time.h>
  40   41  #include <sys/wait.h>
  41   42  #include <stdlib.h>
  42   43  #include <errno.h>
  43   44  #include <pthread.h>
  44   45  #include <thread.h>
  45   46  #include <stdarg.h>
  46   47  #include <fcntl.h>
  47   48  #include <assert.h>
  48   49  #include <unistd.h>
  49   50  #include <memory.h>
  50   51  #include <sys/types.h>
  51   52  #include <syslog.h>
  52   53  #include <locale.h>     /* LC_ALL */
  53   54  
  54   55  #include <alloca.h>
  55   56  #include <ucontext.h>
  56   57  #include <stddef.h>     /* offsetof */
  57   58  #include <priv.h>
  58   59  
  59   60  #include "getxby_door.h"
  60   61  #include "cachemgr.h"
  61   62  
  62   63  static void     detachfromtty();
  63   64  admin_t         current_admin;
  64   65  static int      will_become_server;
  65   66  
  66   67  static void switcher(void *cookie, char *argp, size_t arg_size,
  67   68                          door_desc_t *dp, uint_t n_desc);
  68   69  static void usage(char *s);
  69   70  static int cachemgr_set_lf(admin_t *ptr, char *logfile);
  70   71  static int client_getadmin(admin_t *ptr);
  71   72  static int setadmin(ldap_call_t *ptr);
  72   73  static  int client_setadmin(admin_t *ptr);
  73   74  static int client_showstats(admin_t *ptr);
  74   75  static int is_root(int free_uc, char *dc_str, ucred_t **uc);
  75   76  int is_root_or_all_privs(char *dc_str, ucred_t **ucp);
  76   77  static void admin_modify(LineBuf *config_info, ldap_call_t *in);
  77   78  
  78   79  #ifdef SLP
  79   80  int                     use_slp = 0;
  80   81  static unsigned int     refresh = 10800;        /* dynamic discovery interval */
  81   82  #endif /* SLP */
  82   83  
  83   84  static ldap_stat_t *
  84   85  getcacheptr(char *s)
  85   86  {
  86   87          static const char *caches[1] = {"ldap"};
  87   88  
  88   89          if (strncmp(caches[0], s, strlen(caches[0])) == 0)
  89   90                  return (¤t_admin.ldap_stat);
  90   91  
  91   92          return (NULL);
  92   93  }
  93   94  
  94   95  char *
  95   96  getcacheopt(char *s)
  96   97  {
  97   98          while (*s && *s != ',')
  98   99                  s++;
  99  100          return ((*s == ',') ? (s + 1) : NULL);
 100  101  }
 101  102  
 102  103  /*
 103  104   *  This is here to prevent the ldap_cachemgr becomes
 104  105   *  daemonlized to early to soon during boot time.
 105  106   *  This causes problems during boot when automounter
 106  107   *  and others try to use libsldap before ldap_cachemgr
 107  108   *  finishes walking the server list.
 108  109   */
 109  110  static void
 110  111  sig_ok_to_exit(int signo)
 111  112  {
 112  113          if (signo == SIGUSR1) {
 113  114                  logit("sig_ok_to_exit(): parent exiting...\n");
 114  115                  exit(0);
 115  116          } else {
 116  117                  logit("sig_ok_to_exit(): invalid signal(%d) received.\n",
 117  118                      signo);
 118  119                  syslog(LOG_ERR, gettext("ldap_cachemgr: "
 119  120                      "invalid signal(%d) received."), signo);
 120  121                  exit(1);
 121  122          }
 122  123  }
 123  124  #define LDAP_TABLES             1       /* ldap */
 124  125  #define TABLE_THREADS           10
 125  126  #define COMMON_THREADS          20
 126  127  #define CACHE_MISS_THREADS      (COMMON_THREADS + LDAP_TABLES * TABLE_THREADS)
 127  128  #define CACHE_HIT_THREADS       20
 128  129  /*
 129  130   * There is only one thread handling GETSTATUSCHANGE START from main nscd
 130  131   * most of time. But it could happen that a main nscd is restarted, old main
 131  132   * nscd's handling thread is still alive when new main nscd starts and sends
 132  133   * START, or old main dies. STOP is not sent in both cases.
 133  134   * The main nscd requires 2 threads to handle START and STOP. So max number
 134  135   * of change threads is set to 4.
 135  136   */
 136  137  #define MAX_CHG_THREADS         4
 137  138  #define MAX_SERVER_THREADS      (CACHE_HIT_THREADS + CACHE_MISS_THREADS + \
 138  139                                  MAX_CHG_THREADS)
 139  140  
 140  141  static sema_t common_sema;
 141  142  static sema_t ldap_sema;
 142  143  static thread_key_t lookup_state_key;
 143  144  static int chg_threads_num = 0;
 144  145  static mutex_t chg_threads_num_lock = DEFAULTMUTEX;
 145  146  
 146  147  static void
 147  148  initialize_lookup_clearance()
 148  149  {
 149  150          (void) thr_keycreate(&lookup_state_key, NULL);
 150  151          (void) sema_init(&common_sema, COMMON_THREADS, USYNC_THREAD, 0);
 151  152          (void) sema_init(&ldap_sema, TABLE_THREADS, USYNC_THREAD, 0);
 152  153  }
 153  154  
 154  155  int
 155  156  get_clearance(int callnumber)
 156  157  {
 157  158          sema_t  *table_sema = NULL;
 158  159          char    *tab;
 159  160  
 160  161          if (sema_trywait(&common_sema) == 0) {
 161  162                  (void) thr_setspecific(lookup_state_key, NULL);
 162  163                  return (0);
 163  164          }
 164  165  
 165  166          switch (callnumber) {
 166  167                  case GETLDAPCONFIG:
 167  168                          tab = "ldap";
 168  169                          table_sema = &ldap_sema;
 169  170                          break;
 170  171                  default:
 171  172                          logit("Internal Error: get_clearance\n");
 172  173                          break;
 173  174          }
 174  175  
 175  176          if (sema_trywait(table_sema) == 0) {
 176  177                  (void) thr_setspecific(lookup_state_key, (void*)1);
 177  178                  return (0);
 178  179          }
 179  180  
 180  181          if (current_admin.debug_level >= DBG_CANT_FIND) {
 181  182                  logit("get_clearance: throttling load for %s table\n", tab);
 182  183          }
 183  184  
 184  185          return (-1);
 185  186  }
 186  187  
 187  188  int
 188  189  release_clearance(int callnumber)
 189  190  {
 190  191          int     which;
 191  192          sema_t  *table_sema = NULL;
 192  193  
 193  194          (void) thr_getspecific(lookup_state_key, (void**)&which);
 194  195          if (which == 0) /* from common pool */ {
 195  196                  (void) sema_post(&common_sema);
 196  197                  return (0);
 197  198          }
 198  199  
 199  200          switch (callnumber) {
 200  201                  case GETLDAPCONFIG:
 201  202                          table_sema = &ldap_sema;
 202  203                          break;
 203  204                  default:
 204  205                          logit("Internal Error: release_clearance\n");
 205  206                          break;
 206  207          }
 207  208          (void) sema_post(table_sema);
 208  209  
 209  210          return (0);
 210  211  }
 211  212  
 212  213  
 213  214  static mutex_t          create_lock;
 214  215  static int              num_servers = 0;
 215  216  static thread_key_t     server_key;
 216  217  
 217  218  
  
    | 
      ↓ open down ↓ | 
    184 lines elided | 
    
      ↑ open up ↑ | 
  
 218  219  /*
 219  220   * Bind a TSD value to a server thread. This enables the destructor to
 220  221   * be called if/when this thread exits.  This would be a programming error,
 221  222   * but better safe than sorry.
 222  223   */
 223  224  
 224  225  /*ARGSUSED*/
 225  226  static void *
 226  227  server_tsd_bind(void *arg)
 227  228  {
 228      -        static void     *value = 0;
      229 +        static void *value = "NON-NULL TSD";
 229  230  
 230  231          /*
 231  232           * disable cancellation to prevent hangs when server
 232  233           * threads disappear
 233  234           */
 234      -
      235 +        (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 235  236          (void) thr_setspecific(server_key, value);
 236  237          (void) door_return(NULL, 0, NULL, 0);
 237  238  
 238  239          return (value);
 239  240  }
 240  241  
 241  242  /*
 242  243   * Server threads are created here.
 243  244   */
 244  245  
 245  246  /*ARGSUSED*/
 246  247  static void
 247  248  server_create(door_info_t *dip)
 248  249  {
 249  250          (void) mutex_lock(&create_lock);
 250  251          if (++num_servers > MAX_SERVER_THREADS) {
 251  252                  num_servers--;
 252  253                  (void) mutex_unlock(&create_lock);
 253  254                  return;
 254  255          }
 255  256          (void) mutex_unlock(&create_lock);
 256  257          (void) thr_create(NULL, 0, server_tsd_bind, NULL,
 257  258              THR_BOUND|THR_DETACHED, NULL);
 258  259  }
 259  260  
 260  261  /*
  
    | 
      ↓ open down ↓ | 
    16 lines elided | 
    
      ↑ open up ↑ | 
  
 261  262   * Server thread are destroyed here
 262  263   */
 263  264  
 264  265  /*ARGSUSED*/
 265  266  static void
 266  267  server_destroy(void *arg)
 267  268  {
 268  269          (void) mutex_lock(&create_lock);
 269  270          num_servers--;
 270  271          (void) mutex_unlock(&create_lock);
      272 +        (void) thr_setspecific(server_key, NULL);
 271  273  }
 272  274  
 273  275  static void             client_killserver();
 274  276  
 275  277  int
 276  278  main(int argc, char ** argv)
 277  279  {
 278  280          int                     did;
 279  281          int                     opt;
 280  282          int                     errflg = 0;
 281  283          int                     showstats = 0;
 282  284          int                     doset = 0;
 283  285          int                     dofg = 0;
 284  286          struct stat             buf;
 285  287          sigset_t                myset;
 286  288          struct sigaction        sighupaction;
 287  289          int                     debug_level = 0;
 288  290  
 289  291          /* setup for localization */
 290  292          (void) setlocale(LC_ALL, "");
 291  293          (void) textdomain(TEXT_DOMAIN);
 292  294  
 293  295          openlog("ldap_cachemgr", LOG_PID, LOG_DAEMON);
 294  296  
 295  297          if (chdir(NSLDAPDIRECTORY) < 0) {
 296  298                  (void) fprintf(stderr, gettext("chdir(\"%s\") failed: %s\n"),
 297  299                      NSLDAPDIRECTORY, strerror(errno));
 298  300                  exit(1);
 299  301          }
 300  302  
 301  303          /*
 302  304           * Correctly set file mode creation mask, so to make the new files
 303  305           * created for door calls being readable by all.
 304  306           */
 305  307          (void) umask(0);
 306  308  
 307  309          /*
 308  310           *  Special case non-root user here -   he/she/they/it can just print
 309  311           *                                      stats
 310  312           */
 311  313  
 312  314          if (geteuid()) {
 313  315                  if (argc != 2 || strcmp(argv[1], "-g")) {
 314  316                          (void) fprintf(stderr,
 315  317                              gettext("Must be root to use any option "
 316  318                              "other than -g.\n\n"));
 317  319                          usage(argv[0]);
 318  320                  }
 319  321  
 320  322                  if ((__ns_ldap_cache_ping() != NS_CACHE_SUCCESS) ||
 321  323                      (client_getadmin(¤t_admin) != 0)) {
 322  324                          (void) fprintf(stderr,
 323  325                              gettext("%s doesn't appear to be running.\n"),
 324  326                              argv[0]);
 325  327                          exit(1);
 326  328                  }
 327  329                  (void) client_showstats(¤t_admin);
 328  330                  exit(0);
 329  331          }
 330  332  
 331  333  
 332  334  
 333  335          /*
 334  336           *  Determine if there is already a daemon running
 335  337           */
 336  338  
 337  339          will_become_server = (__ns_ldap_cache_ping() != NS_CACHE_SUCCESS);
 338  340  
 339  341          /*
 340  342           *  load normal config file
 341  343           */
 342  344  
 343  345          if (will_become_server) {
 344  346                  static const ldap_stat_t defaults = {
 345  347                          0,              /* stat */
 346  348                          DEFAULTTTL};    /* ttl */
 347  349  
 348  350                  current_admin.ldap_stat = defaults;
 349  351                  (void) strcpy(current_admin.logfile, LOGFILE);
 350  352          } else {
 351  353                  if (client_getadmin(¤t_admin)) {
 352  354                          (void) fprintf(stderr, gettext("Cannot contact %s "
 353  355                              "properly(?)\n"), argv[0]);
 354  356                          exit(1);
 355  357                  }
 356  358          }
 357  359  
 358  360  #ifndef SLP
 359  361          while ((opt = getopt(argc, argv, "fKgl:r:d:")) != EOF) {
 360  362  #else
 361  363          while ((opt = getopt(argc, argv, "fKgs:l:r:d:")) != EOF) {
 362  364  #endif /* SLP */
 363  365                  ldap_stat_t     *cache;
 364  366  
 365  367                  switch (opt) {
 366  368                  case 'K':
 367  369                          client_killserver();
 368  370                          exit(0);
 369  371                          break;
 370  372                  case 'g':
 371  373                          showstats++;
 372  374                          break;
 373  375                  case 'f':
 374  376                          dofg++;
 375  377                          break;
 376  378                  case 'r':
 377  379                          doset++;
 378  380                          cache = getcacheptr("ldap");
 379  381                          if (!optarg) {
 380  382                                  errflg++;
 381  383                                  break;
 382  384                          }
 383  385                          cache->ldap_ttl = atoi(optarg);
 384  386                          break;
 385  387                  case 'l':
 386  388                          doset++;
 387  389                          (void) strlcpy(current_admin.logfile,
 388  390                              optarg, sizeof (current_admin.logfile));
 389  391                          break;
 390  392                  case 'd':
 391  393                          doset++;
 392  394                          debug_level = atoi(optarg);
 393  395                          break;
 394  396  #ifdef SLP
 395  397                  case 's':       /* undocumented: use dynamic (SLP) config */
 396  398                          use_slp = 1;
 397  399                          break;
 398  400  #endif /* SLP */
 399  401                  default:
 400  402                          errflg++;
 401  403                          break;
 402  404                  }
 403  405          }
 404  406  
 405  407          if (errflg)
 406  408                  usage(argv[0]);
 407  409  
 408  410          /*
 409  411           * will not show statistics if no daemon running
 410  412           */
 411  413          if (will_become_server && showstats) {
 412  414                  (void) fprintf(stderr,
 413  415                      gettext("%s doesn't appear to be running.\n"),
 414  416                      argv[0]);
 415  417                  exit(1);
 416  418          }
 417  419  
 418  420          if (!will_become_server) {
 419  421                  if (showstats) {
 420  422                          (void) client_showstats(¤t_admin);
 421  423                  }
 422  424                  if (doset) {
 423  425                          current_admin.debug_level = debug_level;
 424  426                          if (client_setadmin(¤t_admin) < 0) {
 425  427                                  (void) fprintf(stderr,
 426  428                                      gettext("Error during admin call\n"));
 427  429                                  exit(1);
 428  430                          }
 429  431                  }
 430  432                  if (!showstats && !doset) {
 431  433                          (void) fprintf(stderr,
 432  434                          gettext("%s already running....use '%s "
 433  435                              "-K' to stop\n"), argv[0], argv[0]);
 434  436                  }
 435  437                  exit(0);
 436  438          }
 437  439  
 438  440          /*
 439  441           *   daemon from here on
 440  442           */
 441  443  
 442  444          if (debug_level) {
 443  445                  /*
 444  446                   * we're debugging...
 445  447                   */
 446  448                  if (strlen(current_admin.logfile) == 0)
 447  449                          /*
 448  450                           * no specified log file
 449  451                           */
 450  452                          (void) strcpy(current_admin.logfile, LOGFILE);
 451  453                  (void) cachemgr_set_lf(¤t_admin, current_admin.logfile);
 452  454                  /*
 453  455                   * validate the range of debug level number
 454  456                   * and set the number to current_admin.debug_level
 455  457                   */
 456  458                  if (cachemgr_set_dl(¤t_admin, debug_level) < 0) {
 457  459                                  /*
 458  460                                   * print error messages to the screen
 459  461                                   * cachemgr_set_dl prints msgs to cachemgr.log
 460  462                                   * only
 461  463                                   */
 462  464                                  (void) fprintf(stderr,
 463  465                                  gettext("Incorrect Debug Level: %d\n"
 464  466                                  "It should be between %d and %d\n"),
 465  467                                      debug_level, DBG_OFF, MAXDEBUG);
 466  468                          exit(-1);
 467  469                  }
 468  470          } else {
 469  471                  if (strlen(current_admin.logfile) == 0)
 470  472                          (void) strcpy(current_admin.logfile, "/dev/null");
 471  473                  (void) cachemgr_set_lf(¤t_admin, current_admin.logfile);
 472  474          }
 473  475  
 474  476          if (dofg == 0)
 475  477                  detachfromtty(argv[0]);
 476  478  
 477  479          /*
 478  480           * perform some initialization
 479  481           */
 480  482  
 481  483          initialize_lookup_clearance();
 482  484  
 483  485          if (getldap_init() != 0)
 484  486                  exit(-1);
 485  487  
 486  488          /*
 487  489           * Establish our own server thread pool
 488  490           */
 489  491  
 490  492          (void) door_server_create(server_create);
 491  493          if (thr_keycreate(&server_key, server_destroy) != 0) {
 492  494                  logit("thr_keycreate() call failed\n");
 493  495                  syslog(LOG_ERR,
 494  496                      gettext("ldap_cachemgr: thr_keycreate() call failed"));
 495  497                  perror("thr_keycreate");
 496  498                  exit(-1);
 497  499          }
 498  500  
 499  501          /*
 500  502           * Create a door
 501  503           */
 502  504  
 503  505          if ((did = door_create(switcher, LDAP_CACHE_DOOR_COOKIE,
 504  506              DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
 505  507                  logit("door_create() call failed\n");
 506  508                  syslog(LOG_ERR, gettext(
 507  509                      "ldap_cachemgr: door_create() call failed"));
 508  510                  perror("door_create");
 509  511                  exit(-1);
 510  512          }
 511  513  
 512  514          /*
 513  515           * bind to file system
 514  516           */
 515  517  
 516  518          if (stat(LDAP_CACHE_DOOR, &buf) < 0) {
 517  519                  int     newfd;
 518  520  
 519  521                  if ((newfd = creat(LDAP_CACHE_DOOR, 0444)) < 0) {
 520  522                          logit("Cannot create %s:%s\n",
 521  523                              LDAP_CACHE_DOOR,
 522  524                              strerror(errno));
 523  525                          exit(1);
 524  526                  }
 525  527                  (void) close(newfd);
 526  528          }
 527  529  
 528  530          if (fattach(did, LDAP_CACHE_DOOR) < 0) {
 529  531                  if ((errno != EBUSY) ||
 530  532                      (fdetach(LDAP_CACHE_DOOR) <  0) ||
 531  533                      (fattach(did, LDAP_CACHE_DOOR) < 0)) {
 532  534                          logit("fattach() call failed\n");
 533  535                          syslog(LOG_ERR, gettext(
 534  536                              "ldap_cachemgr: fattach() call failed"));
 535  537                          perror("fattach");
 536  538                          exit(2);
 537  539                  }
 538  540          }
 539  541  
 540  542          /* catch SIGHUP revalid signals */
 541  543          sighupaction.sa_handler = getldap_revalidate;
 542  544          sighupaction.sa_flags = 0;
 543  545          (void) sigemptyset(&sighupaction.sa_mask);
 544  546          (void) sigemptyset(&myset);
 545  547          (void) sigaddset(&myset, SIGHUP);
 546  548  
 547  549          if (sigaction(SIGHUP, &sighupaction, NULL) < 0) {
 548  550                  logit("sigaction() call failed\n");
 549  551                  syslog(LOG_ERR,
 550  552                      gettext("ldap_cachemgr: sigaction() call failed"));
 551  553                  perror("sigaction");
 552  554                  exit(1);
 553  555          }
 554  556  
 555  557          if (thr_sigsetmask(SIG_BLOCK, &myset, NULL) < 0) {
 556  558                  logit("thr_sigsetmask() call failed\n");
 557  559                  syslog(LOG_ERR,
 558  560                      gettext("ldap_cachemgr: thr_sigsetmask() call failed"));
 559  561                  perror("thr_sigsetmask");
 560  562                  exit(1);
 561  563          }
 562  564  
 563  565          /*
 564  566           *  kick off revalidate threads only if ttl != 0
 565  567           */
 566  568  
 567  569          if (thr_create(NULL, 0, (void *(*)(void*))getldap_refresh,
 568  570              NULL, 0, NULL) != 0) {
 569  571                  logit("thr_create() call failed\n");
 570  572                  syslog(LOG_ERR,
 571  573                      gettext("ldap_cachemgr: thr_create() call failed"));
 572  574                  perror("thr_create");
 573  575                  exit(1);
 574  576          }
 575  577  
 576  578          /*
 577  579           *  kick off the thread which refreshes the server info
 578  580           */
 579  581  
 580  582          if (thr_create(NULL, 0, (void *(*)(void*))getldap_serverInfo_refresh,
 581  583              NULL, 0, NULL) != 0) {
 582  584                  logit("thr_create() call failed\n");
 583  585                  syslog(LOG_ERR,
 584  586                      gettext("ldap_cachemgr: thr_create() call failed"));
 585  587                  perror("thr_create");
 586  588                  exit(1);
 587  589          }
 588  590  
 589  591          /*
 590  592           * kick off the thread which cleans up waiting threads for
 591  593           * GETSTATUSCHANGE
 592  594           */
 593  595  
 594  596          if (thr_create(NULL, 0, chg_cleanup_waiting_threads,
 595  597              NULL, 0, NULL) != 0) {
 596  598                  logit("thr_create() chg_cleanup_waiting_threads call failed\n");
 597  599                  syslog(LOG_ERR,
 598  600                      gettext("ldap_cachemgr: thr_create() "
 599  601                      "chg_cleanup_waiting_threads call failed"));
 600  602                  exit(1);
 601  603          }
 602  604  
 603  605  #ifdef SLP
 604  606          if (use_slp) {
 605  607                  /* kick off SLP discovery thread */
 606  608                  if (thr_create(NULL, 0, (void *(*)(void *))discover,
 607  609                      (void *)&refresh, 0, NULL) != 0) {
 608  610                          logit("thr_create() call failed\n");
 609  611                          syslog(LOG_ERR, gettext("ldap_cachemgr: thr_create() "
 610  612                              "call failed"));
 611  613                          perror("thr_create");
 612  614                          exit(1);
 613  615                  }
 614  616          }
 615  617  #endif /* SLP */
 616  618  
 617  619          if (thr_sigsetmask(SIG_UNBLOCK, &myset, NULL) < 0) {
 618  620                  logit("thr_sigsetmask() call failed\n");
 619  621                  syslog(LOG_ERR,
 620  622                      gettext("ldap_cachemgr: the_sigsetmask() call failed"));
 621  623                  perror("thr_sigsetmask");
 622  624                  exit(1);
 623  625          }
 624  626  
 625  627          /*CONSTCOND*/
 626  628          while (1) {
 627  629                  (void) pause();
 628  630          }
 629  631          /* NOTREACHED */
 630  632          /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
 631  633  }
 632  634  
 633  635  
 634  636  /*
 635  637   * Before calling the alloca() function we have to be sure that we won't get
 636  638   * beyond the stack. Since we don't know the precise layout of the stack,
 637  639   * the address of an automatic of the function gives us a rough idea, plus/minus
 638  640   * a bit. We also need a bit more of stackspace after the call to be able
 639  641   * to call further functions. Even something as simple as making a system call
 640  642   * from within this function can take ~100 Bytes of stackspace.
 641  643   */
 642  644  #define SAFETY_BUFFER 32 * 1024 /* 32KB */
 643  645  
 644  646  static
 645  647  size_t
 646  648  get_data_size(LineBuf *config_info, int *err_code)
 647  649  {
 648  650          size_t          configSize = sizeof (ldap_return_t);
 649  651          dataunion       *buf = NULL; /* For the 'sizeof' purpose */
 650  652  
 651  653          if (config_info->str != NULL &&
 652  654              config_info->len >= sizeof (buf->data.ldap_ret.ldap_u.config)) {
 653  655                  configSize = sizeof (buf->space) +
 654  656                      config_info->len -
 655  657                      sizeof (buf->data.ldap_ret.ldap_u.config);
 656  658  
 657  659                  if (!stack_inbounds((char *)&buf -
 658  660                      (configSize + SAFETY_BUFFER))) {
 659  661                          /*
 660  662                           * We do not have enough space on the stack
 661  663                           * to accomodate the whole DUAProfile
 662  664                           */
 663  665                          logit("The DUAProfile is too big. There is not enough "
 664  666                              "space to process it. Ignoring it.\n");
 665  667                          syslog(LOG_ERR, gettext("ldap_cachemgr: The DUAProfile "
 666  668                              "is too big. There is not enough space "
 667  669                              "to process it. Ignoring it."));
 668  670  
 669  671                          *err_code = NS_CACHE_SERVERERROR;
 670  672  
 671  673                          free(config_info->str);
 672  674                          config_info->str = NULL;
 673  675                          config_info->len = 0;
 674  676                          configSize = sizeof (ldap_return_t);
 675  677                  }
 676  678          }
 677  679  
 678  680          return (configSize);
 679  681  }
 680  682  
 681  683  /*ARGSUSED*/
 682  684  static void
 683  685  switcher(void *cookie, char *argp, size_t arg_size,
 684  686      door_desc_t *dp, uint_t n_desc)
 685  687  {
 686  688  #define GETSIZE 1000
 687  689  #define ALLOCATE 1001
 688  690  
 689  691          ldap_call_t     *ptr = (ldap_call_t *)argp;
 690  692          ucred_t         *uc = NULL;
 691  693  
 692  694          LineBuf         configInfo;
 693  695          dataunion       *buf = NULL;
 694  696  
 695  697          /*
 696  698           * By default the size of  a buffer to be passed down to a client
 697  699           * is equal to the size of the ldap_return_t structure. We need
 698  700           * a bigger buffer in a few cases.
 699  701           */
 700  702          size_t          configSize = sizeof (ldap_return_t);
 701  703          int             ldapErrno = 0, state, callnumber;
 702  704          struct {
 703  705                  void    *begin;
 704  706                  size_t  size;
 705  707                  uint8_t destroy;
 706  708          } dataSource;
 707  709  
 708  710          if (argp == DOOR_UNREF_DATA) {
 709  711                  logit("Door Slam... invalid door param\n");
 710  712                  syslog(LOG_ERR, gettext("ldap_cachemgr: Door Slam... "
 711  713                      "invalid door param"));
 712  714                  (void) printf(gettext("Door Slam... invalid door param\n"));
 713  715                  exit(0);
 714  716          }
 715  717  
 716  718          if (ptr == NULL) { /* empty door call */
 717  719                  (void) door_return(NULL, 0, 0, 0); /* return the favor */
 718  720          }
 719  721  
 720  722          bzero(&dataSource, sizeof (dataSource));
 721  723  
 722  724          /*
 723  725           * We presume that sizeof (ldap_return_t) bytes are always available
 724  726           * on the stack
 725  727           */
 726  728          callnumber = ptr->ldap_callnumber;
 727  729  
 728  730          switch (callnumber) {
 729  731                  case NULLCALL:
 730  732                          /*
 731  733                           * Just a 'ping'. Use the default size
 732  734                           * of the buffer and set the
 733  735                           * 'OK' error code.
 734  736                           */
 735  737                          state = ALLOCATE;
 736  738                          break;
 737  739                  case GETLDAPCONFIG:
 738  740                          /*
 739  741                           * Get the current LDAP configuration.
 740  742                           * Since this is dynamic data and its size can exceed
 741  743                           * the size of ldap_return_t, the next step will
 742  744                           * calculate how much space exactly is required.
 743  745                           */
 744  746                          getldap_lookup(&configInfo, ptr);
 745  747  
 746  748                          state = GETSIZE;
 747  749                          break;
 748  750                  case GETADMINCRED:
 749  751                          /*
 750  752                           * Get the current Admin Credentials (DN and password).
 751  753                           * Since this is dynamic data and its size can exceed
 752  754                           * the size of ldap_return_t, the next step will
 753  755                           * calculate how much space exactly is required.
 754  756                           */
 755  757                          getldap_admincred(&configInfo, ptr);
 756  758  
 757  759                          state = GETSIZE;
 758  760                          break;
 759  761                  case GETLDAPSERVER:
 760  762                          /*
 761  763                           * Get the root DSE for a next server in the list.
 762  764                           * Since this is dynamic data and its size can exceed
 763  765                           * the size of ldap_return_t, the next step will
 764  766                           * calculate how much space exactly is required.
 765  767                           */
 766  768                          getldap_getserver(&configInfo, ptr);
 767  769  
 768  770                          state = GETSIZE;
 769  771                          break;
 770  772                  case GETCACHESTAT:
 771  773                          /*
 772  774                           * Get the cache stattistics.
 773  775                           * Since this is dynamic data and its size can exceed
 774  776                           * the size of ldap_return_t, the next step will
 775  777                           * calculate how much space exactly is required.
 776  778                           */
 777  779                          getldap_get_cacheStat(&configInfo);
 778  780  
 779  781                          state = GETSIZE;
 780  782                          break;
 781  783                  case GETADMIN:
 782  784                          /*
 783  785                           * Get current configuration and statistics.
 784  786                           * The size of the statistics structure is less then
 785  787                           * sizeof (ldap_return_t). So specify the source
 786  788                           * where to take the info and proceed with the memory
 787  789                           * allocation.
 788  790                           */
 789  791                          state = ALLOCATE;
 790  792  
 791  793                          if (ldapErrno == 0) {
 792  794                                  dataSource.begin = ¤t_admin;
 793  795                                  dataSource.size = sizeof (current_admin);
 794  796                                  dataSource.destroy = 0;
 795  797                          }
 796  798                          break;
 797  799                  case KILLSERVER:
 798  800                          /*
 799  801                           * Process the request and proceed with the default
 800  802                           * buffer allocation.
 801  803                           */
 802  804                          if (is_root(1, "KILLSERVER", &uc))
 803  805                                  exit(0);
 804  806  
 805  807                          ldapErrno = -1;
 806  808                          state = ALLOCATE;
 807  809                          break;
 808  810                  case SETADMIN:
 809  811                          /*
 810  812                           * Process the request and proceed with the default
 811  813                           * buffer allocation.
 812  814                           */
 813  815                          if (is_root(1, "SETADMIN", &uc))
 814  816                                  ldapErrno = setadmin(ptr);
 815  817                          else
 816  818                                  ldapErrno = -1;
 817  819  
 818  820                          state = ALLOCATE;
 819  821                          break;
 820  822                  case GETCACHE:
 821  823                          /*
 822  824                           * Get the cache stattistics.
 823  825                           * Since this is dynamic data and its size can exceed
 824  826                           * the size of ldap_return_t, the next step will
 825  827                           * calculate how much space exactly is required.
 826  828                           */
 827  829                          getldap_get_cacheData(&configInfo, ptr);
 828  830  
 829  831                          state = GETSIZE;
 830  832                          break;
 831  833                  case SETCACHE:
 832  834                          /*
 833  835                           * Process the request and proceed with the default
 834  836                           * buffer allocation.
 835  837                           */
 836  838                          if (is_root(0, "SETCACHE", &uc) &&
 837  839                              is_called_from_nscd(ucred_getpid(uc))) {
 838  840                                  ldapErrno = getldap_set_cacheData(ptr);
 839  841                                  current_admin.ldap_stat.ldap_numbercalls++;
 840  842                          } else
 841  843                                  ldapErrno = -1;
 842  844  
 843  845                          if (uc != NULL)
 844  846                                  ucred_free(uc);
 845  847                          state = ALLOCATE;
 846  848                          break;
 847  849                  case ADMINMODIFY:
 848  850                          admin_modify(&configInfo, ptr);
 849  851  
 850  852                          state = GETSIZE;
 851  853                          break;
 852  854                  case GETSTATUSCHANGE:
 853  855                          /*
 854  856                           * Process the request and proceed with the default
 855  857                           * buffer allocation.
 856  858                           */
 857  859                          (void) mutex_lock(&chg_threads_num_lock);
 858  860                          chg_threads_num++;
 859  861                          if (chg_threads_num > MAX_CHG_THREADS) {
 860  862                                  chg_threads_num--;
 861  863                                  (void) mutex_unlock(&chg_threads_num_lock);
 862  864                                  ldapErrno = CHG_EXCEED_MAX_THREADS;
 863  865                                  state = ALLOCATE;
 864  866                                  break;
 865  867                          }
 866  868                          (void) mutex_unlock(&chg_threads_num_lock);
 867  869  
 868  870                          if (is_root(0, "GETSTATUSCHANGE", &uc) &&
 869  871                              is_called_from_nscd(ucred_getpid(uc))) {
 870  872                                  ldapErrno = chg_get_statusChange(
 871  873                                      &configInfo, ptr, ucred_getpid(uc));
 872  874                                  state = GETSIZE;
 873  875                          } else {
 874  876                                  ldapErrno = -1;
 875  877                                  state = ALLOCATE;
 876  878                          }
 877  879                          if (uc != NULL)
 878  880                                  ucred_free(uc);
 879  881  
 880  882                          (void) mutex_lock(&chg_threads_num_lock);
 881  883                          chg_threads_num--;
 882  884                          (void) mutex_unlock(&chg_threads_num_lock);
 883  885                          break;
 884  886                  default:
 885  887                          /*
 886  888                           * This means an unknown request type. Proceed with
 887  889                           * the default buffer allocation.
 888  890                           */
 889  891                          logit("Unknown ldap service door call op %d\n",
 890  892                              ptr->ldap_callnumber);
 891  893                          ldapErrno = -99;
 892  894  
 893  895                          state = ALLOCATE;
 894  896                          break;
 895  897          }
 896  898  
 897  899          switch (state) {
 898  900                  case GETSIZE:
 899  901                          /*
 900  902                           * This stage calculates how much data will be
 901  903                           * passed down to the client, checks if there is
 902  904                           * enough space on the stack to accommodate the data,
 903  905                           * increases the value of the configSize variable
 904  906                           * if necessary and specifies the data source.
 905  907                           * In case of any error occurred ldapErrno will be set
 906  908                           * appropriately.
 907  909                           */
 908  910                          if (configInfo.str == NULL) {
 909  911                                  ldapErrno = -1;
 910  912                          }
 911  913  
 912  914                          configSize = get_data_size(&configInfo, &ldapErrno);
 913  915  
 914  916                          if (ldapErrno == 0) {
 915  917                                  dataSource.begin = configInfo.str;
 916  918                                  dataSource.size = configInfo.len;
 917  919                                  dataSource.destroy = 1;
 918  920                          }
 919  921  
 920  922                          current_admin.ldap_stat.ldap_numbercalls++;
 921  923                          /* FALLTHRU */
 922  924                  case ALLOCATE:
 923  925                          /*
 924  926                           * Allocate a buffer of the calculated (or default) size
 925  927                           * and proceed with populating it with data.
 926  928                           */
 927  929                          buf = (dataunion *) alloca(configSize);
 928  930  
 929  931                          /*
 930  932                           * Set a return code and, if a data source is specified,
 931  933                           * copy data from the source to the buffer.
 932  934                           */
 933  935                          buf->data.ldap_ret.ldap_errno = ldapErrno;
 934  936                          buf->data.ldap_ret.ldap_return_code = ldapErrno;
 935  937                          buf->data.ldap_ret.ldap_bufferbytesused = configSize;
 936  938  
 937  939                          if (dataSource.begin != NULL) {
 938  940                                  (void) memcpy(buf->data.ldap_ret.ldap_u.config,
 939  941                                      dataSource.begin,
 940  942                                      dataSource.size);
 941  943                                  if (dataSource.destroy) {
 942  944                                          free(dataSource.begin);
 943  945                                  }
 944  946                          }
 945  947  
 946  948          }
 947  949          (void) door_return((char *)&buf->data,
 948  950              buf->data.ldap_ret.ldap_bufferbytesused,
 949  951              NULL,
 950  952              0);
 951  953  #undef  GETSIZE
 952  954  #undef  ALLOCATE
 953  955  }
 954  956  
 955  957  static void
 956  958  usage(char *s)
 957  959  {
 958  960          (void) fprintf(stderr,
 959  961              gettext("Usage: %s [-d debug_level] [-l logfilename]\n"), s);
 960  962          (void) fprintf(stderr, gettext("        [-K] "
 961  963              "[-r revalidate_interval] "));
 962  964  #ifndef SLP
 963  965          (void) fprintf(stderr, gettext("        [-g]\n"));
 964  966  #else
 965  967          (void) fprintf(stderr, gettext("        [-g] [-s]\n"));
 966  968  #endif /* SLP */
 967  969          exit(1);
 968  970  }
 969  971  
 970  972  
 971  973  static int      logfd = -1;
 972  974  
 973  975  static int
 974  976  cachemgr_set_lf(admin_t *ptr, char *logfile)
 975  977  {
 976  978          int     newlogfd;
 977  979  
 978  980          /*
 979  981           *  we don't really want to try and open the log file
 980  982           *  /dev/null since that will fail w/ our security fixes
 981  983           */
 982  984  
 983  985          if (logfile == NULL || *logfile == 0) {
 984  986                  /*EMPTY*/;
 985  987          } else if (strcmp(logfile, "/dev/null") == 0) {
 986  988                  (void) strcpy(current_admin.logfile, "/dev/null");
 987  989                  (void) close(logfd);
 988  990                  logfd = -1;
 989  991          } else {
 990  992                  if ((newlogfd =
 991  993                      open(logfile, O_EXCL|O_WRONLY|O_CREAT, 0644)) < 0) {
 992  994                          /*
 993  995                           * File already exists... now we need to get cute
 994  996                           * since opening a file in a world-writeable directory
 995  997                           * safely is hard = it could be a hard link or a
 996  998                           * symbolic link to a system file.
 997  999                           *
 998 1000                           */
 999 1001                          struct stat     before;
1000 1002  
1001 1003                          if (lstat(logfile, &before) < 0) {
1002 1004                                  logit("Cannot open new logfile \"%s\": %sn",
1003 1005                                      logfile, strerror(errno));
1004 1006                                  return (-1);
1005 1007                          }
1006 1008                          if (S_ISREG(before.st_mode) &&  /* no symbolic links */
1007 1009                              (before.st_nlink == 1) &&   /* no hard links */
1008 1010                              (before.st_uid == 0)) {     /* owned by root */
1009 1011                                  if ((newlogfd =
1010 1012                                      open(logfile,
1011 1013                                      O_APPEND|O_WRONLY, 0644)) < 0) {
1012 1014                                          logit("Cannot open new logfile "
1013 1015                                              "\"%s\": %s\n",
1014 1016                                              logfile, strerror(errno));
1015 1017                                          return (-1);
1016 1018                                  }
1017 1019                          } else {
1018 1020                                  logit("Cannot use specified logfile "
1019 1021                                      "\"%s\": file is/has links or isn't "
1020 1022                                      "owned by root\n", logfile);
1021 1023                                  return (-1);
1022 1024                          }
1023 1025                  }
1024 1026                  (void) strlcpy(ptr->logfile, logfile, sizeof (ptr->logfile));
1025 1027                  (void) close(logfd);
1026 1028                  logfd = newlogfd;
1027 1029                  logit("Starting ldap_cachemgr, logfile %s\n", logfile);
1028 1030          }
1029 1031          return (0);
1030 1032  }
1031 1033  
1032 1034  /*PRINTFLIKE1*/
1033 1035  void
1034 1036  logit(char *format, ...)
1035 1037  {
1036 1038          static mutex_t  loglock;
1037 1039          struct timeval  tv;
1038 1040          char            buffer[BUFSIZ];
1039 1041          va_list         ap;
1040 1042  
1041 1043          va_start(ap, format);
1042 1044  
1043 1045          if (logfd >= 0) {
1044 1046                  int     safechars;
1045 1047  
1046 1048                  (void) gettimeofday(&tv, NULL);
1047 1049                  (void) ctime_r(&tv.tv_sec, buffer, BUFSIZ);
1048 1050                  (void) snprintf(buffer+19, BUFSIZE, ".%.4ld     ",
1049 1051                      tv.tv_usec/100);
1050 1052                  safechars = sizeof (buffer) - 30;
1051 1053                  if (vsnprintf(buffer+25, safechars, format, ap) > safechars)
1052 1054                          (void) strcat(buffer, "...\n");
1053 1055                  (void) mutex_lock(&loglock);
1054 1056                  (void) write(logfd, buffer, strlen(buffer));
1055 1057                  (void) mutex_unlock(&loglock);
1056 1058          }
1057 1059          va_end(ap);
1058 1060  }
1059 1061  
1060 1062  
1061 1063  static int
1062 1064  client_getadmin(admin_t *ptr)
1063 1065  {
1064 1066          dataunion               u;
1065 1067          ldap_data_t     *dptr;
1066 1068          int             ndata;
1067 1069          int             adata;
1068 1070  
1069 1071          u.data.ldap_call.ldap_callnumber = GETADMIN;
1070 1072          ndata = sizeof (u);
1071 1073          adata = sizeof (u.data);
1072 1074          dptr = &u.data;
1073 1075  
1074 1076          if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) {
1075 1077                  return (-1);
1076 1078          }
1077 1079          (void) memcpy(ptr, dptr->ldap_ret.ldap_u.buff, sizeof (*ptr));
1078 1080  
1079 1081          return (0);
1080 1082  }
1081 1083  
1082 1084  
1083 1085  static int
1084 1086  setadmin(ldap_call_t *ptr)
1085 1087  {
1086 1088          admin_t *new;
1087 1089  
1088 1090          new = (admin_t *)ptr->ldap_u.domainname;
1089 1091  
1090 1092          /*
1091 1093           *  global admin stuff
1092 1094           */
1093 1095  
1094 1096          if ((cachemgr_set_lf(¤t_admin, new->logfile) < 0) ||
1095 1097              cachemgr_set_dl(¤t_admin, new->debug_level) < 0) {
1096 1098                  return (-1);
1097 1099          }
1098 1100  
1099 1101          if (cachemgr_set_ttl(¤t_admin.ldap_stat,
1100 1102              "ldap",
1101 1103              new->ldap_stat.ldap_ttl) < 0) {
1102 1104                  return (-1);
1103 1105          }
1104 1106  
1105 1107          return (0);
1106 1108  }
1107 1109  
1108 1110  
1109 1111  static void
1110 1112  client_killserver()
1111 1113  {
1112 1114          dataunion               u;
1113 1115          ldap_data_t             *dptr;
1114 1116          int                     ndata;
1115 1117          int                     adata;
1116 1118  
1117 1119          u.data.ldap_call.ldap_callnumber = KILLSERVER;
1118 1120          ndata = sizeof (u);
1119 1121          adata = sizeof (ldap_call_t);
1120 1122          dptr = &u.data;
1121 1123  
1122 1124          __ns_ldap_trydoorcall(&dptr, &ndata, &adata);
1123 1125  }
1124 1126  
1125 1127  
1126 1128  static int
1127 1129  client_setadmin(admin_t *ptr)
1128 1130  {
1129 1131          dataunion               u;
1130 1132          ldap_data_t             *dptr;
1131 1133          int                     ndata;
1132 1134          int                     adata;
1133 1135  
1134 1136          u.data.ldap_call.ldap_callnumber = SETADMIN;
1135 1137          (void) memcpy(u.data.ldap_call.ldap_u.domainname, ptr, sizeof (*ptr));
1136 1138          ndata = sizeof (u);
1137 1139          adata = sizeof (*ptr);
1138 1140          dptr = &u.data;
1139 1141  
1140 1142          if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) {
1141 1143                  return (-1);
1142 1144          }
1143 1145  
1144 1146          return (0);
1145 1147  }
1146 1148  
1147 1149  static int
1148 1150  client_showstats(admin_t *ptr)
1149 1151  {
1150 1152          dataunion       u;
1151 1153          ldap_data_t     *dptr;
1152 1154          int             ndata;
1153 1155          int             adata;
1154 1156          char            *rbuf, *sptr, *rest;
1155 1157  
1156 1158          /*
1157 1159           * print admin data
1158 1160           */
1159 1161          (void) printf(gettext("\ncachemgr configuration:\n"));
1160 1162          (void) printf(gettext("server debug level %10d\n"), ptr->debug_level);
1161 1163          (void) printf(gettext("server log file\t\"%s\"\n"), ptr->logfile);
1162 1164          (void) printf(gettext("number of calls to ldapcachemgr %10d\n"),
1163 1165              ptr->ldap_stat.ldap_numbercalls);
1164 1166  
1165 1167          /*
1166 1168           * get cache data statistics
1167 1169           */
1168 1170          u.data.ldap_call.ldap_callnumber = GETCACHESTAT;
1169 1171          ndata = sizeof (u);
1170 1172          adata = sizeof (ldap_call_t);
1171 1173          dptr = &u.data;
1172 1174  
1173 1175          if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) {
1174 1176                  (void) printf(
1175 1177                      gettext("\nCache data statistics not available!\n"));
1176 1178                  return (0);
1177 1179          }
1178 1180  
1179 1181          /*
1180 1182           * print cache data statistics line by line
1181 1183           */
1182 1184          (void) printf(gettext("\ncachemgr cache data statistics:\n"));
1183 1185          rbuf = dptr->ldap_ret.ldap_u.buff;
1184 1186          sptr = strtok_r(rbuf, DOORLINESEP, &rest);
1185 1187          for (;;) {
1186 1188                  (void) printf("%s\n", sptr);
1187 1189                  sptr = strtok_r(NULL, DOORLINESEP, &rest);
1188 1190                  if (sptr == NULL)
1189 1191                          break;
1190 1192          }
1191 1193          return (0);
1192 1194  }
1193 1195  
1194 1196  
1195 1197  /*
1196 1198   * detach from tty
1197 1199   */
1198 1200  static void
1199 1201  detachfromtty(char *pgm)
1200 1202  {
1201 1203          int     status;
1202 1204          pid_t   pid, wret;
1203 1205  
1204 1206          (void) close(0);
1205 1207          (void) close(1);
1206 1208          /*
1207 1209           * Block the SIGUSR1 signal
1208 1210           * just in case that the child
1209 1211           * process may run faster than
1210 1212           * the parent process and
1211 1213           * send this signal before
1212 1214           * the signal handler is ready
1213 1215           * in the parent process.
1214 1216           * This error will cause the parent
1215 1217           * to exit with the User Signal 1
1216 1218           * exit code (144).
1217 1219           */
1218 1220          (void) sighold(SIGUSR1);
1219 1221          pid = fork1();
1220 1222          switch (pid) {
1221 1223                  case (pid_t)-1:
1222 1224                          logit("detachfromtty(): fork1() call failed\n");
1223 1225                          (void) fprintf(stderr,
1224 1226                              gettext("%s: fork1() call failed.\n"),
1225 1227                              pgm);
1226 1228                          syslog(LOG_ERR,
1227 1229                              gettext("ldap_cachemgr: fork1() call failed."));
1228 1230                          exit(1);
1229 1231                          break;
1230 1232                  case 0:
1231 1233                          /*
1232 1234                           * child process does not
1233 1235                           * need to worry about
1234 1236                           * the SIGUSR1 signal
1235 1237                           */
1236 1238                          (void) sigrelse(SIGUSR1);
1237 1239                          (void) close(2);
1238 1240                          break;
1239 1241                  default:
1240 1242                          /*
1241 1243                           * Wait forever until the child process
1242 1244                           * has exited, or has signalled that at
1243 1245                           * least one server in the server list
1244 1246                           * is up.
1245 1247                           */
1246 1248                          if (signal(SIGUSR1, sig_ok_to_exit) == SIG_ERR) {
1247 1249                                  logit("detachfromtty(): "
1248 1250                                      "can't set up signal handler to "
1249 1251                                      " catch SIGUSR1.\n");
1250 1252                                  (void) fprintf(stderr,
1251 1253                                      gettext("%s: signal() call failed.\n"),
1252 1254                                      pgm);
1253 1255                                  syslog(LOG_ERR, gettext("ldap_cachemgr: "
1254 1256                                      "can't set up signal handler to "
1255 1257                                      " catch SIGUSR1."));
1256 1258                                  exit(1);
1257 1259                          }
1258 1260  
1259 1261                          /*
1260 1262                           * now unblock the SIGUSR1 signal
1261 1263                           * to handle the pending or
1262 1264                           * soon to arrive SIGUSR1 signal
1263 1265                           */
1264 1266                          (void) sigrelse(SIGUSR1);
1265 1267                          wret = waitpid(pid, &status, 0);
1266 1268  
1267 1269                          if (wret == -1) {
1268 1270                                  logit("detachfromtty(): "
1269 1271                                      "waitpid() call failed\n");
1270 1272                                  (void) fprintf(stderr,
1271 1273                                      gettext("%s: waitpid() call failed.\n"),
1272 1274                                      pgm);
1273 1275                                  syslog(LOG_ERR,
1274 1276                                      gettext("ldap_cachemgr: waitpid() "
1275 1277                                      "call failed."));
1276 1278                                  exit(1);
1277 1279                          }
1278 1280                          if (wret != pid) {
1279 1281                                  logit("detachfromtty(): "
1280 1282                                      "waitpid() returned %ld when "
1281 1283                                      "child pid was %ld\n",
1282 1284                                      wret, pid);
1283 1285                                  (void) fprintf(stderr,
1284 1286                                      gettext(
1285 1287                                      "%s: waitpid() returned %ld when "
1286 1288                                      "child pid was %ld.\n"),
1287 1289                                      pgm, wret, pid);
1288 1290                                  syslog(LOG_ERR,
1289 1291                                      gettext("ldap_cachemgr: waitpid() "
1290 1292                                      "returned different "
1291 1293                                      "child pid."));
1292 1294                                  exit(1);
1293 1295                          }
1294 1296  
1295 1297                          /* evaluate return status */
1296 1298                          if (WIFEXITED(status)) {
1297 1299                                  if (WEXITSTATUS(status) == 0) {
1298 1300                                          exit(0);
1299 1301                                  }
1300 1302                                  logit("detachfromtty(): "
1301 1303                                      "child failed (rc = %d).\n",
1302 1304                                      WEXITSTATUS(status));
1303 1305                                  (void) fprintf(stderr,
1304 1306                                      gettext("%s: failed. Please see "
1305 1307                                      "syslog for details.\n"),
1306 1308                                      pgm);
1307 1309                                  syslog(LOG_ERR,
1308 1310                                      gettext("ldap_cachemgr: failed "
1309 1311                                      "(rc = %d)."),
1310 1312                                      WEXITSTATUS(status));
1311 1313                          } else if (WIFSIGNALED(status)) {
1312 1314                                  logit("detachfromtty(): "
1313 1315                                      "child terminated by signal %d.\n",
1314 1316                                      WTERMSIG(status));
1315 1317                                  (void) fprintf(stderr,
1316 1318                                  gettext("%s: terminated by signal %d.\n"),
1317 1319                                      pgm, WTERMSIG(status));
1318 1320                                  syslog(LOG_ERR,
1319 1321                                      gettext("ldap_cachemgr: terminated by "
1320 1322                                      "signal %d.\n"),
1321 1323                                      WTERMSIG(status));
1322 1324                          } else if (WCOREDUMP(status)) {
1323 1325                                  logit("detachfromtty(): child core dumped.\n"),
1324 1326                                      (void) fprintf(stderr,
1325 1327                                      gettext("%s: core dumped.\n"),
1326 1328                                      pgm);
1327 1329                                  syslog(LOG_ERR,
1328 1330                                      gettext("ldap_cachemgr: "
1329 1331                                      "core dumped.\n"));
1330 1332                          }
1331 1333  
1332 1334                          exit(1);
1333 1335          }
1334 1336          (void) setsid();
1335 1337          if (open("/dev/null", O_RDWR, 0) != -1) {
1336 1338                  (void) dup(0);
1337 1339                  (void) dup(0);
1338 1340          }
1339 1341  }
1340 1342  
1341 1343  /*
1342 1344   * Check if the door client's euid is 0
1343 1345   *
1344 1346   * We could check for some privilege or re-design the interfaces that
1345 1347   * lead to is_root() being called so that we rely on SMF and RBAC, but
1346 1348   * we need this check only for dealing with undocumented-but-possibly-
1347 1349   * used interfaces.  Anything beyond checking for euid == 0 here would
1348 1350   * be overkill considering that those are undocumented interfaces.
1349 1351   *
1350 1352   * If free_uc is 0, the caller is responsible for freeing *ucp.
1351 1353   *
1352 1354   * return - 0 euid != 0
1353 1355   *          1 euid == 0
1354 1356   */
1355 1357  static int
1356 1358  is_root(int free_uc, char *dc_str, ucred_t **ucp)
1357 1359  {
1358 1360          int     rc;
1359 1361  
1360 1362          if (door_ucred(ucp) != 0) {
1361 1363                  rc = errno;
1362 1364                  logit("door_ucred() call failed %s\n", strerror(rc));
1363 1365                  syslog(LOG_ERR, gettext("ldap_cachemgr: door_ucred() call %s "
1364 1366                      "failed %s"), strerror(rc));
1365 1367                  return (0);
1366 1368          }
1367 1369  
1368 1370  
1369 1371          if (ucred_geteuid(*ucp) != 0) {
1370 1372  
1371 1373                  if (current_admin.debug_level >= DBG_CANT_FIND)
1372 1374                          logit("%s call failed(cred): caller pid %ld, uid %u, "
1373 1375                              "euid %u (if uid or euid is %u, it may be "
1374 1376                              "unavailable)\n", dc_str, ucred_getpid(*ucp),
1375 1377                              ucred_getruid(*ucp), ucred_geteuid(*ucp), -1);
1376 1378  
1377 1379                  rc = 0;
1378 1380          } else {
1379 1381  
1380 1382                  if (current_admin.debug_level >= DBG_ALL)
1381 1383                          logit("received %s call from pid %ld, uid %u, euid %u "
1382 1384                              "(if uid or euid is %u, it may be unavailable)\n",
1383 1385                              dc_str, ucred_getpid(*ucp), ucred_getruid(*ucp),
1384 1386                              ucred_geteuid(*ucp), -1);
1385 1387                  rc = 1;
1386 1388          }
1387 1389  
1388 1390          if (free_uc)
1389 1391                  ucred_free(*ucp);
1390 1392  
1391 1393          return (rc);
1392 1394  }
1393 1395  
1394 1396  /*
1395 1397   * Check if pid is nscd
1396 1398   *
1397 1399   * Input: pid - process id of the door client that calls ldap_cachemgr
1398 1400   *
1399 1401   * Return: 0 - No
1400 1402   *         1 - Yes
1401 1403   */
1402 1404  
1403 1405  int
1404 1406  is_called_from_nscd(pid_t pid)
1405 1407  {
1406 1408          static mutex_t  _door_lock = DEFAULTMUTEX;
1407 1409          static  int     doorfd = -1;
1408 1410          int             match;
1409 1411          door_info_t     my_door;
1410 1412  
1411 1413          /*
1412 1414           * the first time in we try and open and validate the door.
1413 1415           * the validations are that the door must have been
1414 1416           * created with the door cookie and
1415 1417           * that the file attached to the door is owned by root
1416 1418           * and readonly by user, group and other.  If any of these
1417 1419           * validations fail we refuse to use the door.
1418 1420           */
1419 1421  
1420 1422          (void) mutex_lock(&_door_lock);
1421 1423  
1422 1424  try_again:
1423 1425  
1424 1426          if (doorfd == -1) {
1425 1427  
1426 1428                  if ((doorfd = open(NAME_SERVICE_DOOR, O_RDONLY, 0))
1427 1429                      == -1) {
1428 1430                          (void) mutex_unlock(&_door_lock);
1429 1431                          return (0);
1430 1432                  }
1431 1433  
1432 1434                  if (door_info(doorfd, &my_door) == -1 ||
1433 1435                      (my_door.di_attributes & DOOR_REVOKED) ||
1434 1436                      my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
1435 1437                          /*
1436 1438                           * we should close doorfd because we just opened it
1437 1439                           */
1438 1440                          (void) close(doorfd);
1439 1441                          doorfd = -1;
1440 1442                          (void) mutex_unlock(&_door_lock);
1441 1443                          return (0);
1442 1444                  }
1443 1445          } else {
1444 1446                  /*
1445 1447                   * doorfd is cached. Double check just in case
1446 1448                   * the door server is restarted or is down.
1447 1449                   */
1448 1450                  if (door_info(doorfd, &my_door) == -1 ||
1449 1451                      my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) {
1450 1452                          /*
1451 1453                           * don't close it -
1452 1454                           * someone else has clobbered fd
1453 1455                           */
1454 1456                          doorfd = -1;
1455 1457                          goto try_again;
1456 1458                  }
1457 1459  
1458 1460                  if (my_door.di_attributes & DOOR_REVOKED) {
1459 1461                          (void) close(doorfd);
1460 1462                          doorfd = -1;    /* try and restart connection */
1461 1463                          goto try_again;
1462 1464                  }
1463 1465          }
1464 1466  
1465 1467          /*
1466 1468           * door descriptor exists and is valid
1467 1469           */
1468 1470          if (pid == my_door.di_target)
1469 1471                  match = 1;
1470 1472          else
1471 1473                  match = 0;
1472 1474  
1473 1475          (void) mutex_unlock(&_door_lock);
1474 1476  
1475 1477          return (match);
1476 1478  
1477 1479  }
1478 1480  
1479 1481  /*
1480 1482   * new_attr(name, value)
1481 1483   *
1482 1484   * create a new LDAP attribute to be sent to the server
1483 1485   */
1484 1486  static ns_ldap_attr_t *
1485 1487  new_attr(char *name, char *value)
1486 1488  {
1487 1489          ns_ldap_attr_t *tmp;
1488 1490  
1489 1491          tmp = malloc(sizeof (*tmp));
1490 1492          if (tmp != NULL) {
1491 1493                  tmp->attrname = name;
1492 1494                  tmp->attrvalue = (char **)calloc(2, sizeof (char *));
1493 1495                  if (tmp->attrvalue == NULL) {
1494 1496                          free(tmp);
1495 1497                          return (NULL);
1496 1498                  }
1497 1499                  tmp->attrvalue[0] = value;
1498 1500                  tmp->value_count = 1;
1499 1501          }
1500 1502  
1501 1503          return (tmp);
1502 1504  }
1503 1505  
1504 1506  /*
1505 1507   * Convert the flatten ldap attributes in a ns_ldap_attr_t back
1506 1508   * to an ns_ldap_attr_t array.
1507 1509   *
1508 1510   * strlist->ldap_offsets[] contains offsets to strings:
1509 1511   * "dn", <dn value>, <attr 1>, <attrval 1>, ... <attr n>, <attrval n>
1510 1512   * where n is (strlist->ldap_count/2 -1).
1511 1513   * The output ns_ldap_attr_t array has a size of (strlist->ldap_count/2)
1512 1514   * the first (strlist->ldap_count/2 -1) contains all the attribute data,
1513 1515   * the last one is a NULL pointer. DN will be extracted out and pointed
1514 1516   * to by *dn.
1515 1517   */
1516 1518  static ns_ldap_attr_t **
1517 1519  str2attrs(ldap_strlist_t *strlist, char **dn)
1518 1520  {
1519 1521          int             c;
1520 1522          int             i;
1521 1523          int             j;
1522 1524          ns_ldap_attr_t  **ret;
1523 1525  
1524 1526          c = strlist->ldap_count;
1525 1527          ret = calloc(c/2, sizeof (ns_ldap_attr_t *));
1526 1528          if (ret == NULL)
1527 1529                  return (NULL);
1528 1530          *dn = (char *)strlist + strlist->ldap_offsets[1];
1529 1531  
1530 1532          /*
1531 1533           * skip the first 'dn'/<dn value> pair, for all other attr type/value
1532 1534           * pairs, get pointers to the attr type (offset [i]) and attr value
1533 1535           * (offset [i+1]) and put in ns_ldap_attr_t at ret[j]
1534 1536           */
1535 1537          for (i = 2, j = 0; i < c; i = i + 2, j++) {
1536 1538                  ret[j] = new_attr((char *)strlist + strlist->ldap_offsets[i],
1537 1539                      (char *)strlist + strlist->ldap_offsets[i + 1]);
1538 1540          }
1539 1541          return (ret);
1540 1542  }
1541 1543  
1542 1544  static int
1543 1545  get_admin_dn(ns_cred_t *credp, int *status, ns_ldap_error_t **errorp)
1544 1546  {
1545 1547          void    **paramVal = NULL;
1546 1548          int     rc;
1547 1549  
1548 1550          /* get bind DN for shadow update */
1549 1551          rc = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDDN_P,
1550 1552              ¶mVal, errorp);
1551 1553          if (rc != NS_LDAP_SUCCESS)
1552 1554                  return (rc);
1553 1555  
1554 1556          if (paramVal == NULL || *paramVal == NULL) {
1555 1557                  rc = NS_LDAP_CONFIG;
1556 1558                  *status = NS_CONFIG_NOTALLOW;
1557 1559                  if (paramVal != NULL)
1558 1560                          (void) __ns_ldap_freeParam(¶mVal);
1559 1561                  return (rc);
1560 1562          }
1561 1563          credp->cred.unix_cred.userID = strdup((char *)*paramVal);
1562 1564          (void) __ns_ldap_freeParam(¶mVal);
1563 1565          if (credp->cred.unix_cred.userID == NULL)
1564 1566                  return (NS_LDAP_MEMORY);
1565 1567  
1566 1568          return (NS_LDAP_SUCCESS);
1567 1569  }
1568 1570  
1569 1571  /*
1570 1572   * admin_modify() does a privileged modify within the ldap_cachemgr daemon
1571 1573   * process using the admin DN/password configured with parameters
1572 1574   * NS_LDAP_ADMIN_BINDDN and NS_LDAP_ADMIN_BINDPASSWD. It will only
1573 1575   * be done if NS_LDAP_ENABLE_SHADOW_UPDATE is set to TRUE.
1574 1576   *
1575 1577   * The input ldap_call_t (*in) contains LDAP shadowAccount attributes to
1576 1578   * be modified. The data is a flatten ns_ldap_attr_t arrary stored in
1577 1579   * the strlist element of the input ldap_call_t.
1578 1580   * The output will be in LineBuf (*config_info), an ldap_admin_mod_result_t
1579 1581   * structure that contains error code, error status, and error message.
1580 1582   */
1581 1583  static void
1582 1584  admin_modify(LineBuf *config_info, ldap_call_t *in)
1583 1585  {
1584 1586          int             rc = NS_LDAP_SUCCESS;
1585 1587          int             authstried = 0;
1586 1588          int             shadow_enabled = 0;
1587 1589          char            *dn = NULL;
1588 1590          char            **certpath = NULL;
1589 1591          char            **enable_shadow = NULL;
1590 1592          ns_auth_t       **app;
1591 1593          ns_auth_t       **authpp = NULL;
1592 1594          ns_auth_t       *authp = NULL;
1593 1595          ns_cred_t       *credp = NULL;
1594 1596          char            buffer[MAXERROR];
1595 1597          const int       rlen = offsetof(ldap_admin_mod_result_t, msg);
1596 1598          int             mlen = 0;
1597 1599          const int       msgmax = MAXERROR - rlen;
1598 1600          int             status = 0;
1599 1601          ucred_t         *uc = NULL;
1600 1602          ldap_strlist_t  *strlist;
1601 1603          ns_ldap_attr_t  **attrs = NULL;
1602 1604          ns_ldap_error_t *error = NULL;
1603 1605          ldap_admin_mod_result_t *result;
1604 1606  
1605 1607          (void) memset((char *)config_info, 0, sizeof (LineBuf));
1606 1608  
1607 1609          /* only root or an ALL privs user can do admin modify */
1608 1610          if (is_root_or_all_privs("ADMINMODIFY", &uc) == 0) {
1609 1611                  mlen = snprintf(buffer, msgmax, "%s",
1610 1612                      gettext("shadow update by a non-root and no ALL privilege "
1611 1613                      "user not allowed"));
1612 1614                  rc = NS_LDAP_CONFIG;
1613 1615                  goto out;
1614 1616          }
1615 1617  
1616 1618          /* check to see if shadow update is enabled */
1617 1619          rc = __ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P,
1618 1620              (void ***)&enable_shadow, &error);
1619 1621          if (rc != NS_LDAP_SUCCESS)
1620 1622                  goto out;
1621 1623          if (enable_shadow != NULL && *enable_shadow != NULL) {
1622 1624                  shadow_enabled = (*(int *)enable_shadow[0] ==
1623 1625                      NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE);
1624 1626          }
1625 1627          if (enable_shadow != NULL)
1626 1628                  (void) __ns_ldap_freeParam((void ***)&enable_shadow);
1627 1629          if (shadow_enabled == 0) {
1628 1630                  rc = NS_LDAP_CONFIG;
1629 1631                  status = NS_CONFIG_NOTALLOW;
1630 1632                  mlen = snprintf(buffer, msgmax, "%s",
1631 1633                      gettext("shadow update not enabled"));
1632 1634                  goto out;
1633 1635          }
1634 1636  
1635 1637          /* convert attributes in string buffer into an ldap attribute array */
1636 1638          strlist = &in->ldap_u.strlist;
1637 1639          attrs = str2attrs(strlist, &dn);
1638 1640          if (attrs == NULL || *attrs == NULL || dn == NULL || *dn == '\0') {
1639 1641                  rc = NS_LDAP_INVALID_PARAM;
1640 1642                  goto out;
1641 1643          }
1642 1644  
1643 1645          if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) {
1644 1646                  rc = NS_LDAP_MEMORY;
1645 1647                  goto out;
1646 1648          }
1647 1649  
1648 1650          /* get host certificate path, if one is configured */
1649 1651          rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
1650 1652              (void ***)&certpath, &error);
1651 1653          if (rc != NS_LDAP_SUCCESS)
1652 1654                  goto out;
1653 1655          if (certpath != NULL && *certpath != NULL) {
1654 1656                  credp->hostcertpath = strdup(*certpath);
1655 1657                  if (credp->hostcertpath == NULL)
1656 1658                          rc = NS_LDAP_MEMORY;
1657 1659          }
1658 1660          if (certpath != NULL)
1659 1661                  (void) __ns_ldap_freeParam((void ***)&certpath);
1660 1662          if (rc != NS_LDAP_SUCCESS)
1661 1663                  goto out;
1662 1664  
1663 1665          /* Load the service specific authentication method */
1664 1666          rc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
1665 1667              &error);
1666 1668          if (rc != NS_LDAP_SUCCESS) {
1667 1669                  if (credp->hostcertpath != NULL)
1668 1670                          free(credp->hostcertpath);
1669 1671                  goto out;
1670 1672          }
1671 1673  
1672 1674          /*
1673 1675           * if authpp is null, there is no serviceAuthenticationMethod
1674 1676           * try default authenticationMethod
1675 1677           */
1676 1678          if (authpp == NULL) {
1677 1679                  rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
1678 1680                      &error);
1679 1681                  if (rc != NS_LDAP_SUCCESS)
1680 1682                          goto out;
1681 1683          }
1682 1684  
1683 1685          /*
1684 1686           * if authpp is still null, then can not authenticate, syslog
1685 1687           * error message and return error
1686 1688           */
1687 1689          if (authpp == NULL) {
1688 1690                  rc = NS_LDAP_CONFIG;
1689 1691                  mlen = snprintf(buffer, msgmax, "%s",
1690 1692                      gettext("No legal LDAP authentication method configured"));
1691 1693                  goto out;
1692 1694          }
1693 1695  
1694 1696          /*
1695 1697           * Walk the array and try all authentication methods in order except
1696 1698           * for "none".
1697 1699           */
1698 1700          for (app = authpp; *app; app++) {
1699 1701                  authp = *app;
1700 1702                  if (authp->type == NS_LDAP_AUTH_NONE)
1701 1703                          continue;
1702 1704                  authstried++;
1703 1705                  credp->auth.type = authp->type;
1704 1706                  credp->auth.tlstype = authp->tlstype;
1705 1707                  credp->auth.saslmech = authp->saslmech;
1706 1708                  credp->auth.saslopt = authp->saslopt;
1707 1709  
1708 1710                  /*
1709 1711                   * For GSSAPI, host credential will be used. No admin
1710 1712                   * DN is needed. For other authentication methods,
1711 1713                   * we need to set admin.
1712 1714                   */
1713 1715                  if (credp->auth.saslmech != NS_LDAP_SASL_GSSAPI) {
1714 1716                          if ((rc = get_admin_dn(credp, &status,
1715 1717                              &error)) != NS_LDAP_SUCCESS) {
1716 1718                                  if (error != NULL)
1717 1719                                          goto out;
1718 1720                                  if (status == NS_CONFIG_NOTALLOW) {
1719 1721                                          mlen = snprintf(buffer, msgmax, "%s",
1720 1722                                              gettext("Admin bind DN not "
1721 1723                                              "configured"));
1722 1724                                          goto out;
1723 1725                                  }
1724 1726                          }
1725 1727                  }
1726 1728  
1727 1729                  rc = __ns_ldap_repAttr(NS_ADMIN_SHADOW_UPDATE, dn,
1728 1730                      (const ns_ldap_attr_t * const *)attrs,
1729 1731                      credp, 0, &error);
1730 1732                  if (rc == NS_LDAP_SUCCESS)
1731 1733                          goto out;
1732 1734  
1733 1735                  /*
1734 1736                   * Other errors might need to be added to this list, for
1735 1737                   * the current supported mechanisms this is sufficient.
1736 1738                   */
1737 1739                  if (rc == NS_LDAP_INTERNAL &&
1738 1740                      error->pwd_mgmt.status == NS_PASSWD_GOOD &&
1739 1741                      (error->status == LDAP_INAPPROPRIATE_AUTH ||
1740 1742                      error->status == LDAP_INVALID_CREDENTIALS))
1741 1743                          goto out;
1742 1744  
1743 1745                  /*
1744 1746                   * If there is error related to password policy,
1745 1747                   * return it to caller.
1746 1748                   */
1747 1749                  if (rc == NS_LDAP_INTERNAL &&
1748 1750                      error->pwd_mgmt.status != NS_PASSWD_GOOD) {
1749 1751                          rc = NS_LDAP_CONFIG;
1750 1752                          status = NS_CONFIG_NOTALLOW;
1751 1753                          (void) __ns_ldap_freeError(&error);
1752 1754                          mlen = snprintf(buffer, msgmax, "%s",
1753 1755                              gettext("update failed due to "
1754 1756                              "password policy on server (%d)"),
1755 1757                              error->pwd_mgmt.status);
1756 1758                          goto out;
1757 1759                  }
1758 1760  
1759 1761                  /* we don't really care about the error, just clean it up */
1760 1762                  if (error)
1761 1763                          (void) __ns_ldap_freeError(&error);
1762 1764          }
1763 1765          if (authstried == 0) {
1764 1766                  rc = NS_LDAP_CONFIG;
1765 1767                  mlen = snprintf(buffer, msgmax, "%s",
1766 1768                      gettext("No legal LDAP authentication method configured"));
1767 1769                  goto out;
1768 1770          }
1769 1771  
1770 1772          rc = NS_LDAP_OP_FAILED;
1771 1773  
1772 1774  out:
1773 1775          if (credp != NULL)
1774 1776                  (void) __ns_ldap_freeCred(&credp);
1775 1777  
1776 1778          if (authpp != NULL)
1777 1779                  (void) __ns_ldap_freeParam((void ***)&authpp);
1778 1780  
1779 1781          if (error != NULL) {
1780 1782                  mlen = snprintf(buffer, msgmax, "%s", error->message);
1781 1783                  status = error->status;
1782 1784                  (void) __ns_ldap_freeError(&error);
1783 1785          }
1784 1786  
1785 1787          if (attrs != NULL) {
1786 1788                  int i;
1787 1789                  for (i = 0; attrs[i]; i++) {
1788 1790                          free(attrs[i]->attrvalue);
1789 1791                          free(attrs[i]);
1790 1792                  }
1791 1793          }
1792 1794  
1793 1795          config_info->len = rlen + mlen + 1;
1794 1796          config_info->str = malloc(config_info->len);
1795 1797          if (config_info->str == NULL) {
1796 1798                  config_info->len = 0;
1797 1799                  return;
1798 1800          }
1799 1801          result = (ldap_admin_mod_result_t *)config_info->str;
1800 1802          result->ns_err = rc;
1801 1803          result->status = status;
1802 1804          if (mlen != 0) {
1803 1805                  result->msg_size = mlen + 1;
1804 1806                  (void) strcpy(config_info->str + rlen, buffer);
1805 1807          }
1806 1808  }
1807 1809  
1808 1810  /*
1809 1811   * Check to see if the door client's euid is 0 or if it has ALL zone privilege.
1810 1812   * return - 0 No or error
1811 1813   *          1 Yes
1812 1814   */
1813 1815  int
1814 1816  is_root_or_all_privs(char *dc_str, ucred_t **ucp)
1815 1817  {
1816 1818          const priv_set_t *ps;   /* door client */
1817 1819          priv_set_t *zs;         /* zone */
1818 1820          int rc = 0;
1819 1821  
1820 1822          *ucp = NULL;
1821 1823  
1822 1824          /* no more to do if door client's euid is 0 */
1823 1825          if (is_root(0, dc_str, ucp) == 1) {
1824 1826                  ucred_free(*ucp);
1825 1827                  return (1);
1826 1828          }
1827 1829  
1828 1830          /* error if couldn't get the ucred_t */
1829 1831          if (*ucp == NULL)
1830 1832                  return (0);
1831 1833  
1832 1834          if ((ps = ucred_getprivset(*ucp, PRIV_EFFECTIVE)) != NULL) {
1833 1835                  zs = priv_str_to_set("zone", ",", NULL);
1834 1836                  if (priv_isequalset(ps, zs))
1835 1837                          rc = 1; /* has all zone privs */
1836 1838                  else {
1837 1839                          if (current_admin.debug_level >= DBG_CANT_FIND)
1838 1840                                  logit("%s call failed (no all zone privs): "
1839 1841                                      "caller pid %ld, uid %u, euid %u "
1840 1842                                      "(if uid or euid is %u, it may "
1841 1843                                      "be unavailable)\n", dc_str,
1842 1844                                      ucred_getpid(*ucp), ucred_getruid(*ucp),
1843 1845                                      ucred_geteuid(*ucp), -1);
1844 1846                  }
1845 1847                  priv_freeset(zs);
1846 1848          }
1847 1849  
1848 1850          ucred_free(*ucp);
1849 1851          return (rc);
1850 1852  }
  
    | 
      ↓ open down ↓ | 
    1570 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX