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 } 1853