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