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 (void) cachemgr_set_lf(¤t_admin, current_admin.logfile); 452 /* 453 * validate the range of debug level number 454 * and set the number to current_admin.debug_level 455 */ 456 if (cachemgr_set_dl(¤t_admin, debug_level) < 0) { 457 /* 458 * print error messages to the screen 459 * cachemgr_set_dl prints msgs to cachemgr.log 460 * only 461 */ 462 (void) fprintf(stderr, 463 gettext("Incorrect Debug Level: %d\n" 464 "It should be between %d and %d\n"), 465 debug_level, DBG_OFF, MAXDEBUG); 466 exit(-1); 467 } 468 } else { 469 if (strlen(current_admin.logfile) == 0) 470 (void) strcpy(current_admin.logfile, "/dev/null"); 471 (void) cachemgr_set_lf(¤t_admin, current_admin.logfile); 472 } 473 474 if (dofg == 0) 475 detachfromtty(argv[0]); 476 477 /* 478 * perform some initialization 479 */ 480 481 initialize_lookup_clearance(); 482 483 if (getldap_init() != 0) 484 exit(-1); 485 486 /* 487 * Establish our own server thread pool 488 */ 489 490 (void) door_server_create(server_create); 491 if (thr_keycreate(&server_key, server_destroy) != 0) { 492 logit("thr_keycreate() call failed\n"); 493 syslog(LOG_ERR, 494 gettext("ldap_cachemgr: thr_keycreate() call failed")); 495 perror("thr_keycreate"); 496 exit(-1); 497 } 498 499 /* 500 * Create a door 501 */ 502 503 if ((did = door_create(switcher, LDAP_CACHE_DOOR_COOKIE, 504 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { 505 logit("door_create() call failed\n"); 506 syslog(LOG_ERR, gettext( 507 "ldap_cachemgr: door_create() call failed")); 508 perror("door_create"); 509 exit(-1); 510 } 511 512 /* 513 * bind to file system 514 */ 515 516 if (stat(LDAP_CACHE_DOOR, &buf) < 0) { 517 int newfd; 518 519 if ((newfd = creat(LDAP_CACHE_DOOR, 0444)) < 0) { 520 logit("Cannot create %s:%s\n", 521 LDAP_CACHE_DOOR, 522 strerror(errno)); 523 exit(1); 524 } 525 (void) close(newfd); 526 } 527 528 if (fattach(did, LDAP_CACHE_DOOR) < 0) { 529 if ((errno != EBUSY) || 530 (fdetach(LDAP_CACHE_DOOR) < 0) || 531 (fattach(did, LDAP_CACHE_DOOR) < 0)) { 532 logit("fattach() call failed\n"); 533 syslog(LOG_ERR, gettext( 534 "ldap_cachemgr: fattach() call failed")); 535 perror("fattach"); 536 exit(2); 537 } 538 } 539 540 /* catch SIGHUP revalid signals */ 541 sighupaction.sa_handler = getldap_revalidate; 542 sighupaction.sa_flags = 0; 543 (void) sigemptyset(&sighupaction.sa_mask); 544 (void) sigemptyset(&myset); 545 (void) sigaddset(&myset, SIGHUP); 546 547 if (sigaction(SIGHUP, &sighupaction, NULL) < 0) { 548 logit("sigaction() call failed\n"); 549 syslog(LOG_ERR, 550 gettext("ldap_cachemgr: sigaction() call failed")); 551 perror("sigaction"); 552 exit(1); 553 } 554 555 if (thr_sigsetmask(SIG_BLOCK, &myset, NULL) < 0) { 556 logit("thr_sigsetmask() call failed\n"); 557 syslog(LOG_ERR, 558 gettext("ldap_cachemgr: thr_sigsetmask() call failed")); 559 perror("thr_sigsetmask"); 560 exit(1); 561 } 562 563 /* 564 * kick off revalidate threads only if ttl != 0 565 */ 566 567 if (thr_create(NULL, 0, (void *(*)(void*))getldap_refresh, 568 NULL, 0, NULL) != 0) { 569 logit("thr_create() call failed\n"); 570 syslog(LOG_ERR, 571 gettext("ldap_cachemgr: thr_create() call failed")); 572 perror("thr_create"); 573 exit(1); 574 } 575 576 /* 577 * kick off the thread which refreshes the server info 578 */ 579 580 if (thr_create(NULL, 0, (void *(*)(void*))getldap_serverInfo_refresh, 581 NULL, 0, NULL) != 0) { 582 logit("thr_create() call failed\n"); 583 syslog(LOG_ERR, 584 gettext("ldap_cachemgr: thr_create() call failed")); 585 perror("thr_create"); 586 exit(1); 587 } 588 589 /* 590 * kick off the thread which cleans up waiting threads for 591 * GETSTATUSCHANGE 592 */ 593 594 if (thr_create(NULL, 0, chg_cleanup_waiting_threads, 595 NULL, 0, NULL) != 0) { 596 logit("thr_create() chg_cleanup_waiting_threads call failed\n"); 597 syslog(LOG_ERR, 598 gettext("ldap_cachemgr: thr_create() " 599 "chg_cleanup_waiting_threads call failed")); 600 exit(1); 601 } 602 603 #ifdef SLP 604 if (use_slp) { 605 /* kick off SLP discovery thread */ 606 if (thr_create(NULL, 0, (void *(*)(void *))discover, 607 (void *)&refresh, 0, NULL) != 0) { 608 logit("thr_create() call failed\n"); 609 syslog(LOG_ERR, gettext("ldap_cachemgr: thr_create() " 610 "call failed")); 611 perror("thr_create"); 612 exit(1); 613 } 614 } 615 #endif /* SLP */ 616 617 if (thr_sigsetmask(SIG_UNBLOCK, &myset, NULL) < 0) { 618 logit("thr_sigsetmask() call failed\n"); 619 syslog(LOG_ERR, 620 gettext("ldap_cachemgr: the_sigsetmask() call failed")); 621 perror("thr_sigsetmask"); 622 exit(1); 623 } 624 625 /*CONSTCOND*/ 626 while (1) { 627 (void) pause(); 628 } 629 /* NOTREACHED */ 630 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 631 } 632 633 634 /* 635 * Before calling the alloca() function we have to be sure that we won't get 636 * beyond the stack. Since we don't know the precise layout of the stack, 637 * the address of an automatic of the function gives us a rough idea, plus/minus 638 * a bit. We also need a bit more of stackspace after the call to be able 639 * to call further functions. Even something as simple as making a system call 640 * from within this function can take ~100 Bytes of stackspace. 641 */ 642 #define SAFETY_BUFFER 32 * 1024 /* 32KB */ 643 644 static 645 size_t 646 get_data_size(LineBuf *config_info, int *err_code) 647 { 648 size_t configSize = sizeof (ldap_return_t); 649 dataunion *buf = NULL; /* For the 'sizeof' purpose */ 650 651 if (config_info->str != NULL && 652 config_info->len >= sizeof (buf->data.ldap_ret.ldap_u.config)) { 653 configSize = sizeof (buf->space) + 654 config_info->len - 655 sizeof (buf->data.ldap_ret.ldap_u.config); 656 657 if (!stack_inbounds((char *)&buf - 658 (configSize + SAFETY_BUFFER))) { 659 /* 660 * We do not have enough space on the stack 661 * to accomodate the whole DUAProfile 662 */ 663 logit("The DUAProfile is too big. There is not enough " 664 "space to process it. Ignoring it.\n"); 665 syslog(LOG_ERR, gettext("ldap_cachemgr: The DUAProfile " 666 "is too big. There is not enough space " 667 "to process it. Ignoring it.")); 668 669 *err_code = NS_CACHE_SERVERERROR; 670 671 free(config_info->str); 672 config_info->str = NULL; 673 config_info->len = 0; 674 configSize = sizeof (ldap_return_t); 675 } 676 } 677 678 return (configSize); 679 } 680 681 /*ARGSUSED*/ 682 static void 683 switcher(void *cookie, char *argp, size_t arg_size, 684 door_desc_t *dp, uint_t n_desc) 685 { 686 #define GETSIZE 1000 687 #define ALLOCATE 1001 688 689 ldap_call_t *ptr = (ldap_call_t *)argp; 690 ucred_t *uc = NULL; 691 692 LineBuf configInfo; 693 dataunion *buf = NULL; 694 695 /* 696 * By default the size of a buffer to be passed down to a client 697 * is equal to the size of the ldap_return_t structure. We need 698 * a bigger buffer in a few cases. 699 */ 700 size_t configSize = sizeof (ldap_return_t); 701 int ldapErrno = 0, state, callnumber; 702 struct { 703 void *begin; 704 size_t size; 705 uint8_t destroy; 706 } dataSource; 707 708 if (argp == DOOR_UNREF_DATA) { 709 logit("Door Slam... invalid door param\n"); 710 syslog(LOG_ERR, gettext("ldap_cachemgr: Door Slam... " 711 "invalid door param")); 712 (void) printf(gettext("Door Slam... invalid door param\n")); 713 exit(0); 714 } 715 716 if (ptr == NULL) { /* empty door call */ 717 (void) door_return(NULL, 0, 0, 0); /* return the favor */ 718 } 719 720 bzero(&dataSource, sizeof (dataSource)); 721 722 /* 723 * We presume that sizeof (ldap_return_t) bytes are always available 724 * on the stack 725 */ 726 callnumber = ptr->ldap_callnumber; 727 728 switch (callnumber) { 729 case NULLCALL: 730 /* 731 * Just a 'ping'. Use the default size 732 * of the buffer and set the 733 * 'OK' error code. 734 */ 735 state = ALLOCATE; 736 break; 737 case GETLDAPCONFIG: 738 /* 739 * Get the current LDAP configuration. 740 * Since this is dynamic data and its size can exceed 741 * the size of ldap_return_t, the next step will 742 * calculate how much space exactly is required. 743 */ 744 getldap_lookup(&configInfo, ptr); 745 746 state = GETSIZE; 747 break; 748 case GETADMINCRED: 749 /* 750 * Get the current Admin Credentials (DN and password). 751 * Since this is dynamic data and its size can exceed 752 * the size of ldap_return_t, the next step will 753 * calculate how much space exactly is required. 754 */ 755 getldap_admincred(&configInfo, ptr); 756 757 state = GETSIZE; 758 break; 759 case GETLDAPSERVER: 760 /* 761 * Get the root DSE for a next server in the list. 762 * Since this is dynamic data and its size can exceed 763 * the size of ldap_return_t, the next step will 764 * calculate how much space exactly is required. 765 */ 766 getldap_getserver(&configInfo, ptr); 767 768 state = GETSIZE; 769 break; 770 case GETCACHESTAT: 771 /* 772 * Get the cache stattistics. 773 * Since this is dynamic data and its size can exceed 774 * the size of ldap_return_t, the next step will 775 * calculate how much space exactly is required. 776 */ 777 getldap_get_cacheStat(&configInfo); 778 779 state = GETSIZE; 780 break; 781 case GETADMIN: 782 /* 783 * Get current configuration and statistics. 784 * The size of the statistics structure is less then 785 * sizeof (ldap_return_t). So specify the source 786 * where to take the info and proceed with the memory 787 * allocation. 788 */ 789 state = ALLOCATE; 790 791 if (ldapErrno == 0) { 792 dataSource.begin = ¤t_admin; 793 dataSource.size = sizeof (current_admin); 794 dataSource.destroy = 0; 795 } 796 break; 797 case KILLSERVER: 798 /* 799 * Process the request and proceed with the default 800 * buffer allocation. 801 */ 802 if (is_root(1, "KILLSERVER", &uc)) 803 exit(0); 804 805 ldapErrno = -1; 806 state = ALLOCATE; 807 break; 808 case SETADMIN: 809 /* 810 * Process the request and proceed with the default 811 * buffer allocation. 812 */ 813 if (is_root(1, "SETADMIN", &uc)) 814 ldapErrno = setadmin(ptr); 815 else 816 ldapErrno = -1; 817 818 state = ALLOCATE; 819 break; 820 case GETCACHE: 821 /* 822 * Get the cache stattistics. 823 * Since this is dynamic data and its size can exceed 824 * the size of ldap_return_t, the next step will 825 * calculate how much space exactly is required. 826 */ 827 getldap_get_cacheData(&configInfo, ptr); 828 829 state = GETSIZE; 830 break; 831 case SETCACHE: 832 /* 833 * Process the request and proceed with the default 834 * buffer allocation. 835 */ 836 if (is_root(0, "SETCACHE", &uc) && 837 is_called_from_nscd(ucred_getpid(uc))) { 838 ldapErrno = getldap_set_cacheData(ptr); 839 current_admin.ldap_stat.ldap_numbercalls++; 840 } else 841 ldapErrno = -1; 842 843 if (uc != NULL) 844 ucred_free(uc); 845 state = ALLOCATE; 846 break; 847 case ADMINMODIFY: 848 admin_modify(&configInfo, ptr); 849 850 state = GETSIZE; 851 break; 852 case GETSTATUSCHANGE: 853 /* 854 * Process the request and proceed with the default 855 * buffer allocation. 856 */ 857 (void) mutex_lock(&chg_threads_num_lock); 858 chg_threads_num++; 859 if (chg_threads_num > MAX_CHG_THREADS) { 860 chg_threads_num--; 861 (void) mutex_unlock(&chg_threads_num_lock); 862 ldapErrno = CHG_EXCEED_MAX_THREADS; 863 state = ALLOCATE; 864 break; 865 } 866 (void) mutex_unlock(&chg_threads_num_lock); 867 868 if (is_root(0, "GETSTATUSCHANGE", &uc) && 869 is_called_from_nscd(ucred_getpid(uc))) { 870 ldapErrno = chg_get_statusChange( 871 &configInfo, ptr, ucred_getpid(uc)); 872 state = GETSIZE; 873 } else { 874 ldapErrno = -1; 875 state = ALLOCATE; 876 } 877 if (uc != NULL) 878 ucred_free(uc); 879 880 (void) mutex_lock(&chg_threads_num_lock); 881 chg_threads_num--; 882 (void) mutex_unlock(&chg_threads_num_lock); 883 break; 884 default: 885 /* 886 * This means an unknown request type. Proceed with 887 * the default buffer allocation. 888 */ 889 logit("Unknown ldap service door call op %d\n", 890 ptr->ldap_callnumber); 891 ldapErrno = -99; 892 893 state = ALLOCATE; 894 break; 895 } 896 897 switch (state) { 898 case GETSIZE: 899 /* 900 * This stage calculates how much data will be 901 * passed down to the client, checks if there is 902 * enough space on the stack to accommodate the data, 903 * increases the value of the configSize variable 904 * if necessary and specifies the data source. 905 * In case of any error occurred ldapErrno will be set 906 * appropriately. 907 */ 908 if (configInfo.str == NULL) { 909 ldapErrno = -1; 910 } 911 912 configSize = get_data_size(&configInfo, &ldapErrno); 913 914 if (ldapErrno == 0) { 915 dataSource.begin = configInfo.str; 916 dataSource.size = configInfo.len; 917 dataSource.destroy = 1; 918 } 919 920 current_admin.ldap_stat.ldap_numbercalls++; 921 /* FALLTHRU */ 922 case ALLOCATE: 923 /* 924 * Allocate a buffer of the calculated (or default) size 925 * and proceed with populating it with data. 926 */ 927 buf = (dataunion *) alloca(configSize); 928 929 /* 930 * Set a return code and, if a data source is specified, 931 * copy data from the source to the buffer. 932 */ 933 buf->data.ldap_ret.ldap_errno = ldapErrno; 934 buf->data.ldap_ret.ldap_return_code = ldapErrno; 935 buf->data.ldap_ret.ldap_bufferbytesused = configSize; 936 937 if (dataSource.begin != NULL) { 938 (void) memcpy(buf->data.ldap_ret.ldap_u.config, 939 dataSource.begin, 940 dataSource.size); 941 if (dataSource.destroy) { 942 free(dataSource.begin); 943 } 944 } 945 946 } 947 (void) door_return((char *)&buf->data, 948 buf->data.ldap_ret.ldap_bufferbytesused, 949 NULL, 950 0); 951 #undef GETSIZE 952 #undef ALLOCATE 953 } 954 955 static void 956 usage(char *s) 957 { 958 (void) fprintf(stderr, 959 gettext("Usage: %s [-d debug_level] [-l logfilename]\n"), s); 960 (void) fprintf(stderr, gettext(" [-K] " 961 "[-r revalidate_interval] ")); 962 #ifndef SLP 963 (void) fprintf(stderr, gettext(" [-g]\n")); 964 #else 965 (void) fprintf(stderr, gettext(" [-g] [-s]\n")); 966 #endif /* SLP */ 967 exit(1); 968 } 969 970 971 static int logfd = -1; 972 973 static int 974 cachemgr_set_lf(admin_t *ptr, char *logfile) 975 { 976 int newlogfd; 977 978 /* 979 * we don't really want to try and open the log file 980 * /dev/null since that will fail w/ our security fixes 981 */ 982 983 if (logfile == NULL || *logfile == 0) { 984 /*EMPTY*/; 985 } else if (strcmp(logfile, "/dev/null") == 0) { 986 (void) strcpy(current_admin.logfile, "/dev/null"); 987 (void) close(logfd); 988 logfd = -1; 989 } else { 990 if ((newlogfd = 991 open(logfile, O_EXCL|O_WRONLY|O_CREAT, 0644)) < 0) { 992 /* 993 * File already exists... now we need to get cute 994 * since opening a file in a world-writeable directory 995 * safely is hard = it could be a hard link or a 996 * symbolic link to a system file. 997 * 998 */ 999 struct stat before; 1000 1001 if (lstat(logfile, &before) < 0) { 1002 logit("Cannot open new logfile \"%s\": %sn", 1003 logfile, strerror(errno)); 1004 return (-1); 1005 } 1006 if (S_ISREG(before.st_mode) && /* no symbolic links */ 1007 (before.st_nlink == 1) && /* no hard links */ 1008 (before.st_uid == 0)) { /* owned by root */ 1009 if ((newlogfd = 1010 open(logfile, 1011 O_APPEND|O_WRONLY, 0644)) < 0) { 1012 logit("Cannot open new logfile " 1013 "\"%s\": %s\n", 1014 logfile, strerror(errno)); 1015 return (-1); 1016 } 1017 } else { 1018 logit("Cannot use specified logfile " 1019 "\"%s\": file is/has links or isn't " 1020 "owned by root\n", logfile); 1021 return (-1); 1022 } 1023 } 1024 (void) strlcpy(ptr->logfile, logfile, sizeof (ptr->logfile)); 1025 (void) close(logfd); 1026 logfd = newlogfd; 1027 logit("Starting ldap_cachemgr, logfile %s\n", logfile); 1028 } 1029 return (0); 1030 } 1031 1032 /*PRINTFLIKE1*/ 1033 void 1034 logit(char *format, ...) 1035 { 1036 static mutex_t loglock; 1037 struct timeval tv; 1038 char buffer[BUFSIZ]; 1039 va_list ap; 1040 1041 va_start(ap, format); 1042 1043 if (logfd >= 0) { 1044 int safechars; 1045 1046 (void) gettimeofday(&tv, NULL); 1047 (void) ctime_r(&tv.tv_sec, buffer, BUFSIZ); 1048 (void) snprintf(buffer+19, BUFSIZE, ".%.4ld ", 1049 tv.tv_usec/100); 1050 safechars = sizeof (buffer) - 30; 1051 if (vsnprintf(buffer+25, safechars, format, ap) > safechars) 1052 (void) strcat(buffer, "...\n"); 1053 (void) mutex_lock(&loglock); 1054 (void) write(logfd, buffer, strlen(buffer)); 1055 (void) mutex_unlock(&loglock); 1056 } 1057 va_end(ap); 1058 } 1059 1060 1061 static int 1062 client_getadmin(admin_t *ptr) 1063 { 1064 dataunion u; 1065 ldap_data_t *dptr; 1066 int ndata; 1067 int adata; 1068 1069 u.data.ldap_call.ldap_callnumber = GETADMIN; 1070 ndata = sizeof (u); 1071 adata = sizeof (u.data); 1072 dptr = &u.data; 1073 1074 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) { 1075 return (-1); 1076 } 1077 (void) memcpy(ptr, dptr->ldap_ret.ldap_u.buff, sizeof (*ptr)); 1078 1079 return (0); 1080 } 1081 1082 1083 static int 1084 setadmin(ldap_call_t *ptr) 1085 { 1086 admin_t *new; 1087 1088 new = (admin_t *)ptr->ldap_u.domainname; 1089 1090 /* 1091 * global admin stuff 1092 */ 1093 1094 if ((cachemgr_set_lf(¤t_admin, new->logfile) < 0) || 1095 cachemgr_set_dl(¤t_admin, new->debug_level) < 0) { 1096 return (-1); 1097 } 1098 1099 if (cachemgr_set_ttl(¤t_admin.ldap_stat, 1100 "ldap", 1101 new->ldap_stat.ldap_ttl) < 0) { 1102 return (-1); 1103 } 1104 1105 return (0); 1106 } 1107 1108 1109 static void 1110 client_killserver() 1111 { 1112 dataunion u; 1113 ldap_data_t *dptr; 1114 int ndata; 1115 int adata; 1116 1117 u.data.ldap_call.ldap_callnumber = KILLSERVER; 1118 ndata = sizeof (u); 1119 adata = sizeof (ldap_call_t); 1120 dptr = &u.data; 1121 1122 __ns_ldap_trydoorcall(&dptr, &ndata, &adata); 1123 } 1124 1125 1126 static int 1127 client_setadmin(admin_t *ptr) 1128 { 1129 dataunion u; 1130 ldap_data_t *dptr; 1131 int ndata; 1132 int adata; 1133 1134 u.data.ldap_call.ldap_callnumber = SETADMIN; 1135 (void) memcpy(u.data.ldap_call.ldap_u.domainname, ptr, sizeof (*ptr)); 1136 ndata = sizeof (u); 1137 adata = sizeof (*ptr); 1138 dptr = &u.data; 1139 1140 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) { 1141 return (-1); 1142 } 1143 1144 return (0); 1145 } 1146 1147 static int 1148 client_showstats(admin_t *ptr) 1149 { 1150 dataunion u; 1151 ldap_data_t *dptr; 1152 int ndata; 1153 int adata; 1154 char *rbuf, *sptr, *rest; 1155 1156 /* 1157 * print admin data 1158 */ 1159 (void) printf(gettext("\ncachemgr configuration:\n")); 1160 (void) printf(gettext("server debug level %10d\n"), ptr->debug_level); 1161 (void) printf(gettext("server log file\t\"%s\"\n"), ptr->logfile); 1162 (void) printf(gettext("number of calls to ldapcachemgr %10d\n"), 1163 ptr->ldap_stat.ldap_numbercalls); 1164 1165 /* 1166 * get cache data statistics 1167 */ 1168 u.data.ldap_call.ldap_callnumber = GETCACHESTAT; 1169 ndata = sizeof (u); 1170 adata = sizeof (ldap_call_t); 1171 dptr = &u.data; 1172 1173 if (__ns_ldap_trydoorcall(&dptr, &ndata, &adata) != NS_CACHE_SUCCESS) { 1174 (void) printf( 1175 gettext("\nCache data statistics not available!\n")); 1176 return (0); 1177 } 1178 1179 /* 1180 * print cache data statistics line by line 1181 */ 1182 (void) printf(gettext("\ncachemgr cache data statistics:\n")); 1183 rbuf = dptr->ldap_ret.ldap_u.buff; 1184 sptr = strtok_r(rbuf, DOORLINESEP, &rest); 1185 for (;;) { 1186 (void) printf("%s\n", sptr); 1187 sptr = strtok_r(NULL, DOORLINESEP, &rest); 1188 if (sptr == NULL) 1189 break; 1190 } 1191 return (0); 1192 } 1193 1194 1195 /* 1196 * detach from tty 1197 */ 1198 static void 1199 detachfromtty(char *pgm) 1200 { 1201 int status; 1202 pid_t pid, wret; 1203 1204 (void) close(0); 1205 (void) close(1); 1206 /* 1207 * Block the SIGUSR1 signal 1208 * just in case that the child 1209 * process may run faster than 1210 * the parent process and 1211 * send this signal before 1212 * the signal handler is ready 1213 * in the parent process. 1214 * This error will cause the parent 1215 * to exit with the User Signal 1 1216 * exit code (144). 1217 */ 1218 (void) sighold(SIGUSR1); 1219 pid = fork1(); 1220 switch (pid) { 1221 case (pid_t)-1: 1222 logit("detachfromtty(): fork1() call failed\n"); 1223 (void) fprintf(stderr, 1224 gettext("%s: fork1() call failed.\n"), 1225 pgm); 1226 syslog(LOG_ERR, 1227 gettext("ldap_cachemgr: fork1() call failed.")); 1228 exit(1); 1229 break; 1230 case 0: 1231 /* 1232 * child process does not 1233 * need to worry about 1234 * the SIGUSR1 signal 1235 */ 1236 (void) sigrelse(SIGUSR1); 1237 (void) close(2); 1238 break; 1239 default: 1240 /* 1241 * Wait forever until the child process 1242 * has exited, or has signalled that at 1243 * least one server in the server list 1244 * is up. 1245 */ 1246 if (signal(SIGUSR1, sig_ok_to_exit) == SIG_ERR) { 1247 logit("detachfromtty(): " 1248 "can't set up signal handler to " 1249 " catch SIGUSR1.\n"); 1250 (void) fprintf(stderr, 1251 gettext("%s: signal() call failed.\n"), 1252 pgm); 1253 syslog(LOG_ERR, gettext("ldap_cachemgr: " 1254 "can't set up signal handler to " 1255 " catch SIGUSR1.")); 1256 exit(1); 1257 } 1258 1259 /* 1260 * now unblock the SIGUSR1 signal 1261 * to handle the pending or 1262 * soon to arrive SIGUSR1 signal 1263 */ 1264 (void) sigrelse(SIGUSR1); 1265 wret = waitpid(pid, &status, 0); 1266 1267 if (wret == -1) { 1268 logit("detachfromtty(): " 1269 "waitpid() call failed\n"); 1270 (void) fprintf(stderr, 1271 gettext("%s: waitpid() call failed.\n"), 1272 pgm); 1273 syslog(LOG_ERR, 1274 gettext("ldap_cachemgr: waitpid() " 1275 "call failed.")); 1276 exit(1); 1277 } 1278 if (wret != pid) { 1279 logit("detachfromtty(): " 1280 "waitpid() returned %ld when " 1281 "child pid was %ld\n", 1282 wret, pid); 1283 (void) fprintf(stderr, 1284 gettext( 1285 "%s: waitpid() returned %ld when " 1286 "child pid was %ld.\n"), 1287 pgm, wret, pid); 1288 syslog(LOG_ERR, 1289 gettext("ldap_cachemgr: waitpid() " 1290 "returned different " 1291 "child pid.")); 1292 exit(1); 1293 } 1294 1295 /* evaluate return status */ 1296 if (WIFEXITED(status)) { 1297 if (WEXITSTATUS(status) == 0) { 1298 exit(0); 1299 } 1300 logit("detachfromtty(): " 1301 "child failed (rc = %d).\n", 1302 WEXITSTATUS(status)); 1303 (void) fprintf(stderr, 1304 gettext("%s: failed. Please see " 1305 "syslog for details.\n"), 1306 pgm); 1307 syslog(LOG_ERR, 1308 gettext("ldap_cachemgr: failed " 1309 "(rc = %d)."), 1310 WEXITSTATUS(status)); 1311 } else if (WIFSIGNALED(status)) { 1312 logit("detachfromtty(): " 1313 "child terminated by signal %d.\n", 1314 WTERMSIG(status)); 1315 (void) fprintf(stderr, 1316 gettext("%s: terminated by signal %d.\n"), 1317 pgm, WTERMSIG(status)); 1318 syslog(LOG_ERR, 1319 gettext("ldap_cachemgr: terminated by " 1320 "signal %d.\n"), 1321 WTERMSIG(status)); 1322 } else if (WCOREDUMP(status)) { 1323 logit("detachfromtty(): child core dumped.\n"), 1324 (void) fprintf(stderr, 1325 gettext("%s: core dumped.\n"), 1326 pgm); 1327 syslog(LOG_ERR, 1328 gettext("ldap_cachemgr: " 1329 "core dumped.\n")); 1330 } 1331 1332 exit(1); 1333 } 1334 (void) setsid(); 1335 if (open("/dev/null", O_RDWR, 0) != -1) { 1336 (void) dup(0); 1337 (void) dup(0); 1338 } 1339 } 1340 1341 /* 1342 * Check if the door client's euid is 0 1343 * 1344 * We could check for some privilege or re-design the interfaces that 1345 * lead to is_root() being called so that we rely on SMF and RBAC, but 1346 * we need this check only for dealing with undocumented-but-possibly- 1347 * used interfaces. Anything beyond checking for euid == 0 here would 1348 * be overkill considering that those are undocumented interfaces. 1349 * 1350 * If free_uc is 0, the caller is responsible for freeing *ucp. 1351 * 1352 * return - 0 euid != 0 1353 * 1 euid == 0 1354 */ 1355 static int 1356 is_root(int free_uc, char *dc_str, ucred_t **ucp) 1357 { 1358 int rc; 1359 1360 if (door_ucred(ucp) != 0) { 1361 rc = errno; 1362 logit("door_ucred() call failed %s\n", strerror(rc)); 1363 syslog(LOG_ERR, gettext("ldap_cachemgr: door_ucred() call %s " 1364 "failed %s"), strerror(rc)); 1365 return (0); 1366 } 1367 1368 1369 if (ucred_geteuid(*ucp) != 0) { 1370 1371 if (current_admin.debug_level >= DBG_CANT_FIND) 1372 logit("%s call failed(cred): caller pid %ld, uid %u, " 1373 "euid %u (if uid or euid is %u, it may be " 1374 "unavailable)\n", dc_str, ucred_getpid(*ucp), 1375 ucred_getruid(*ucp), ucred_geteuid(*ucp), -1); 1376 1377 rc = 0; 1378 } else { 1379 1380 if (current_admin.debug_level >= DBG_ALL) 1381 logit("received %s call from pid %ld, uid %u, euid %u " 1382 "(if uid or euid is %u, it may be unavailable)\n", 1383 dc_str, ucred_getpid(*ucp), ucred_getruid(*ucp), 1384 ucred_geteuid(*ucp), -1); 1385 rc = 1; 1386 } 1387 1388 if (free_uc) 1389 ucred_free(*ucp); 1390 1391 return (rc); 1392 } 1393 1394 /* 1395 * Check if pid is nscd 1396 * 1397 * Input: pid - process id of the door client that calls ldap_cachemgr 1398 * 1399 * Return: 0 - No 1400 * 1 - Yes 1401 */ 1402 1403 int 1404 is_called_from_nscd(pid_t pid) 1405 { 1406 static mutex_t _door_lock = DEFAULTMUTEX; 1407 static int doorfd = -1; 1408 int match; 1409 door_info_t my_door; 1410 1411 /* 1412 * the first time in we try and open and validate the door. 1413 * the validations are that the door must have been 1414 * created with the door cookie and 1415 * that the file attached to the door is owned by root 1416 * and readonly by user, group and other. If any of these 1417 * validations fail we refuse to use the door. 1418 */ 1419 1420 (void) mutex_lock(&_door_lock); 1421 1422 try_again: 1423 1424 if (doorfd == -1) { 1425 1426 if ((doorfd = open(NAME_SERVICE_DOOR, O_RDONLY, 0)) 1427 == -1) { 1428 (void) mutex_unlock(&_door_lock); 1429 return (0); 1430 } 1431 1432 if (door_info(doorfd, &my_door) == -1 || 1433 (my_door.di_attributes & DOOR_REVOKED) || 1434 my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { 1435 /* 1436 * we should close doorfd because we just opened it 1437 */ 1438 (void) close(doorfd); 1439 doorfd = -1; 1440 (void) mutex_unlock(&_door_lock); 1441 return (0); 1442 } 1443 } else { 1444 /* 1445 * doorfd is cached. Double check just in case 1446 * the door server is restarted or is down. 1447 */ 1448 if (door_info(doorfd, &my_door) == -1 || 1449 my_door.di_data != (uintptr_t)NAME_SERVICE_DOOR_COOKIE) { 1450 /* 1451 * don't close it - 1452 * someone else has clobbered fd 1453 */ 1454 doorfd = -1; 1455 goto try_again; 1456 } 1457 1458 if (my_door.di_attributes & DOOR_REVOKED) { 1459 (void) close(doorfd); 1460 doorfd = -1; /* try and restart connection */ 1461 goto try_again; 1462 } 1463 } 1464 1465 /* 1466 * door descriptor exists and is valid 1467 */ 1468 if (pid == my_door.di_target) 1469 match = 1; 1470 else 1471 match = 0; 1472 1473 (void) mutex_unlock(&_door_lock); 1474 1475 return (match); 1476 1477 } 1478 1479 /* 1480 * new_attr(name, value) 1481 * 1482 * create a new LDAP attribute to be sent to the server 1483 */ 1484 static ns_ldap_attr_t * 1485 new_attr(char *name, char *value) 1486 { 1487 ns_ldap_attr_t *tmp; 1488 1489 tmp = malloc(sizeof (*tmp)); 1490 if (tmp != NULL) { 1491 tmp->attrname = name; 1492 tmp->attrvalue = (char **)calloc(2, sizeof (char *)); 1493 if (tmp->attrvalue == NULL) { 1494 free(tmp); 1495 return (NULL); 1496 } 1497 tmp->attrvalue[0] = value; 1498 tmp->value_count = 1; 1499 } 1500 1501 return (tmp); 1502 } 1503 1504 /* 1505 * Convert the flatten ldap attributes in a ns_ldap_attr_t back 1506 * to an ns_ldap_attr_t array. 1507 * 1508 * strlist->ldap_offsets[] contains offsets to strings: 1509 * "dn", <dn value>, <attr 1>, <attrval 1>, ... <attr n>, <attrval n> 1510 * where n is (strlist->ldap_count/2 -1). 1511 * The output ns_ldap_attr_t array has a size of (strlist->ldap_count/2) 1512 * the first (strlist->ldap_count/2 -1) contains all the attribute data, 1513 * the last one is a NULL pointer. DN will be extracted out and pointed 1514 * to by *dn. 1515 */ 1516 static ns_ldap_attr_t ** 1517 str2attrs(ldap_strlist_t *strlist, char **dn) 1518 { 1519 int c; 1520 int i; 1521 int j; 1522 ns_ldap_attr_t **ret; 1523 1524 c = strlist->ldap_count; 1525 ret = calloc(c/2, sizeof (ns_ldap_attr_t *)); 1526 if (ret == NULL) 1527 return (NULL); 1528 *dn = (char *)strlist + strlist->ldap_offsets[1]; 1529 1530 /* 1531 * skip the first 'dn'/<dn value> pair, for all other attr type/value 1532 * pairs, get pointers to the attr type (offset [i]) and attr value 1533 * (offset [i+1]) and put in ns_ldap_attr_t at ret[j] 1534 */ 1535 for (i = 2, j = 0; i < c; i = i + 2, j++) { 1536 ret[j] = new_attr((char *)strlist + strlist->ldap_offsets[i], 1537 (char *)strlist + strlist->ldap_offsets[i + 1]); 1538 } 1539 return (ret); 1540 } 1541 1542 static int 1543 get_admin_dn(ns_cred_t *credp, int *status, ns_ldap_error_t **errorp) 1544 { 1545 void **paramVal = NULL; 1546 int rc; 1547 1548 /* get bind DN for shadow update */ 1549 rc = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDDN_P, 1550 ¶mVal, errorp); 1551 if (rc != NS_LDAP_SUCCESS) 1552 return (rc); 1553 1554 if (paramVal == NULL || *paramVal == NULL) { 1555 rc = NS_LDAP_CONFIG; 1556 *status = NS_CONFIG_NOTALLOW; 1557 if (paramVal != NULL) 1558 (void) __ns_ldap_freeParam(¶mVal); 1559 return (rc); 1560 } 1561 credp->cred.unix_cred.userID = strdup((char *)*paramVal); 1562 (void) __ns_ldap_freeParam(¶mVal); 1563 if (credp->cred.unix_cred.userID == NULL) 1564 return (NS_LDAP_MEMORY); 1565 1566 return (NS_LDAP_SUCCESS); 1567 } 1568 1569 /* 1570 * admin_modify() does a privileged modify within the ldap_cachemgr daemon 1571 * process using the admin DN/password configured with parameters 1572 * NS_LDAP_ADMIN_BINDDN and NS_LDAP_ADMIN_BINDPASSWD. It will only 1573 * be done if NS_LDAP_ENABLE_SHADOW_UPDATE is set to TRUE. 1574 * 1575 * The input ldap_call_t (*in) contains LDAP shadowAccount attributes to 1576 * be modified. The data is a flatten ns_ldap_attr_t arrary stored in 1577 * the strlist element of the input ldap_call_t. 1578 * The output will be in LineBuf (*config_info), an ldap_admin_mod_result_t 1579 * structure that contains error code, error status, and error message. 1580 */ 1581 static void 1582 admin_modify(LineBuf *config_info, ldap_call_t *in) 1583 { 1584 int rc = NS_LDAP_SUCCESS; 1585 int authstried = 0; 1586 int shadow_enabled = 0; 1587 char *dn = NULL; 1588 char **certpath = NULL; 1589 char **enable_shadow = NULL; 1590 ns_auth_t **app; 1591 ns_auth_t **authpp = NULL; 1592 ns_auth_t *authp = NULL; 1593 ns_cred_t *credp = NULL; 1594 char buffer[MAXERROR]; 1595 const int rlen = offsetof(ldap_admin_mod_result_t, msg); 1596 int mlen = 0; 1597 const int msgmax = MAXERROR - rlen; 1598 int status = 0; 1599 ucred_t *uc = NULL; 1600 ldap_strlist_t *strlist; 1601 ns_ldap_attr_t **attrs = NULL; 1602 ns_ldap_error_t *error = NULL; 1603 ldap_admin_mod_result_t *result; 1604 1605 (void) memset((char *)config_info, 0, sizeof (LineBuf)); 1606 1607 /* only root or an ALL privs user can do admin modify */ 1608 if (is_root_or_all_privs("ADMINMODIFY", &uc) == 0) { 1609 mlen = snprintf(buffer, msgmax, "%s", 1610 gettext("shadow update by a non-root and no ALL privilege " 1611 "user not allowed")); 1612 rc = NS_LDAP_CONFIG; 1613 goto out; 1614 } 1615 1616 /* check to see if shadow update is enabled */ 1617 rc = __ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P, 1618 (void ***)&enable_shadow, &error); 1619 if (rc != NS_LDAP_SUCCESS) 1620 goto out; 1621 if (enable_shadow != NULL && *enable_shadow != NULL) { 1622 shadow_enabled = (*(int *)enable_shadow[0] == 1623 NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE); 1624 } 1625 if (enable_shadow != NULL) 1626 (void) __ns_ldap_freeParam((void ***)&enable_shadow); 1627 if (shadow_enabled == 0) { 1628 rc = NS_LDAP_CONFIG; 1629 status = NS_CONFIG_NOTALLOW; 1630 mlen = snprintf(buffer, msgmax, "%s", 1631 gettext("shadow update not enabled")); 1632 goto out; 1633 } 1634 1635 /* convert attributes in string buffer into an ldap attribute array */ 1636 strlist = &in->ldap_u.strlist; 1637 attrs = str2attrs(strlist, &dn); 1638 if (attrs == NULL || *attrs == NULL || dn == NULL || *dn == '\0') { 1639 rc = NS_LDAP_INVALID_PARAM; 1640 goto out; 1641 } 1642 1643 if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) { 1644 rc = NS_LDAP_MEMORY; 1645 goto out; 1646 } 1647 1648 /* get host certificate path, if one is configured */ 1649 rc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 1650 (void ***)&certpath, &error); 1651 if (rc != NS_LDAP_SUCCESS) 1652 goto out; 1653 if (certpath != NULL && *certpath != NULL) { 1654 credp->hostcertpath = strdup(*certpath); 1655 if (credp->hostcertpath == NULL) 1656 rc = NS_LDAP_MEMORY; 1657 } 1658 if (certpath != NULL) 1659 (void) __ns_ldap_freeParam((void ***)&certpath); 1660 if (rc != NS_LDAP_SUCCESS) 1661 goto out; 1662 1663 /* Load the service specific authentication method */ 1664 rc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp, 1665 &error); 1666 if (rc != NS_LDAP_SUCCESS) { 1667 if (credp->hostcertpath != NULL) 1668 free(credp->hostcertpath); 1669 goto out; 1670 } 1671 1672 /* 1673 * if authpp is null, there is no serviceAuthenticationMethod 1674 * try default authenticationMethod 1675 */ 1676 if (authpp == NULL) { 1677 rc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp, 1678 &error); 1679 if (rc != NS_LDAP_SUCCESS) 1680 goto out; 1681 } 1682 1683 /* 1684 * if authpp is still null, then can not authenticate, syslog 1685 * error message and return error 1686 */ 1687 if (authpp == NULL) { 1688 rc = NS_LDAP_CONFIG; 1689 mlen = snprintf(buffer, msgmax, "%s", 1690 gettext("No legal LDAP authentication method configured")); 1691 goto out; 1692 } 1693 1694 /* 1695 * Walk the array and try all authentication methods in order except 1696 * for "none". 1697 */ 1698 for (app = authpp; *app; app++) { 1699 authp = *app; 1700 if (authp->type == NS_LDAP_AUTH_NONE) 1701 continue; 1702 authstried++; 1703 credp->auth.type = authp->type; 1704 credp->auth.tlstype = authp->tlstype; 1705 credp->auth.saslmech = authp->saslmech; 1706 credp->auth.saslopt = authp->saslopt; 1707 1708 /* 1709 * For GSSAPI, host credential will be used. No admin 1710 * DN is needed. For other authentication methods, 1711 * we need to set admin. 1712 */ 1713 if (credp->auth.saslmech != NS_LDAP_SASL_GSSAPI) { 1714 if ((rc = get_admin_dn(credp, &status, 1715 &error)) != NS_LDAP_SUCCESS) { 1716 if (error != NULL) 1717 goto out; 1718 if (status == NS_CONFIG_NOTALLOW) { 1719 mlen = snprintf(buffer, msgmax, "%s", 1720 gettext("Admin bind DN not " 1721 "configured")); 1722 goto out; 1723 } 1724 } 1725 } 1726 1727 rc = __ns_ldap_repAttr(NS_ADMIN_SHADOW_UPDATE, dn, 1728 (const ns_ldap_attr_t * const *)attrs, 1729 credp, 0, &error); 1730 if (rc == NS_LDAP_SUCCESS) 1731 goto out; 1732 1733 /* 1734 * Other errors might need to be added to this list, for 1735 * the current supported mechanisms this is sufficient. 1736 */ 1737 if (rc == NS_LDAP_INTERNAL && 1738 error->pwd_mgmt.status == NS_PASSWD_GOOD && 1739 (error->status == LDAP_INAPPROPRIATE_AUTH || 1740 error->status == LDAP_INVALID_CREDENTIALS)) 1741 goto out; 1742 1743 /* 1744 * If there is error related to password policy, 1745 * return it to caller. 1746 */ 1747 if (rc == NS_LDAP_INTERNAL && 1748 error->pwd_mgmt.status != NS_PASSWD_GOOD) { 1749 rc = NS_LDAP_CONFIG; 1750 status = NS_CONFIG_NOTALLOW; 1751 (void) __ns_ldap_freeError(&error); 1752 mlen = snprintf(buffer, msgmax, "%s", 1753 gettext("update failed due to " 1754 "password policy on server (%d)"), 1755 error->pwd_mgmt.status); 1756 goto out; 1757 } 1758 1759 /* we don't really care about the error, just clean it up */ 1760 if (error) 1761 (void) __ns_ldap_freeError(&error); 1762 } 1763 if (authstried == 0) { 1764 rc = NS_LDAP_CONFIG; 1765 mlen = snprintf(buffer, msgmax, "%s", 1766 gettext("No legal LDAP authentication method configured")); 1767 goto out; 1768 } 1769 1770 rc = NS_LDAP_OP_FAILED; 1771 1772 out: 1773 if (credp != NULL) 1774 (void) __ns_ldap_freeCred(&credp); 1775 1776 if (authpp != NULL) 1777 (void) __ns_ldap_freeParam((void ***)&authpp); 1778 1779 if (error != NULL) { 1780 mlen = snprintf(buffer, msgmax, "%s", error->message); 1781 status = error->status; 1782 (void) __ns_ldap_freeError(&error); 1783 } 1784 1785 if (attrs != NULL) { 1786 int i; 1787 for (i = 0; attrs[i]; i++) { 1788 free(attrs[i]->attrvalue); 1789 free(attrs[i]); 1790 } 1791 } 1792 1793 config_info->len = rlen + mlen + 1; 1794 config_info->str = malloc(config_info->len); 1795 if (config_info->str == NULL) { 1796 config_info->len = 0; 1797 return; 1798 } 1799 result = (ldap_admin_mod_result_t *)config_info->str; 1800 result->ns_err = rc; 1801 result->status = status; 1802 if (mlen != 0) { 1803 result->msg_size = mlen + 1; 1804 (void) strcpy(config_info->str + rlen, buffer); 1805 } 1806 } 1807 1808 /* 1809 * Check to see if the door client's euid is 0 or if it has ALL zone privilege. 1810 * return - 0 No or error 1811 * 1 Yes 1812 */ 1813 int 1814 is_root_or_all_privs(char *dc_str, ucred_t **ucp) 1815 { 1816 const priv_set_t *ps; /* door client */ 1817 priv_set_t *zs; /* zone */ 1818 int rc = 0; 1819 1820 *ucp = NULL; 1821 1822 /* no more to do if door client's euid is 0 */ 1823 if (is_root(0, dc_str, ucp) == 1) { 1824 ucred_free(*ucp); 1825 return (1); 1826 } 1827 1828 /* error if couldn't get the ucred_t */ 1829 if (*ucp == NULL) 1830 return (0); 1831 1832 if ((ps = ucred_getprivset(*ucp, PRIV_EFFECTIVE)) != NULL) { 1833 zs = priv_str_to_set("zone", ",", NULL); 1834 if (priv_isequalset(ps, zs)) 1835 rc = 1; /* has all zone privs */ 1836 else { 1837 if (current_admin.debug_level >= DBG_CANT_FIND) 1838 logit("%s call failed (no all zone privs): " 1839 "caller pid %ld, uid %u, euid %u " 1840 "(if uid or euid is %u, it may " 1841 "be unavailable)\n", dc_str, 1842 ucred_getpid(*ucp), ucred_getruid(*ucp), 1843 ucred_geteuid(*ucp), -1); 1844 } 1845 priv_freeset(zs); 1846 } 1847 1848 ucred_free(*ucp); 1849 return (rc); 1850 } 1851