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