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