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 int 274 main(int argc, char ** argv) 275 { 276 int did; 277 int opt; 278 int errflg = 0; 279 int showstats = 0; 280 int doset = 0; 281 int dofg = 0; 282 struct stat buf; 283 sigset_t myset; 284 struct sigaction sighupaction; 285 static void client_killserver(); 286 int debug_level = 0; 287 288 /* setup for localization */ 289 (void) setlocale(LC_ALL, ""); 290 (void) textdomain(TEXT_DOMAIN); 291 292 openlog("ldap_cachemgr", LOG_PID, LOG_DAEMON); 293 294 if (chdir(NSLDAPDIRECTORY) < 0) { 295 (void) fprintf(stderr, gettext("chdir(\"%s\") failed: %s\n"), 296 NSLDAPDIRECTORY, strerror(errno)); 297 exit(1); 298 } 299 300 /* 301 * Correctly set file mode creation mask, so to make the new files 302 * created for door calls being readable by all. 303 */ 304 (void) umask(0); 305 306 /* 307 * Special case non-root user here - he/she/they/it can just print 308 * stats 309 */ 310 311 if (geteuid()) { 312 if (argc != 2 || strcmp(argv[1], "-g")) { 313 (void) fprintf(stderr, 314 gettext("Must be root to use any option " 315 "other than -g.\n\n")); 316 usage(argv[0]); 317 } 318 319 if ((__ns_ldap_cache_ping() != NS_CACHE_SUCCESS) || 320 (client_getadmin(¤t_admin) != 0)) { 321 (void) fprintf(stderr, 322 gettext("%s doesn't appear to be running.\n"), 323 argv[0]); 324 exit(1); 325 } 326 (void) client_showstats(¤t_admin); 327 exit(0); 328 } 329 330 331 332 /* 333 * Determine if there is already a daemon running 334 */ 335 336 will_become_server = (__ns_ldap_cache_ping() != NS_CACHE_SUCCESS); 337 338 /* 339 * load normal config file 340 */ 341 342 if (will_become_server) { 343 static const ldap_stat_t defaults = { 344 0, /* stat */ 345 DEFAULTTTL}; /* ttl */ 346 347 current_admin.ldap_stat = defaults; 348 (void) strcpy(current_admin.logfile, LOGFILE); 349 } else { 350 if (client_getadmin(¤t_admin)) { 351 (void) fprintf(stderr, gettext("Cannot contact %s " 352 "properly(?)\n"), argv[0]); 353 exit(1); 354 } 355 } 356 357 #ifndef SLP 358 while ((opt = getopt(argc, argv, "fKgl:r:d:")) != EOF) { 359 #else 360 while ((opt = getopt(argc, argv, "fKgs:l:r:d:")) != EOF) { 361 #endif /* SLP */ 362 ldap_stat_t *cache; 363 364 switch (opt) { 365 case 'K': 366 client_killserver(); 367 exit(0); 368 break; 369 case 'g': 370 showstats++; 371 break; 372 case 'f': 373 dofg++; 374 break; 375 case 'r': 376 doset++; 377 cache = getcacheptr("ldap"); 378 if (!optarg) { 379 errflg++; 380 break; 381 } 382 cache->ldap_ttl = atoi(optarg); 383 break; 384 case 'l': 385 doset++; 386 (void) strlcpy(current_admin.logfile, 387 optarg, sizeof (current_admin.logfile)); 388 break; 389 case 'd': 390 doset++; 391 debug_level = atoi(optarg); 392 break; 393 #ifdef SLP 394 case 's': /* undocumented: use dynamic (SLP) config */ 395 use_slp = 1; 396 break; 397 #endif /* SLP */ 398 default: 399 errflg++; 400 break; 401 } 402 } 403 404 if (errflg) 405 usage(argv[0]); 406 407 /* 408 * will not show statistics if no daemon running 409 */ 410 if (will_become_server && showstats) { 411 (void) fprintf(stderr, 412 gettext("%s doesn't appear to be running.\n"), 413 argv[0]); 414 exit(1); 415 } 416 417 if (!will_become_server) { 418 if (showstats) { 419 (void) client_showstats(¤t_admin); 420 } 421 if (doset) { 422 current_admin.debug_level = debug_level; 423 if (client_setadmin(¤t_admin) < 0) { 424 (void) fprintf(stderr, 425 gettext("Error during admin call\n")); 426 exit(1); 427 } 428 } 429 if (!showstats && !doset) { 430 (void) fprintf(stderr, 431 gettext("%s already running....use '%s " 432 "-K' to stop\n"), argv[0], argv[0]); 433 } 434 exit(0); 435 } 436 437 /* 438 * daemon from here on 439 */ 440 441 if (debug_level) { 442 /* 443 * we're debugging... 444 */ 445 if (strlen(current_admin.logfile) == 0) 446 /* 447 * no specified log file 448 */ 449 (void) strcpy(current_admin.logfile, LOGFILE); 450 else 451 (void) cachemgr_set_lf(¤t_admin, 452 current_admin.logfile); 453 /* 454 * validate the range of debug level number 455 * and set the number to current_admin.debug_level 456 */ 457 if (cachemgr_set_dl(¤t_admin, debug_level) < 0) { 458 /* 459 * print error messages to the screen 460 * cachemgr_set_dl prints msgs to cachemgr.log 461 * only 462 */ 463 (void) fprintf(stderr, 464 gettext("Incorrect Debug Level: %d\n" 465 "It should be between %d and %d\n"), 466 debug_level, DBG_OFF, MAXDEBUG); 467 exit(-1); 468 } 469 } else { 470 if (strlen(current_admin.logfile) == 0) 471 (void) strcpy(current_admin.logfile, "/dev/null"); 472 (void) cachemgr_set_lf(¤t_admin, 473 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 { 1409 static mutex_t _door_lock = DEFAULTMUTEX; 1410 static int doorfd = -1; 1411 int match; 1412 door_info_t my_door; 1413 1414 /* 1415 * the first time in we try and open and validate the door. 1416 * the validations are that the door must have been 1417 * created with the door cookie and 1418 * that the file attached to the door is owned by root 1419 * and readonly by user, group and other. If any of these 1420 * validations fail we refuse to use the door. 1421 */ 1422 1423 (void) mutex_lock(&_door_lock); 1424 1425 try_again: 1426 1427 if (doorfd == -1) { 1428 1429 if ((doorfd = open(NAME_SERVICE_DOOR, O_RDONLY, 0)) 1430 == -1) { 1431 (void) mutex_unlock(&_door_lock); 1432 return (0); 1433 } 1434 1435 if (door_info(doorfd, &my_door) == -1 || 1436 (my_door.di_attributes & DOOR_REVOKED) || 1437 my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { 1438 /* 1439 * we should close doorfd because we just opened it 1440 */ 1441 (void) close(doorfd); 1442 doorfd = -1; 1443 (void) mutex_unlock(&_door_lock); 1444 return (0); 1445 } 1446 } else { 1447 /* 1448 * doorfd is cached. Double check just in case 1449 * the door server is restarted or is down. 1450 */ 1451 if (door_info(doorfd, &my_door) == -1 || 1452 my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { 1453 /* 1454 * don't close it - 1455 * someone else has clobbered fd 1456 */ 1457 doorfd = -1; 1458 goto try_again; 1459 } 1460 1461 if (my_door.di_attributes & DOOR_REVOKED) { 1462 (void) close(doorfd); 1463 doorfd = -1; /* try and restart connection */ 1464 goto try_again; 1465 } 1466 } 1467 1468 /* 1469 * door descriptor exists and is valid 1470 */ 1471 if (pid == my_door.di_target) 1472 match = 1; 1473 else 1474 match = 0; 1475 1476 (void) mutex_unlock(&_door_lock); 1477 1478 return (match); 1479 1480 } 1481 1482 /* 1483 * new_attr(name, value) 1484 * 1485 * create a new LDAP attribute to be sent to the server 1486 */ 1487 static ns_ldap_attr_t * 1488 new_attr(char *name, char *value) 1489 { 1490 ns_ldap_attr_t *tmp; 1491 1492 tmp = malloc(sizeof (*tmp)); 1493 if (tmp != NULL) { 1494 tmp->attrname = name; 1495 tmp->attrvalue = (char **)calloc(2, sizeof (char *)); 1496 if (tmp->attrvalue == NULL) { 1497 free(tmp); 1498 return (NULL); 1499 } 1500 tmp->attrvalue[0] = value; 1501 tmp->value_count = 1; 1502 } 1503 1504 return (tmp); 1505 } 1506 1507 /* 1508 * Convert the flatten ldap attributes in a ns_ldap_attr_t back 1509 * to an ns_ldap_attr_t array. 1510 * 1511 * strlist->ldap_offsets[] contains offsets to strings: 1512 * "dn", <dn value>, <attr 1>, <attrval 1>, ... <attr n>, <attrval n> 1513 * where n is (strlist->ldap_count/2 -1). 1514 * The output ns_ldap_attr_t array has a size of (strlist->ldap_count/2) 1515 * the first (strlist->ldap_count/2 -1) contains all the attribute data, 1516 * the last one is a NULL pointer. DN will be extracted out and pointed 1517 * to by *dn. 1518 */ 1519 static ns_ldap_attr_t ** 1520 str2attrs(ldap_strlist_t *strlist, char **dn) 1521 { 1522 int c; 1523 int i; 1524 int j; 1525 ns_ldap_attr_t **ret; 1526 1527 c = strlist->ldap_count; 1528 ret = calloc(c/2, sizeof (ns_ldap_attr_t *)); 1529 if (ret == NULL) 1530 return (NULL); 1531 *dn = (char *)strlist + strlist->ldap_offsets[1]; 1532 1533 /* 1534 * skip the first 'dn'/<dn value> pair, for all other attr type/value 1535 * pairs, get pointers to the attr type (offset [i]) and attr value 1536 * (offset [i+1]) and put in ns_ldap_attr_t at ret[j] 1537 */ 1538 for (i = 2, j = 0; i < c; i = i + 2, j++) { 1539 ret[j] = new_attr((char *)strlist + strlist->ldap_offsets[i], 1540 (char *)strlist + strlist->ldap_offsets[i + 1]); 1541 } 1542 return (ret); 1543 } 1544 1545 static int 1546 get_admin_dn(ns_cred_t *credp, int *status, ns_ldap_error_t **errorp) 1547 { 1548 void **paramVal = NULL; 1549 int rc; 1550 1551 /* get bind DN for shadow update */ 1552 rc = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDDN_P, 1553 ¶mVal, errorp); 1554 if (rc != NS_LDAP_SUCCESS) 1555 return (rc); 1556 1557 if (paramVal == NULL || *paramVal == NULL) { 1558 rc = NS_LDAP_CONFIG; 1559 *status = NS_CONFIG_NOTALLOW; 1560 if (paramVal != NULL) 1561 (void) __ns_ldap_freeParam(¶mVal); 1562 return (rc); 1563 } 1564 credp->cred.unix_cred.userID = strdup((char *)*paramVal); 1565 (void) __ns_ldap_freeParam(¶mVal); 1566 if (credp->cred.unix_cred.userID == NULL) 1567 return (NS_LDAP_MEMORY); 1568 1569 return (NS_LDAP_SUCCESS); 1570 } 1571 1572 /* 1573 * admin_modify() does a privileged modify within the ldap_cachemgr daemon 1574 * process using the admin DN/password configured with parameters 1575 * NS_LDAP_ADMIN_BINDDN and NS_LDAP_ADMIN_BINDPASSWD. It will only 1576 * be done if NS_LDAP_ENABLE_SHADOW_UPDATE is set to TRUE. 1577 * 1578 * The input ldap_call_t (*in) contains LDAP shadowAccount attributes to 1579 * be modified. The data is a flatten ns_ldap_attr_t arrary stored in 1580 * the strlist element of the input ldap_call_t. 1581 * The output will be in LineBuf (*config_info), an ldap_admin_mod_result_t 1582 * structure that contains error code, error status, and error message. 1583 */ 1584 static void 1585 admin_modify(LineBuf *config_info, ldap_call_t *in) 1586 { 1587 int rc = NS_LDAP_SUCCESS; 1588 int authstried = 0; 1589 int shadow_enabled = 0; 1590 char *dn = NULL; 1591 char **certpath = NULL; 1592 char **enable_shadow = NULL; 1593 ns_auth_t **app; 1594 ns_auth_t **authpp = NULL; 1595 ns_auth_t *authp = NULL; 1596 ns_cred_t *credp = NULL; 1597 char buffer[MAXERROR]; 1598 const int rlen = offsetof(ldap_admin_mod_result_t, msg); 1599 int mlen = 0; 1600 const int msgmax = MAXERROR - rlen; 1601 int status = 0; 1602 ucred_t *uc = NULL; 1603 ldap_strlist_t *strlist; 1604 ns_ldap_attr_t **attrs = NULL; 1605 ns_ldap_error_t *error = NULL; 1606 ldap_admin_mod_result_t *result; 1607 1608 (void) memset((char *)config_info, 0, sizeof (LineBuf)); 1609 1610 /* only root or an ALL privs user can do admin modify */ 1611 if (is_root_or_all_privs("ADMINMODIFY", &uc) == 0) { 1612 mlen = snprintf(buffer, msgmax, "%s", 1613 gettext("shadow update by a non-root and no ALL privilege " 1614 "user not allowed")); 1615 rc = NS_LDAP_CONFIG; 1616 goto out; 1617 } 1618 1619 /* check to see if shadow update is enabled */ 1620 rc = __ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P, 1621 (void ***)&enable_shadow, &error); 1622 if (rc != NS_LDAP_SUCCESS) 1623 goto out; 1624 if (enable_shadow != NULL && *enable_shadow != NULL) { 1625 shadow_enabled = (*(int *)enable_shadow[0] == 1626 NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE); 1627 } 1628 if (enable_shadow != NULL) 1629 (void) __ns_ldap_freeParam((void ***)&enable_shadow); 1630 if (shadow_enabled == 0) { 1631 rc = NS_LDAP_CONFIG; 1632 status = NS_CONFIG_NOTALLOW; 1633 mlen = snprintf(buffer, msgmax, "%s", 1634 gettext("shadow update not enabled")); 1635 goto out; 1636 } 1637 1638 /* convert attributes in string buffer into an ldap attribute array */ 1639 strlist = &in->ldap_u.strlist; 1640 attrs = str2attrs(strlist, &dn); 1641 if (attrs == NULL || *attrs == NULL || dn == NULL || *dn == '\0') { 1642 rc = NS_LDAP_INVALID_PARAM; 1643 goto out; 1644 } 1645 1646 if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) { 1647 rc = NS_LDAP_MEMORY; 1648 goto out; 1649 } 1650 1651 /* get host certificate path, if one is configured */ 1652 rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 1653 (void ***)&certpath, &error); 1654 if (rc != NS_LDAP_SUCCESS) 1655 goto out; 1656 if (certpath != NULL && *certpath != NULL) { 1657 credp->hostcertpath = strdup(*certpath); 1658 if (credp->hostcertpath == NULL) 1659 rc = NS_LDAP_MEMORY; 1660 } 1661 if (certpath != NULL) 1662 (void) __ns_ldap_freeParam((void ***)&certpath); 1663 if (rc != NS_LDAP_SUCCESS) 1664 goto out; 1665 1666 /* Load the service specific authentication method */ 1667 rc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp, 1668 &error); 1669 if (rc != NS_LDAP_SUCCESS) { 1670 if (credp->hostcertpath != NULL) 1671 free(credp->hostcertpath); 1672 goto out; 1673 } 1674 1675 /* 1676 * if authpp is null, there is no serviceAuthenticationMethod 1677 * try default authenticationMethod 1678 */ 1679 if (authpp == NULL) { 1680 rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp, 1681 &error); 1682 if (rc != NS_LDAP_SUCCESS) 1683 goto out; 1684 } 1685 1686 /* 1687 * if authpp is still null, then can not authenticate, syslog 1688 * error message and return error 1689 */ 1690 if (authpp == NULL) { 1691 rc = NS_LDAP_CONFIG; 1692 mlen = snprintf(buffer, msgmax, "%s", 1693 gettext("No legal LDAP authentication method configured")); 1694 goto out; 1695 } 1696 1697 /* 1698 * Walk the array and try all authentication methods in order except 1699 * for "none". 1700 */ 1701 for (app = authpp; *app; app++) { 1702 authp = *app; 1703 if (authp->type == NS_LDAP_AUTH_NONE) 1704 continue; 1705 authstried++; 1706 credp->auth.type = authp->type; 1707 credp->auth.tlstype = authp->tlstype; 1708 credp->auth.saslmech = authp->saslmech; 1709 credp->auth.saslopt = authp->saslopt; 1710 1711 /* 1712 * For GSSAPI, host credential will be used. No admin 1713 * DN is needed. For other authentication methods, 1714 * we need to set admin. 1715 */ 1716 if (credp->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 1717 if ((rc = get_admin_dn(credp, &status, 1718 &error)) != NS_LDAP_SUCCESS) { 1719 if (error != NULL) 1720 goto out; 1721 if (status == NS_CONFIG_NOTALLOW) { 1722 mlen = snprintf(buffer, msgmax, "%s", 1723 gettext("Admin bind DN not " 1724 "configured")); 1725 goto out; 1726 } 1727 } 1728 } 1729 1730 rc = __ns_ldap_repAttr(NS_ADMIN_SHADOW_UPDATE, dn, 1731 (const ns_ldap_attr_t * const *)attrs, 1732 credp, 0, &error); 1733 if (rc == NS_LDAP_SUCCESS) 1734 goto out; 1735 1736 /* 1737 * Other errors might need to be added to this list, for 1738 * the current supported mechanisms this is sufficient. 1739 */ 1740 if (rc == NS_LDAP_INTERNAL && 1741 error->pwd_mgmt.status == NS_PASSWD_GOOD && 1742 (error->status == LDAP_INAPPROPRIATE_AUTH || 1743 error->status == LDAP_INVALID_CREDENTIALS)) 1744 goto out; 1745 1746 /* 1747 * If there is error related to password policy, 1748 * return it to caller. 1749 */ 1750 if (rc == NS_LDAP_INTERNAL && 1751 error->pwd_mgmt.status != NS_PASSWD_GOOD) { 1752 rc = NS_LDAP_CONFIG; 1753 status = NS_CONFIG_NOTALLOW; 1754 (void) __ns_ldap_freeError(&error); 1755 mlen = snprintf(buffer, msgmax, "%s", 1756 gettext("update failed due to " 1757 "password policy on server (%d)"), 1758 error->pwd_mgmt.status); 1759 goto out; 1760 } 1761 1762 /* we don't really care about the error, just clean it up */ 1763 if (error) 1764 (void) __ns_ldap_freeError(&error); 1765 } 1766 if (authstried == 0) { 1767 rc = NS_LDAP_CONFIG; 1768 mlen = snprintf(buffer, msgmax, "%s", 1769 gettext("No legal LDAP authentication method configured")); 1770 goto out; 1771 } 1772 1773 rc = NS_LDAP_OP_FAILED; 1774 1775 out: 1776 if (credp != NULL) 1777 (void) __ns_ldap_freeCred(&credp); 1778 1779 if (authpp != NULL) 1780 (void) __ns_ldap_freeParam((void ***)&authpp); 1781 1782 if (error != NULL) { 1783 mlen = snprintf(buffer, msgmax, "%s", error->message); 1784 status = error->status; 1785 (void) __ns_ldap_freeError(&error); 1786 } 1787 1788 if (attrs != NULL) { 1789 int i; 1790 for (i = 0; attrs[i]; i++) { 1791 free(attrs[i]->attrvalue); 1792 free(attrs[i]); 1793 } 1794 } 1795 1796 config_info->len = rlen + mlen + 1; 1797 config_info->str = malloc(config_info->len); 1798 if (config_info->str == NULL) { 1799 config_info->len = 0; 1800 return; 1801 } 1802 result = (ldap_admin_mod_result_t *)config_info->str; 1803 result->ns_err = rc; 1804 result->status = status; 1805 if (mlen != 0) { 1806 result->msg_size = mlen + 1; 1807 (void) strcpy(config_info->str + rlen, buffer); 1808 } 1809 } 1810 1811 /* 1812 * Check to see if the door client's euid is 0 or if it has ALL zone privilege. 1813 * return - 0 No or error 1814 * 1 Yes 1815 */ 1816 int 1817 is_root_or_all_privs(char *dc_str, ucred_t **ucp) 1818 { 1819 const priv_set_t *ps; /* door client */ 1820 priv_set_t *zs; /* zone */ 1821 int rc = 0; 1822 1823 *ucp = NULL; 1824 1825 /* no more to do if door client's euid is 0 */ 1826 if (is_root(0, dc_str, ucp) == 1) { 1827 ucred_free(*ucp); 1828 return (1); 1829 } 1830 1831 /* error if couldn't get the ucred_t */ 1832 if (*ucp == NULL) 1833 return (0); 1834 1835 if ((ps = ucred_getprivset(*ucp, PRIV_EFFECTIVE)) != NULL) { 1836 zs = priv_str_to_set("zone", ",", NULL); 1837 if (priv_isequalset(ps, zs)) 1838 rc = 1; /* has all zone privs */ 1839 else { 1840 if (current_admin.debug_level >= DBG_CANT_FIND) 1841 logit("%s call failed (no all zone privs): " 1842 "caller pid %ld, uid %u, euid %u " 1843 "(if uid or euid is %u, it may " 1844 "be unavailable)\n", dc_str, 1845 ucred_getpid(*ucp), ucred_getruid(*ucp), 1846 ucred_geteuid(*ucp), -1); 1847 } 1848 priv_freeset(zs); 1849 } 1850 1851 ucred_free(*ucp); 1852 return (rc); 1853 } 1854