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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <synch.h> 31 #include <thread.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <dlfcn.h> 35 #include <door.h> 36 #include <libscf.h> 37 #include <ucred.h> 38 #include <sys/varargs.h> 39 #include <signal.h> 40 #include <unistd.h> 41 #include <sys/types.h> 42 #include <dirent.h> 43 #include <sys/proc.h> 44 #include <procfs.h> 45 #include <sys/stat.h> 46 #include <fcntl.h> 47 #include <limits.h> 48 #include <sys/resource.h> 49 #include <libscf.h> 50 #include "nscd_door.h" 51 #include "nscd_config.h" 52 #include "nscd_log.h" 53 #include "nscd_frontend.h" 54 #include "nscd_selfcred.h" 55 #include "nscd_admin.h" 56 #include "nscd_common.h" 57 #include "ns_sldap.h" 58 59 extern int _logfd; 60 static char *execpath; 61 static char **execargv; 62 static char *selfcred_dbs = NULL; 63 64 static void *get_smf_prop(const char *var, char type, void *def_val); 65 66 /* current self-cred configuration data being used */ 67 static nscd_cfg_global_selfcred_t nscd_selfcred_cfg_g; 68 69 #define _NSCD_PUN_BLOCK 1024 70 static uint8_t pu_nscd_enabled; 71 static int max_pu_nscd = _NSCD_PUN_BLOCK; 72 static int pu_nscd_ttl; 73 74 static nscd_rc_t setup_ldap_backend(); 75 static nscd_rc_t init_user_proc_monitor(); 76 77 /* 78 * clild state 79 */ 80 typedef enum { 81 CHILD_STATE_NONE = 0, 82 CHILD_STATE_UIDKNOWN, 83 CHILD_STATE_FORKSENT, 84 CHILD_STATE_PIDKNOWN 85 } child_state_t; 86 87 88 typedef struct _child { 89 int child_slot; 90 int child_door; 91 pid_t child_pid; 92 uid_t child_uid; 93 gid_t child_gid; 94 child_state_t child_state; 95 int next_open; 96 mutex_t *mutex; 97 cond_t *cond; 98 } child_t; 99 100 static child_t **child = NULL; 101 static mutex_t child_lock = DEFAULTMUTEX; 102 static int open_head; 103 static int open_tail; 104 static int used_slot; 105 106 /* nscd door id */ 107 extern int _doorfd; 108 static pid_t main_uid = 0; 109 110 /* nscd id: main, forker, or child */ 111 extern int _whoami; 112 113 /* forker nscd pid */ 114 static pid_t forker_pid = 0; 115 static pid_t forker_uid = 0; 116 117 long activity = 0; 118 mutex_t activity_lock = DEFAULTMUTEX; 119 120 static int forking_door = -1; 121 static mutex_t forking_lock = DEFAULTMUTEX; 122 123 static void 124 free_slot(int s) 125 { 126 if (child[s] == NULL) 127 return; 128 free(child[s]->mutex); 129 free(child[s]->cond); 130 free(child[s]); 131 child[s] = NULL; 132 } 133 134 void 135 _nscd_free_cslots() 136 { 137 138 int i; 139 140 (void) mutex_lock(&child_lock); 141 142 for (i = 0; i < max_pu_nscd; i++) 143 free_slot(i); 144 145 open_head = -1; 146 open_tail = -1; 147 used_slot = -1; 148 149 (void) mutex_unlock(&child_lock); 150 151 } 152 153 static int 154 init_slot(int s) 155 { 156 child_t *ch; 157 char *me = "init_slot"; 158 159 if (child[s] == NULL) { 160 child[s] = (child_t *)calloc(1, sizeof (child_t)); 161 if (child[s] == NULL) 162 return (-1); 163 ch = child[s]; 164 165 if ((ch->mutex = (mutex_t *)calloc(1, 166 sizeof (mutex_t))) == NULL) { 167 free(ch); 168 return (-1); 169 } 170 (void) mutex_init(ch->mutex, USYNC_THREAD, NULL); 171 172 if ((ch->cond = (cond_t *)calloc(1, 173 sizeof (cond_t))) == NULL) { 174 free(ch->mutex); 175 free(ch); 176 return (-1); 177 } 178 (void) cond_init(ch->cond, USYNC_THREAD, NULL); 179 180 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 181 (me, "slot %d allocated\n", s); 182 } else 183 ch = child[s]; 184 185 ch->child_slot = s; 186 ch->child_door = 0; 187 ch->child_state = CHILD_STATE_NONE; 188 ch->child_pid = 0; 189 ch->child_uid = 0; 190 ch->child_gid = 0; 191 ch->next_open = -1; 192 193 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 194 (me, "slot %d initialized\n", s); 195 196 return (0); 197 } 198 199 static int 200 _nscd_init_cslots() 201 { 202 (void) mutex_lock(&child_lock); 203 204 child = (child_t **)calloc(max_pu_nscd, sizeof (child_t *)); 205 if (child == NULL) 206 return (-1); 207 208 open_head = -1; 209 open_tail = -1; 210 used_slot = -1; 211 212 (void) mutex_unlock(&child_lock); 213 214 return (0); 215 } 216 217 static child_t * 218 get_cslot( 219 uid_t uid, 220 int no_alloc) 221 { 222 int i; 223 child_t *ch, *ret = NULL; 224 char *me = "get_cslot"; 225 226 (void) mutex_lock(&child_lock); 227 228 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 229 (me, "looking for uid %d (slot used = %d)\n", uid, used_slot); 230 231 /* first find the slot with a matching uid */ 232 for (i = 0; i <= used_slot; i++) { 233 ch = child[i]; 234 if (ch->child_state >= CHILD_STATE_UIDKNOWN && 235 ch->child_uid == uid) { 236 ret = ch; 237 (void) mutex_unlock(&child_lock); 238 239 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 240 (me, "slot %d found with uid %d\n", 241 ret->child_slot, ret->child_uid); 242 243 return (ret); 244 } 245 } 246 247 /* if no need to allocate a new slot, return NULL */ 248 if (no_alloc == 1) { 249 (void) mutex_unlock(&child_lock); 250 return (ret); 251 } 252 253 /* no open slot ? get a new one */ 254 if (open_head == -1) { 255 /* if no slot available, allocate more */ 256 if (used_slot >= max_pu_nscd - 1) { 257 child_t **tmp; 258 int newmax = max_pu_nscd + _NSCD_PUN_BLOCK; 259 260 tmp = (child_t **)calloc(newmax, sizeof (child_t *)); 261 if (tmp == NULL) { 262 (void) mutex_unlock(&child_lock); 263 return (ret); 264 } 265 (void) memcpy(tmp, child, sizeof (child_t) * 266 max_pu_nscd); 267 free(child); 268 child = tmp; 269 max_pu_nscd = newmax; 270 } 271 used_slot++; 272 if (init_slot(used_slot) == -1) { 273 used_slot--; 274 (void) mutex_unlock(&child_lock); 275 return (ret); 276 } 277 ch = child[used_slot]; 278 } else { 279 ch = child[open_head]; 280 open_head = ch->next_open; 281 /* got last one ? reset tail */ 282 if (open_head == -1) 283 open_tail = -1; 284 ch->next_open = -1; 285 } 286 287 ch->child_uid = uid; 288 ch->child_state = CHILD_STATE_UIDKNOWN; 289 ret = ch; 290 291 (void) mutex_unlock(&child_lock); 292 293 return (ret); 294 } 295 296 static void 297 return_cslot_nolock(child_t *ch) 298 { 299 300 int slot = ch->child_slot; 301 302 /* have open slot ? add to and reset tail */ 303 if (open_tail != -1) { 304 child[open_tail]->next_open = slot; 305 open_tail = slot; 306 } else { 307 /* no open slot ? make one */ 308 open_head = open_tail = slot; 309 } 310 311 (void) init_slot(ch->child_slot); 312 } 313 314 static void 315 return_cslot(child_t *ch) 316 { 317 318 char *me = "return_cslot"; 319 320 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 321 (me, "returning slot %d\n", ch->child_slot); 322 323 /* return if the slot has been returned by another thread */ 324 if (ch->child_state == CHILD_STATE_NONE) 325 return; 326 327 (void) mutex_lock(&child_lock); 328 329 /* check one more time */ 330 if (ch->child_state == CHILD_STATE_NONE) { 331 (void) mutex_unlock(&child_lock); 332 return; 333 } 334 335 return_cslot_nolock(ch); 336 337 (void) mutex_unlock(&child_lock); 338 } 339 340 static int 341 selfcred_kill( 342 int fd) 343 { 344 int ret; 345 char *me = "selfcred_kill"; 346 347 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 348 (me, "sending kill to door %d\n", fd); 349 350 if (fd != -1) 351 ret = _nscd_doorcall_fd(fd, NSCD_KILL, NULL, 0, 352 NULL, 0, NULL); 353 else 354 ret = _nscd_doorcall(NSCD_KILL); 355 356 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 357 (me, "kill request sent to door %d (rc = %d)\n", fd, ret); 358 359 return (ret); 360 } 361 362 363 void 364 _nscd_kill_forker() 365 { 366 (void) mutex_lock(&forking_lock); 367 if (forking_door != -1) 368 (void) selfcred_kill(forking_door); 369 forking_door = -1; 370 (void) mutex_unlock(&forking_lock); 371 } 372 373 void 374 _nscd_kill_all_children() 375 { 376 int i; 377 int ret; 378 char *me = "_nscd_kill_all_children"; 379 380 (void) mutex_lock(&child_lock); 381 for (i = 0; i <= used_slot; i++) { 382 if (child[i] == NULL) 383 continue; 384 385 if (child[i]->child_state >= CHILD_STATE_PIDKNOWN) { 386 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 387 (me, "killing child process %d (doorfd %d)\n", 388 child[i]->child_pid, child[i]->child_door); 389 390 ret = selfcred_kill(child[i]->child_door); 391 392 if (ret != -1) 393 (void) kill(child[i]->child_pid, SIGTERM); 394 } 395 if (child[i]->child_state != CHILD_STATE_NONE) 396 (void) return_cslot_nolock(child[i]); 397 } 398 (void) mutex_unlock(&child_lock); 399 } 400 static int 401 selfcred_pulse( 402 int fd) 403 { 404 int ret; 405 char *me = "selfcred_pulse"; 406 407 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 408 (me, "start monitoring door %d\n", fd); 409 410 ret = _nscd_doorcall_fd(fd, NSCD_PULSE |(_whoami & NSCD_WHOAMI), 411 NULL, 0, NULL, 0, NULL); 412 413 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 414 (me, "door (%d) monitor exited (rc = %d)\n", fd, ret); 415 416 return (ret); 417 } 418 419 /*ARGSUSED*/ 420 static void * 421 forker_monitor( 422 void *arg) 423 { 424 pid_t fpid; 425 char *fmri; 426 char *me = "forker_monitor"; 427 428 /* wait until forker exits */ 429 fpid = forker_pid; 430 (void) selfcred_pulse(forking_door); 431 432 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 433 (me, "forker (pid = %d) exited or crashed, killing all child processes\n", 434 fpid); 435 436 (void) mutex_lock(&forking_lock); 437 forking_door = -1; 438 forker_pid = -1; 439 (void) mutex_unlock(&forking_lock); 440 441 /* forker exited/crashed, kill all the child processes */ 442 _nscd_kill_all_children(); 443 444 /* restart forker */ 445 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 446 (me, "restarting the forker ...\n"); 447 448 switch (fpid = fork1()) { 449 case (pid_t)-1: 450 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 451 (me, "unable to fork and start the forker ...\n"); 452 453 /* enter the maintenance mode */ 454 if ((fmri = getenv("SMF_FMRI")) != NULL) { 455 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 456 (me, "entering maintenance mode ...\n"); 457 smf_maintain_instance(fmri, SMF_TEMPORARY); 458 } 459 thr_exit((void *)1); 460 break; 461 case 0: 462 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 463 (me, "execv path = %s\n", execpath); 464 465 (void) execv(execpath, execargv); 466 exit(0); 467 break; 468 default: 469 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 470 (me, "new forker's pid is %d\n", fpid); 471 forker_pid = fpid; 472 break; 473 } 474 475 thr_exit((void *)0); 476 477 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 478 } 479 480 static void * 481 child_monitor( 482 void *arg) 483 { 484 child_t *ch = (child_t *)arg; 485 pid_t cpid; 486 char *me = "child_monitor"; 487 488 /* wait until child exits */ 489 cpid = ch->child_pid; 490 (void) selfcred_pulse(ch->child_door); 491 492 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 493 (me, "child (pid = %d) exited or crashed ...\n", cpid); 494 495 /* return the slot used by the child */ 496 return_cslot(ch); 497 498 thr_exit((void *)0); 499 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 500 } 501 502 503 void 504 _nscd_proc_iamhere( 505 void *buf, 506 door_desc_t *dp, 507 uint_t n_desc, 508 int iam) 509 { 510 int cslot; 511 child_t *ch; 512 int errnum; 513 ucred_t *uc = NULL; 514 uid_t uid; 515 nscd_imhere_t *ih; 516 nss_pheader_t *phdr = (nss_pheader_t *)buf; 517 char *me = "_nscd_proc_iamhere"; 518 519 520 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 521 (me, "%d receives iamhere from %d\n", _whoami, iam); 522 523 if (door_ucred(&uc) != 0) { 524 errnum = errno; 525 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 526 (me, "door_ucred failed: %s\n", strerror(errnum)); 527 528 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum, 529 NSCD_DOOR_UCRED_ERROR); 530 } 531 uid = ucred_geteuid(uc); 532 533 switch (iam) { 534 535 case NSCD_MAIN: 536 if (_whoami == NSCD_MAIN || uid != main_uid) { 537 /* 538 * I'm main, or uid from door is not correct, 539 * this must be an imposter 540 */ 541 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 542 (me, "MAIN IMPOSTER CAUGHT!\n"); 543 544 545 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 546 NSCD_SELF_CRED_MAIN_IMPOSTER); 547 } 548 break; 549 550 case NSCD_FORKER: 551 if (_whoami == NSCD_FORKER || uid != forker_uid) { 552 /* 553 * I'm forker, or uid from door is not correct, 554 * this must be an imposter 555 */ 556 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 557 (me, "FORKER IMPOSTER CAUGHT!\n"); 558 559 560 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 561 NSCD_SELF_CRED_FORKER_IMPOSTER); 562 break; 563 } 564 565 /* only main needs to know the forker */ 566 if (_whoami != NSCD_MAIN) { 567 568 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 569 NSCD_SELF_CRED_WRONG_NSCD); 570 break; 571 } 572 573 if (ucred_getpid(uc) != forker_pid) { 574 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 575 (me, "FORKER IMPOSTER CAUGHT: pid = %d should be %d\n", 576 ucred_getpid(uc), forker_pid); 577 578 579 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 580 NSCD_SELF_CRED_FORKER_IMPOSTER); 581 break; 582 } 583 584 if (n_desc < 1) { 585 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 586 (me, "BAD FORKER, NO DOOR!\n"); 587 588 589 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 590 NSCD_SELF_CRED_NO_DOOR); 591 break; 592 } 593 594 if ((dp->d_attributes & DOOR_DESCRIPTOR) && 595 dp->d_data.d_desc.d_descriptor > 0 && 596 dp->d_data.d_desc.d_id != 0) { 597 (void) mutex_lock(&forking_lock); 598 if (forking_door != -1) 599 (void) close(forking_door); 600 forking_door = dp->d_data.d_desc.d_descriptor; 601 (void) mutex_unlock(&forking_lock); 602 603 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 604 (me, "forking door is %d\n", forking_door); 605 606 NSCD_SET_STATUS_SUCCESS(phdr); 607 } else { 608 NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0); 609 break; 610 } 611 612 /* monitor the forker nscd */ 613 (void) thr_create(NULL, 0, forker_monitor, NULL, 614 THR_DETACHED, NULL); 615 616 break; 617 618 case NSCD_CHILD: 619 if (_whoami != NSCD_MAIN) { 620 /* child nscd can only talk to the main nscd */ 621 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 622 (me, "CHILD IMPOSTER CAUGHT!\n"); 623 624 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 625 NSCD_SELF_CRED_CHILD_IMPOSTER); 626 break; 627 } 628 629 /* get the main nscd assigned slot number */ 630 ih = NSCD_N2N_DOOR_DATA(nscd_imhere_t, buf); 631 cslot = ih->slot; 632 (void) mutex_lock(&child_lock); 633 if (cslot < 0 || cslot >= max_pu_nscd) 634 ch = NULL; 635 else 636 ch = child[cslot]; 637 (void) mutex_unlock(&child_lock); 638 639 if (ch == NULL) { 640 /* Bad slot number */ 641 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 642 (me, "bad slot number %d\n", cslot); 643 644 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 645 NSCD_SELF_CRED_INVALID_SLOT_NUMBER); 646 break; 647 } 648 649 if (uid != ch->child_uid) { 650 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 651 (me, "CHILD IMPOSTER CAUGHT: uid = %d should be %d\n", 652 uid, ch->child_uid); 653 654 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 655 NSCD_SELF_CRED_CHILD_IMPOSTER); 656 break; 657 } 658 659 if (ch->child_state != CHILD_STATE_UIDKNOWN && 660 ch->child_state != CHILD_STATE_FORKSENT) { 661 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 662 (me, "invalid slot/child state (%d) for uid %d\n", 663 ch->child_state, uid); 664 665 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 666 NSCD_SELF_CRED_INVALID_SLOT_STATE); 667 break; 668 } 669 670 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 671 (me, "d_descriptor = %d, d_id = %lld\n", 672 dp->d_data.d_desc.d_descriptor, dp->d_data.d_desc.d_id); 673 674 if ((dp->d_attributes & DOOR_DESCRIPTOR) && 675 dp->d_data.d_desc.d_descriptor > 0 && 676 dp->d_data.d_desc.d_id != 0) { 677 (void) mutex_lock(ch->mutex); 678 if (ch->child_door != -1) 679 (void) close(ch->child_door); 680 ch->child_door = dp->d_data.d_desc.d_descriptor; 681 ch->child_pid = ucred_getpid(uc); 682 ch->child_state = CHILD_STATE_PIDKNOWN; 683 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 684 (me, "child in slot %d has door %d\n", 685 cslot, ch->child_door); 686 687 /* 688 * let waiters know that the child is ready to 689 * serve 690 */ 691 (void) cond_broadcast(ch->cond); 692 (void) mutex_unlock(ch->mutex); 693 694 /* monitor the child nscd */ 695 (void) thr_create(NULL, 0, child_monitor, 696 ch, THR_DETACHED, NULL); 697 NSCD_SET_STATUS_SUCCESS(phdr); 698 break; 699 } else { 700 NSCD_SET_STATUS(phdr, NSS_ALTRETRY, 0); 701 } 702 break; 703 } 704 705 ucred_free(uc); 706 uc = NULL; 707 } 708 709 void 710 _nscd_proc_pulse( 711 void *buf, 712 int iam) 713 { 714 long last_active; 715 int done = 0; 716 nss_pheader_t *phdr = (nss_pheader_t *)buf; 717 char *me = "_nscd_proc_pulse"; 718 719 /* only main nscd sends pulse */ 720 if (iam != NSCD_MAIN) { 721 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 722 (me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", iam); 723 724 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 725 NSCD_SELF_CRED_MAIN_IMPOSTER); 726 } 727 728 /* forker doesn't return stats, it just pauses */ 729 if (_whoami == NSCD_FORKER) { 730 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 731 (me, "forker ready to pause ...\n"); 732 733 /*CONSTCOND*/ 734 while (1) 735 (void) pause(); 736 737 NSCD_RETURN_STATUS_SUCCESS(phdr); 738 } 739 740 /* remember the current activity sequence number */ 741 (void) mutex_lock(&activity_lock); 742 last_active = activity; 743 (void) mutex_unlock(&activity_lock); 744 745 while (!done) { 746 747 /* allow per_user_nscd_ttl seconds of inactivity */ 748 (void) sleep(pu_nscd_ttl); 749 750 (void) mutex_lock(&activity_lock); 751 if (last_active == activity) 752 done = 1; 753 else { 754 last_active = activity; 755 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 756 (me, "active, sleep again for %d seconds\n", 757 pu_nscd_ttl); 758 } 759 (void) mutex_unlock(&activity_lock); 760 } 761 762 /* no activity in the specified seconds, exit and disconnect */ 763 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 764 (me, "no activity in the last %d seconds, exit\n", pu_nscd_ttl); 765 exit(0); 766 } 767 768 void 769 _nscd_proc_fork( 770 void *buf, 771 int iam) 772 { 773 int slot; 774 int ret; 775 char *fmri; 776 pid_t cid; 777 uid_t set2uid; 778 gid_t set2gid; 779 nss_pheader_t *phdr = (nss_pheader_t *)buf; 780 char *me = "_nscd_proc_fork"; 781 nscd_fork_t *f; 782 nscd_imhere_t ih; 783 784 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 785 (me, "%d receives fork request from %d\n", _whoami, iam); 786 787 /* only main nscd sends fork requests */ 788 if (iam != NSCD_MAIN) { 789 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 790 (me, "MAIN IMPOSTER CAUGHT! i am %d not NSCD_MAIN\n", 791 iam); 792 793 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 794 NSCD_SELF_CRED_MAIN_IMPOSTER); 795 } 796 797 /* only forker handles fork requests */ 798 if (_whoami != NSCD_FORKER) { 799 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 800 (me, "MAIN IMPOSTER CAUGHT! I AM NOT FORKER!\n"); 801 802 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 803 NSCD_SELF_CRED_WRONG_NSCD); 804 } 805 806 /* fork a child for the slot assigned by the main nscd */ 807 f = NSCD_N2N_DOOR_DATA(nscd_fork_t, buf); 808 slot = f->slot; 809 /* set the uid/gid as assigned by the main nscd */ 810 set2uid = f->uid; 811 set2gid = f->gid; 812 813 /* ignore bad slot number */ 814 if (slot < 0 || slot >= max_pu_nscd) { 815 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 816 (me, "bas slot number\n"); 817 818 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 819 NSCD_SELF_CRED_INVALID_SLOT_NUMBER); 820 } 821 822 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 823 (me, "before fork1() ...\n"); 824 825 if ((cid = fork1()) == 0) { 826 _whoami = NSCD_CHILD; 827 828 /* close all except the log file */ 829 if (_logfd > 0) { 830 int i; 831 for (i = 0; i < _logfd; i++) 832 (void) close(i); 833 closefrom(_logfd + 1); 834 } else 835 closefrom(0); 836 837 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 838 (me, "child %d\n", getpid()); 839 840 (void) setgid(set2gid); 841 (void) setuid(set2uid); 842 843 /* set up the door and server thread pool */ 844 if ((_doorfd = _nscd_setup_child_server(_doorfd)) == -1) 845 exit(-1); 846 847 /* tell libsldap to do self cred only */ 848 (void) setup_ldap_backend(); 849 850 /* notify main that child is active */ 851 ih.slot = slot; 852 for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; ) 853 ret = _nscd_doorcall_sendfd(_doorfd, 854 NSCD_IMHERE | (NSCD_CHILD & NSCD_WHOAMI), 855 &ih, sizeof (ih), NULL); 856 857 NSCD_RETURN_STATUS_SUCCESS(phdr); 858 } if (cid == (pid_t)-1) { 859 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 860 (me, "forker unable to fork ...\n"); 861 862 /* enter the maintenance mode */ 863 if ((fmri = getenv("SMF_FMRI")) != NULL) { 864 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 865 (me, "entering maintenance mode ...\n"); 866 smf_maintain_instance(fmri, SMF_TEMPORARY); 867 } 868 exit(0); 869 } else { 870 /* 871 * start the monitor so as to exit as early as 872 * possible if no other processes are running 873 * with the same PUN uid (i.e., this PUN is 874 * not needed any more) 875 */ 876 (void) init_user_proc_monitor(); 877 878 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 879 (me, "child forked: parent pid = %d, child pid = %d\n", 880 getpid(), cid); 881 882 NSCD_SET_STATUS_SUCCESS(phdr); 883 } 884 885 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 886 (me, "after fork\n"); 887 } 888 889 static void 890 selfcred_fork( 891 void *buf, 892 int doorfd, 893 int cslot, 894 uid_t uid, 895 gid_t gid) 896 { 897 int ret; 898 nscd_fork_t f; 899 nss_pheader_t *phdr = (nss_pheader_t *)buf; 900 char *me = "selfcred_fork"; 901 902 /* if no door fd, do nothing */ 903 if (doorfd == -1) { 904 NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 905 NSCD_SELF_CRED_NO_DOOR); 906 } 907 908 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 909 (me, "sending fork request to door %d for slot %d " 910 "(uid = %d, gid = %d)\n", doorfd, cslot, uid, gid); 911 912 f.slot = cslot; 913 f.uid = uid; 914 f.gid = gid; 915 916 ret = _nscd_doorcall_fd(doorfd, NSCD_FORK|(_whoami&NSCD_WHOAMI), 917 &f, sizeof (f), NULL, 0, phdr); 918 919 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 920 (me, "fork request sent to door %d for slot %d (rc = %d)\n", 921 doorfd, cslot, ret); 922 923 if (NSCD_STATUS_IS_NOT_OK(phdr)) { 924 925 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 926 (me, "fork request sent to door %d for slot %d failed: " 927 "status = %d, errno = %s, nscd status = %d\n", doorfd, 928 cslot, NSCD_GET_STATUS(phdr), strerror(NSCD_GET_ERRNO(phdr)), 929 NSCD_GET_NSCD_STATUS(phdr)); 930 931 } 932 } 933 934 void 935 _nscd_proc_alt_get( 936 void *buf, 937 int *door) 938 { 939 int errnum; 940 uid_t set2uid; 941 gid_t set2gid; 942 nss_pheader_t *phdr = (nss_pheader_t *)buf; 943 char *me = "_nscd_proc_alt_get"; 944 ucred_t *uc = NULL; 945 child_t *ch; 946 947 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 948 (me, "getting an alternate door ...\n"); 949 950 /* make sure there is a door to talk to the forker */ 951 if (forking_door == -1) { 952 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) 953 (me, "no door to talk to the forker\n"); 954 955 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 956 NSCD_SELF_CRED_NO_FORKER); 957 } 958 959 /* get door client's credential information */ 960 if (door_ucred(&uc) != 0) { 961 errnum = errno; 962 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 963 (me, "door_ucred failed: %s\n", strerror(errnum)); 964 965 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum, 966 NSCD_DOOR_UCRED_ERROR); 967 } 968 969 /* get door client's effective uid and effective gid */ 970 set2uid = ucred_geteuid(uc); 971 set2gid = ucred_getegid(uc); 972 ucred_free(uc); 973 uc = NULL; 974 975 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 976 (me, "child uid = %d, gid = %d\n", set2uid, set2gid); 977 978 /* is a slot available ? if not, no one to serve */ 979 if (child == NULL || (ch = get_cslot(set2uid, 0)) == NULL) { 980 981 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 982 (me, "no child slot available (child array = %p, slot = %d)\n", 983 child, ch->child_slot); 984 985 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 986 NSCD_SELF_CRED_NO_CHILD_SLOT); 987 } 988 989 /* create the per user nscd if necessary */ 990 if (ch->child_state != CHILD_STATE_PIDKNOWN) { 991 992 nss_pheader_t phdr1; 993 NSCD_CLEAR_STATUS(&phdr1); 994 995 (void) mutex_lock(ch->mutex); 996 if (ch->child_state == CHILD_STATE_UIDKNOWN) { 997 998 /* ask forker to fork a new child */ 999 selfcred_fork(&phdr1, forking_door, ch->child_slot, 1000 set2uid, set2gid); 1001 if (NSCD_STATUS_IS_NOT_OK(&phdr1)) { 1002 (void) mutex_unlock(ch->mutex); 1003 NSCD_COPY_STATUS(phdr, &phdr1); 1004 return; 1005 } 1006 ch->child_state = CHILD_STATE_FORKSENT; 1007 } 1008 1009 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 1010 (me, "waiting for door (slot = %d, uid = %d, gid = %d)\n", 1011 ch->child_slot, set2uid, set2gid); 1012 1013 /* wait for the per user nscd to become available */ 1014 while (ch->child_state == CHILD_STATE_FORKSENT) { 1015 timestruc_t to; 1016 int err; 1017 int ttl = 5; 1018 1019 to.tv_sec = ttl; 1020 to.tv_nsec = 0; 1021 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 1022 (me, "cond_reltimedwait %d seconds\n", ttl); 1023 err = cond_reltimedwait(ch->cond, ch->mutex, &to); 1024 if (err == ETIME) { 1025 ch->child_state = 1026 CHILD_STATE_UIDKNOWN; 1027 _NSCD_LOG(NSCD_LOG_SELF_CRED, 1028 NSCD_LOG_LEVEL_DEBUG) 1029 (me, "door wait timedout (slot = %d)\n", 1030 ch->child_slot); 1031 break; 1032 } 1033 } 1034 (void) mutex_unlock(ch->mutex); 1035 } 1036 1037 if (ch->child_state != CHILD_STATE_PIDKNOWN) { 1038 1039 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 1040 NSCD_SELF_CRED_INVALID_SLOT_STATE); 1041 } 1042 1043 *door = ch->child_door; 1044 1045 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 1046 (me, "returning door %d for slot %d, uid %d, gid = %d\n", 1047 *door, ch->child_slot, set2uid, set2gid); 1048 1049 NSCD_RETURN_STATUS(phdr, NSS_ALTRETRY, 0); 1050 } 1051 1052 static char ** 1053 cpargv( 1054 int argc, 1055 char **inargv) 1056 { 1057 char **newargv; 1058 int c = 4; 1059 int i = 0, j, k = 0, n = 0; 1060 1061 newargv = (char **)calloc(c + 1, sizeof (char *)); 1062 if (newargv == NULL) 1063 return (NULL); 1064 1065 newargv[n] = strdup(inargv[0]); 1066 if (newargv[n++] == NULL) { 1067 free(newargv); 1068 return (NULL); 1069 } 1070 1071 newargv[n] = strdup("-F"); 1072 if (newargv[n++] == NULL) { 1073 free(newargv[0]); 1074 free(newargv); 1075 return (NULL); 1076 } 1077 1078 for (i = 1; i < argc; i++) { 1079 if (strcmp(inargv[i], "-f") == 0) 1080 k = 2; 1081 if (k == 0) 1082 continue; 1083 1084 newargv[n] = strdup(inargv[i]); 1085 if (newargv[n] == NULL) { 1086 for (j = 0; j < n; j++) 1087 free(newargv[j]); 1088 free(newargv); 1089 return (NULL); 1090 } 1091 1092 k--; 1093 n++; 1094 } 1095 return (newargv); 1096 } 1097 1098 1099 void 1100 _nscd_start_forker( 1101 char *path, 1102 int argc, 1103 char **argv) 1104 { 1105 pid_t cid; 1106 struct rlimit rl; 1107 char *me = "_nscd_start_forker"; 1108 1109 /* if self cred is not configured, do nothing */ 1110 if (!_nscd_is_self_cred_on(1, NULL)) 1111 return; 1112 1113 /* save pathname and generate the new argv for the forker */ 1114 execpath = strdup(path); 1115 execargv = cpargv(argc, argv); 1116 if (execpath == NULL || execargv == NULL) 1117 exit(1); 1118 1119 switch (cid = fork1()) { 1120 case (pid_t)-1: 1121 exit(1); 1122 break; 1123 case 0: 1124 /* start the forker nscd */ 1125 (void) execv(path, execargv); 1126 exit(0); 1127 break; 1128 default: 1129 /* main nscd */ 1130 /* remember process id of the forker */ 1131 forker_pid = cid; 1132 1133 /* set NOFILE to unlimited */ 1134 rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; 1135 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { 1136 _NSCD_LOG(NSCD_LOG_SELF_CRED, 1137 NSCD_LOG_LEVEL_ERROR) 1138 (me, "Cannot set open file limit: %s\n", 1139 strerror(errno)); 1140 exit(1); 1141 } 1142 1143 /* enable child nscd management */ 1144 (void) _nscd_init_cslots(); 1145 break; 1146 } 1147 } 1148 1149 static nscd_rc_t 1150 get_ldap_funcs( 1151 char *name, 1152 void **func_p) 1153 { 1154 char *me = "get_ldap_funcs"; 1155 static void *handle = NULL; 1156 void *sym; 1157 1158 if (name == NULL && handle != NULL) { 1159 (void) dlclose(handle); 1160 return (NSCD_SUCCESS); 1161 } 1162 /* no handle to close, it's OK */ 1163 if (name == NULL) 1164 return (NSCD_SUCCESS); 1165 1166 if (handle == NULL) { 1167 handle = dlopen("libsldap.so.1", RTLD_LAZY); 1168 if (handle == NULL) { 1169 1170 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) 1171 (me, "unable to dlopen libsldap.so.1"); 1172 return (NSCD_CFG_DLOPEN_ERROR); 1173 } 1174 } 1175 1176 if ((sym = dlsym(handle, name)) == NULL) { 1177 1178 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) 1179 (me, "unable to find symbol %s", name); 1180 return (NSCD_CFG_DLSYM_ERROR); 1181 } else 1182 (void) memcpy(func_p, &sym, sizeof (void *)); 1183 1184 return (NSCD_SUCCESS); 1185 } 1186 1187 1188 int 1189 _nscd_is_self_cred_on(int recheck, char **dblist) 1190 { 1191 static int checked = 0; 1192 static int is_on = 0; 1193 static int (*ldap_func)(); 1194 char *srcs = "ldap"; /* only ldap support self cred */ 1195 int ldap_on = 0; 1196 1197 char *ldap_sc_func = "__ns_ldap_self_gssapi_config"; 1198 ns_ldap_self_gssapi_config_t ldap_config; 1199 1200 if (checked && !recheck) { 1201 if (is_on && dblist != NULL) 1202 *dblist = selfcred_dbs; 1203 return (is_on); 1204 } 1205 1206 if (selfcred_dbs != NULL) 1207 free(selfcred_dbs); 1208 selfcred_dbs = _nscd_srcs_in_db_nsw_policy(1, &srcs); 1209 1210 /* 1211 * also check the ldap backend to see if 1212 * the configuration there is good for 1213 * doing self credentialing 1214 */ 1215 if (ldap_func == NULL) 1216 (void) get_ldap_funcs(ldap_sc_func, (void **)&ldap_func); 1217 if (ldap_func != NULL) { 1218 if (ldap_func(&ldap_config) == NS_LDAP_SUCCESS && 1219 ldap_config != NS_LDAP_SELF_GSSAPI_CONFIG_NONE) 1220 ldap_on = 1; 1221 } 1222 1223 is_on = pu_nscd_enabled == nscd_true && 1224 ldap_on && selfcred_dbs != NULL; 1225 1226 checked = 1; 1227 1228 if (is_on && dblist != NULL) 1229 *dblist = selfcred_dbs; 1230 1231 return (is_on); 1232 } 1233 1234 static nscd_rc_t 1235 setup_ldap_backend() 1236 { 1237 nscd_rc_t rc; 1238 static void (*ldap_func)(); 1239 char *ldap_sc_func = "__ns_ldap_self_gssapi_only_set"; 1240 if (ldap_func == NULL) 1241 rc = get_ldap_funcs(ldap_sc_func, (void **)&ldap_func); 1242 if (ldap_func != NULL) { 1243 ldap_func(1); 1244 return (NSCD_SUCCESS); 1245 } 1246 return (rc); 1247 } 1248 1249 /*ARGSUSED*/ 1250 void 1251 _nscd_peruser_getadmin( 1252 void *buf, 1253 int buf_size) 1254 { 1255 void *result_mn = NSCD_N2N_DOOR_DATA(void, buf); 1256 int errnum = 0; 1257 int ret; 1258 uid_t uid; 1259 nss_pheader_t *phdr = (nss_pheader_t *)buf; 1260 char *me = "_nscd_peruser_getadmin"; 1261 ucred_t *uc = NULL; 1262 child_t *ch; 1263 1264 /* get door client's credential information */ 1265 if (door_ucred(&uc) != 0) { 1266 errnum = errno; 1267 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 1268 (me, "door_ucred failed: %s\n", strerror(errnum)); 1269 1270 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, errnum, 1271 NSCD_DOOR_UCRED_ERROR); 1272 } 1273 1274 /* get door client's effective uid */ 1275 uid = ucred_geteuid(uc); 1276 ucred_free(uc); 1277 uc = NULL; 1278 1279 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 1280 (me, "per user get admin ... (uid = %d)\n", uid); 1281 1282 /* is the per-user nscd running ? if not, no one to serve */ 1283 ch = get_cslot(uid, 1); 1284 if (ch == NULL) { 1285 NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, 1286 NSCD_SELF_CRED_NO_CHILD_SLOT); 1287 } 1288 1289 ret = _nscd_doorcall_fd(ch->child_door, NSCD_GETADMIN, 1290 NULL, sizeof (nscd_admin_t), result_mn, 1291 sizeof (nscd_admin_t), phdr); 1292 1293 if (ret == NSS_SUCCESS) { 1294 phdr->data_len = sizeof (nscd_admin_t); 1295 return; 1296 } 1297 } 1298 1299 static void 1300 set_selfcred_cfg( 1301 char param, 1302 void *data) 1303 { 1304 int64_t prop_int; 1305 char *me = "set_selfcred_cfg"; 1306 1307 if (param == 'a' || param == 'e') { 1308 pu_nscd_enabled = *(uint8_t *)get_smf_prop( 1309 "enable_per_user_lookup", 'b', data); 1310 1311 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 1312 (me, "self cred config: enabled = %d\n", pu_nscd_enabled); 1313 } 1314 1315 if (param == 'a' || param == 't') { 1316 prop_int = *(int *)data; 1317 pu_nscd_ttl = *(int64_t *)get_smf_prop( 1318 "per_user_nscd_time_to_live", 'i', &prop_int); 1319 1320 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 1321 (me, "self cred config: PUN TTL = %d\n", pu_nscd_ttl); 1322 } 1323 } 1324 1325 /* ARGSUSED */ 1326 nscd_rc_t 1327 _nscd_cfg_selfcred_notify( 1328 void *data, 1329 struct nscd_cfg_param_desc *pdesc, 1330 nscd_cfg_id_t *nswdb, 1331 nscd_cfg_flag_t dflag, 1332 nscd_cfg_error_t **errorp, 1333 void *cookie) 1334 { 1335 1336 nscd_cfg_global_selfcred_t *sc_cfg = &nscd_selfcred_cfg_g; 1337 int off; 1338 1339 /* 1340 * At init time, the whole group of config params are received. 1341 * At update time, group or individual parameter value could 1342 * be received. 1343 */ 1344 1345 if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) { 1346 1347 *sc_cfg = *(nscd_cfg_global_selfcred_t *)data; 1348 1349 off = offsetof(nscd_cfg_global_selfcred_t, 1350 enable_selfcred); 1351 set_selfcred_cfg('e', (char *)data + off); 1352 1353 off = offsetof(nscd_cfg_global_selfcred_t, 1354 max_per_user_nscd); 1355 set_selfcred_cfg('n', (char *)data + off); 1356 1357 off = offsetof(nscd_cfg_global_selfcred_t, 1358 per_user_nscd_ttl); 1359 set_selfcred_cfg('t', (char *)data + off); 1360 1361 return (NSCD_SUCCESS); 1362 } 1363 1364 /* 1365 * individual config parameter 1366 */ 1367 off = offsetof(nscd_cfg_global_selfcred_t, enable_selfcred); 1368 if (pdesc->p_offset == off) { 1369 sc_cfg->enable_selfcred = *(nscd_bool_t *)data; 1370 set_selfcred_cfg('e', data); 1371 return (NSCD_SUCCESS); 1372 } 1373 1374 off = offsetof(nscd_cfg_global_selfcred_t, max_per_user_nscd); 1375 if (pdesc->p_offset == off) { 1376 sc_cfg->max_per_user_nscd = *(int *)data; 1377 set_selfcred_cfg('n', data); 1378 return (NSCD_SUCCESS); 1379 } 1380 1381 off = offsetof(nscd_cfg_global_selfcred_t, per_user_nscd_ttl); 1382 if (pdesc->p_offset == off) { 1383 sc_cfg->per_user_nscd_ttl = *(int *)data; 1384 set_selfcred_cfg('t', data); 1385 return (NSCD_SUCCESS); 1386 } 1387 1388 return (NSCD_SUCCESS); 1389 } 1390 1391 /* ARGSUSED */ 1392 nscd_rc_t 1393 _nscd_cfg_selfcred_verify( 1394 void *data, 1395 struct nscd_cfg_param_desc *pdesc, 1396 nscd_cfg_id_t *nswdb, 1397 nscd_cfg_flag_t dflag, 1398 nscd_cfg_error_t **errorp, 1399 void **cookie) 1400 { 1401 1402 return (NSCD_SUCCESS); 1403 } 1404 1405 /* ARGSUSED */ 1406 nscd_rc_t 1407 _nscd_cfg_selfcred_get_stat( 1408 void **stat, 1409 struct nscd_cfg_stat_desc *sdesc, 1410 nscd_cfg_id_t *nswdb, 1411 nscd_cfg_flag_t *dflag, 1412 void (**free_stat)(void *stat), 1413 nscd_cfg_error_t **errorp) 1414 { 1415 return (NSCD_SUCCESS); 1416 } 1417 1418 static int 1419 check_uid(char *pid_name) 1420 { 1421 char pname[PATH_MAX]; 1422 static pid_t pid = 0; 1423 static uid_t uid = 0; 1424 static uid_t euid = 0; 1425 int pfd; /* file descriptor for /proc/<pid>/psinfo */ 1426 psinfo_t info; /* process information from /proc */ 1427 1428 if (uid == 0) { 1429 pid = getpid(); 1430 uid = getuid(); 1431 euid = geteuid(); 1432 } 1433 1434 (void) snprintf(pname, sizeof (pname), "/proc/%s/psinfo", pid_name); 1435 retry: 1436 if ((pfd = open(pname, O_RDONLY)) == -1) { 1437 /* Process may have exited */ 1438 return (1); 1439 } 1440 1441 /* 1442 * Get the info structure for the process and close quickly. 1443 */ 1444 if (read(pfd, (char *)&info, sizeof (info)) < 0) { 1445 int saverr = errno; 1446 1447 (void) close(pfd); 1448 if (saverr == EAGAIN) 1449 goto retry; 1450 if (saverr != ENOENT) 1451 return (1); 1452 } 1453 (void) close(pfd); 1454 1455 if (info.pr_pid != pid && 1456 info.pr_uid == uid && info.pr_euid == euid) 1457 return (0); 1458 else 1459 return (1); 1460 } 1461 1462 1463 /* 1464 * FUNCTION: check_user_process 1465 */ 1466 /*ARGSUSED*/ 1467 static void * 1468 check_user_process(void *arg) 1469 { 1470 1471 DIR *dp; 1472 struct dirent *ep; 1473 int found; 1474 char *me = "check_user_process"; 1475 1476 /*CONSTCOND*/ 1477 while (1) { 1478 (void) sleep(60); 1479 1480 found = 0; 1481 1482 /* 1483 * search the /proc directory and look at each process 1484 */ 1485 if ((dp = opendir("/proc")) == NULL) { 1486 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) 1487 (me, "unable to open the /proc directory\n"); 1488 continue; 1489 } 1490 1491 /* for each active process */ 1492 while (ep = readdir(dp)) { 1493 if (ep->d_name[0] == '.') /* skip . and .. */ 1494 continue; 1495 if (check_uid(ep->d_name) == 0) { 1496 found = 1; 1497 break; 1498 } 1499 } 1500 1501 /* 1502 * if no process running as the PUN uid found, exit 1503 * to kill this PUN 1504 */ 1505 if (found == 0) { 1506 (void) closedir(dp); 1507 exit(1); 1508 } 1509 (void) closedir(dp); 1510 } 1511 /* NOTREACHED */ 1512 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ 1513 } 1514 1515 static nscd_rc_t 1516 init_user_proc_monitor() { 1517 1518 int errnum; 1519 char *me = "init_user_proc_monitor"; 1520 1521 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_DEBUG) 1522 (me, "initializing the user process monitor\n"); 1523 1524 /* 1525 * start a thread to make sure there is at least a process 1526 * running as the PUN user. If not, terminate this PUN. 1527 */ 1528 if (thr_create(NULL, NULL, check_user_process, 1529 NULL, THR_DETACHED, NULL) != 0) { 1530 errnum = errno; 1531 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ERROR) 1532 (me, "thr_create: %s\n", strerror(errnum)); 1533 return (NSCD_THREAD_CREATE_ERROR); 1534 } 1535 1536 return (NSCD_SUCCESS); 1537 } 1538 1539 static void * 1540 get_smf_prop(const char *var, char type, void *def_val) 1541 { 1542 scf_simple_prop_t *prop; 1543 void *val = def_val; 1544 char *me = "get_smf_prop"; 1545 1546 prop = scf_simple_prop_get(NULL, NULL, "config", var); 1547 if (prop) { 1548 switch (type) { 1549 case 'b': 1550 val = scf_simple_prop_next_boolean(prop); 1551 break; 1552 1553 case 'i': 1554 val = scf_simple_prop_next_integer(prop); 1555 break; 1556 1557 case 'c': 1558 val = scf_simple_prop_next_count(prop); 1559 break; 1560 } 1561 scf_simple_prop_free(prop); 1562 } 1563 1564 if (prop == NULL || val == NULL) { 1565 char vs[64]; 1566 1567 switch (type) { 1568 case 'b': 1569 if (*(uint8_t *)def_val) 1570 (void) strcpy(vs, "yes"); 1571 else 1572 (void) strcpy(vs, "no"); 1573 1574 break; 1575 1576 case 'i': 1577 case 'c': 1578 (void) sprintf(vs, "%lld", *(int64_t *)def_val); 1579 break; 1580 1581 } 1582 _NSCD_LOG(NSCD_LOG_SELF_CRED, NSCD_LOG_LEVEL_ALERT) 1583 (me, "no value for config/%s (%s). " 1584 "Using default \"%s\"\n", var, 1585 scf_strerror(scf_error()), vs); 1586 } 1587 1588 return (val); 1589 } 1590