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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * PICL daemon 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <stdarg.h> 36 #include <string.h> 37 #include <libintl.h> 38 #include <locale.h> 39 #include <alloca.h> 40 #include <errno.h> 41 #include <assert.h> 42 #include <stropts.h> 43 #include <unistd.h> 44 #include <signal.h> 45 #include <pthread.h> 46 #include <synch.h> 47 #include <door.h> 48 #include <sys/door.h> 49 #include <fcntl.h> 50 #include <dlfcn.h> 51 #include <time.h> 52 #include <sys/utsname.h> 53 #include <sys/systeminfo.h> 54 #include <sys/stat.h> 55 #include <sys/wait.h> 56 #include <dirent.h> 57 #include <syslog.h> 58 #include <poll.h> 59 #include <limits.h> 60 #include <picl.h> 61 #include "picl2door.h" 62 #include <picltree.h> 63 #include "ptree_impl.h" 64 65 /* 66 * Log text messages 67 */ 68 #define MUST_BE_ROOT gettext("this program must be run as root\n") 69 #define CD_ROOT_FAILED gettext("chdir to root failed\n") 70 #define INIT_FAILED gettext("ptree initialization failed\n") 71 #define DAEMON_RUNNING gettext("PICL daemon already running\n") 72 #define DOOR_FAILED gettext("Failed creating picld door\n") 73 #define SIGACT_FAILED \ 74 gettext("Failed to install signal handler for %s: %s\n") 75 76 /* 77 * Constants 78 */ 79 #define PICLD "picld" 80 #define DOS_PICL_REQUESTS_LIMIT 10000 81 #define SLIDING_INTERVAL_MILLISECONDS 1000 82 #define PICLD_MAJOR_REV 0x1 83 #define PICLD_MINOR_REV 0x0 84 #define DOS_SLEEPTIME_MS 1000 85 #define MAX_POOL_SIZE _POSIX_THREAD_THREADS_MAX 86 #define MAX_CONCURRENT_WAITS (_POSIX_THREAD_THREADS_MAX - 2) 87 #define MAX_USER_WAITS 4 88 89 /* 90 * Macros 91 */ 92 #define PICLD_VERSION(x, y) ((x << 8) | y) 93 #define PICL_CLIENT_REV(x) (x & 0xff) 94 #define MILLI_TO_NANO(x) (x * 1000000) 95 96 extern char **environ; 97 98 /* 99 * Module Variables 100 */ 101 static int logflag = 1; 102 static int doreinit = 0; 103 static int door_id = -1; 104 static pthread_mutex_t door_mutex = PTHREAD_MUTEX_INITIALIZER; 105 static pthread_cond_t door_cv = PTHREAD_COND_INITIALIZER; 106 static int service_requests = 0; 107 static hrtime_t orig_time; 108 static hrtime_t sliding_interval_ms; 109 static uint32_t dos_req_limit; 110 static uint32_t dos_ms; 111 static pthread_mutex_t dos_mutex = PTHREAD_MUTEX_INITIALIZER; 112 static rwlock_t init_lk; 113 static int pool_count = 0; 114 static pthread_mutex_t pool_mutex = PTHREAD_MUTEX_INITIALIZER; 115 static pthread_mutex_t wait_req_mutex = PTHREAD_MUTEX_INITIALIZER; 116 static int wait_count = 0; 117 static struct { 118 uid_t uid; 119 int count; 120 } user_count[MAX_CONCURRENT_WAITS]; 121 122 /* 123 * This returns an error message to libpicl 124 */ 125 static void 126 picld_return_error(picl_callnumber_t cnum, picl_errno_t err) 127 { 128 picl_reterror_t ret_error; 129 130 ret_error.cnum = PICL_CNUM_ERROR; 131 ret_error.in_cnum = cnum; 132 ret_error.errnum = err; 133 (void) rw_unlock(&init_lk); 134 (void) door_return((char *)&ret_error, sizeof (picl_reterror_t), NULL, 135 0); 136 } 137 138 /* 139 * picld_init is called when a picl_initialize request is received 140 */ 141 static void 142 picld_init(picl_service_t *req) 143 { 144 picl_retinit_t ret_init; 145 int clmajrev; 146 147 clmajrev = PICL_CLIENT_REV(req->req_init.clrev); 148 149 if (clmajrev < PICL_VERSION_1) 150 picld_return_error(req->req_init.cnum, PICL_NOTSUPPORTED); 151 152 ret_init.cnum = req->req_init.cnum; 153 ret_init.rev = PICLD_VERSION(PICLD_MAJOR_REV, PICLD_MINOR_REV); 154 155 (void) rw_unlock(&init_lk); 156 (void) door_return((char *)&ret_init, sizeof (picl_retinit_t), NULL, 0); 157 } 158 159 /* 160 * picld_fini is called when a picl_shutdown request is received 161 */ 162 static void 163 picld_fini(picl_service_t *in) 164 { 165 picl_retfini_t ret; 166 167 ret.cnum = in->req_fini.cnum; 168 169 (void) rw_unlock(&init_lk); 170 (void) door_return((char *)&ret, sizeof (picl_retfini_t), NULL, 0); 171 } 172 173 static void 174 picld_ping(picl_service_t *in) 175 { 176 picl_retping_t ret; 177 178 ret.cnum = in->req_ping.cnum; 179 180 (void) rw_unlock(&init_lk); 181 (void) door_return((char *)&ret, sizeof (picl_retping_t), NULL, 0); 182 } 183 184 static int 185 check_user(uid_t uid) 186 { 187 int i; 188 uid_t tmp_uid; 189 int free_idx = -1; 190 191 if (uid == 0) 192 return (PICL_SUCCESS); 193 for (i = 0; i < MAX_CONCURRENT_WAITS; i++) { 194 if ((tmp_uid = user_count[i].uid) == uid) { 195 if (user_count[i].count == MAX_USER_WAITS) 196 return (PICL_FAILURE); 197 user_count[i].count++; 198 return (PICL_SUCCESS); 199 } 200 if ((free_idx == -1) && (tmp_uid == 0)) 201 free_idx = i; 202 } 203 if (free_idx != -1) { 204 user_count[free_idx].uid = uid; 205 user_count[free_idx].count = 1; 206 return (PICL_SUCCESS); 207 } 208 return (PICL_FAILURE); 209 } 210 211 static void 212 done_user(uid_t uid) 213 { 214 int i; 215 216 if (uid == 0) 217 return; 218 for (i = 0; i < MAX_CONCURRENT_WAITS; i++) { 219 if (user_count[i].uid == uid) { 220 if (--user_count[i].count == 0) 221 user_count[i].uid = 0; 222 return; 223 } 224 } 225 } 226 227 static int 228 enter_picld_wait(uid_t uid) 229 { 230 int rv; 231 232 if (pthread_mutex_lock(&wait_req_mutex) != 0) 233 return (PICL_FAILURE); 234 if ((wait_count < MAX_CONCURRENT_WAITS) && 235 (check_user(uid) == PICL_SUCCESS)) { 236 rv = PICL_SUCCESS; 237 wait_count++; 238 } else { 239 rv = PICL_FAILURE; 240 } 241 (void) pthread_mutex_unlock(&wait_req_mutex); 242 return (rv); 243 } 244 245 static void 246 exit_picld_wait(uid_t uid) 247 { 248 (void) pthread_mutex_lock(&wait_req_mutex); 249 done_user(uid); 250 wait_count--; 251 (void) pthread_mutex_unlock(&wait_req_mutex); 252 } 253 254 /* 255 * picld_wait is called when a picl_wait request is received 256 */ 257 static void 258 picld_wait(picl_service_t *in) 259 { 260 picl_retwait_t ret; 261 int err; 262 ucred_t *puc = NULL; 263 uid_t uid; 264 265 ret.cnum = in->req_wait.cnum; 266 if (door_ucred(&puc) != 0) 267 ret.retcode = PICL_FAILURE; 268 else { 269 uid = ucred_geteuid(puc); 270 if (enter_picld_wait(uid) == PICL_FAILURE) 271 ret.retcode = PICL_FAILURE; 272 else { 273 err = xptree_refresh_notify(in->req_wait.secs); 274 ret.retcode = err; 275 exit_picld_wait(uid); 276 } 277 ucred_free(puc); 278 } 279 (void) rw_unlock(&init_lk); 280 (void) door_return((char *)&ret, sizeof (picl_retwait_t), NULL, 0); 281 } 282 283 /* 284 * This function returns the handle of the root node of the PICL tree 285 */ 286 static void 287 picld_getroot(picl_service_t *in) 288 { 289 picl_retroot_t ret; 290 int err; 291 292 ret.cnum = PICL_CNUM_GETROOT; 293 err = ptree_get_root(&ret.rnode); 294 if (err != PICL_SUCCESS) 295 picld_return_error(in->in.cnum, err); 296 cvt_ptree2picl(&ret.rnode); 297 (void) rw_unlock(&init_lk); 298 (void) door_return((char *)&ret, sizeof (picl_retroot_t), NULL, 0); 299 } 300 301 /* 302 * This function returns the value of the PICL property 303 */ 304 static void 305 picld_get_attrval(picl_service_t *in) 306 { 307 picl_retattrval_t *ret; 308 int err; 309 size_t vbufsize; 310 size_t len; 311 door_cred_t cred; 312 picl_prophdl_t ptreeh; 313 ptree_propinfo_t pinfo; 314 315 if (door_cred(&cred) < 0) 316 picld_return_error(in->in.cnum, PICL_FAILURE); 317 318 err = cvt_picl2ptree(in->req_attrval.attr, &ptreeh); 319 if (err != PICL_SUCCESS) 320 picld_return_error(in->in.cnum, err); 321 322 err = ptree_get_propinfo(ptreeh, &pinfo); 323 if (err != PICL_SUCCESS) 324 picld_return_error(in->in.cnum, err); 325 326 if (!(pinfo.piclinfo.accessmode & PICL_READ)) 327 picld_return_error(in->in.cnum, PICL_NOTREADABLE); 328 329 vbufsize = pinfo.piclinfo.size; 330 vbufsize = MIN((size_t)in->req_attrval.bufsize, vbufsize); 331 332 len = sizeof (picl_retattrval_t) + vbufsize; 333 ret = alloca(len); 334 if (ret == NULL) 335 picld_return_error(in->in.cnum, PICL_FAILURE); 336 ret->cnum = PICL_CNUM_GETATTRVAL; 337 ret->attr = in->req_attrval.attr; 338 ret->nbytes = (uint32_t)vbufsize; 339 err = xptree_get_propval_with_cred(ptreeh, ret->ret_buf, vbufsize, 340 cred); 341 if (err != PICL_SUCCESS) 342 picld_return_error(in->in.cnum, err); 343 344 /* 345 * adjust returned bytes for charstrings 346 */ 347 if (pinfo.piclinfo.type == PICL_PTYPE_CHARSTRING) 348 ret->nbytes = (uint32_t)strlen(ret->ret_buf) + 1; 349 350 /* 351 * convert handle values to picl handles 352 */ 353 if ((pinfo.piclinfo.type == PICL_PTYPE_TABLE) || 354 (pinfo.piclinfo.type == PICL_PTYPE_REFERENCE)) 355 cvt_ptree2picl(&ret->ret_nodeh); 356 (void) rw_unlock(&init_lk); 357 (void) door_return((char *)ret, sizeof (picl_retattrval_t) + 358 (size_t)ret->nbytes, NULL, 0); 359 } 360 361 /* 362 * This function returns the value of the PICL property specified by 363 * its name. 364 */ 365 static void 366 picld_get_attrval_by_name(picl_service_t *in) 367 { 368 picl_retattrvalbyname_t *ret; 369 int err; 370 size_t vbufsize; 371 size_t len; 372 door_cred_t cred; 373 picl_nodehdl_t ptreeh; 374 ptree_propinfo_t pinfo; 375 376 if (door_cred(&cred) < 0) 377 picld_return_error(in->in.cnum, PICL_FAILURE); 378 379 err = cvt_picl2ptree(in->req_attrvalbyname.nodeh, &ptreeh); 380 if (err != PICL_SUCCESS) 381 picld_return_error(in->in.cnum, err); 382 383 err = xptree_get_propinfo_by_name(ptreeh, 384 in->req_attrvalbyname.propname, &pinfo); 385 if (err != PICL_SUCCESS) 386 picld_return_error(in->in.cnum, err); 387 388 if (!(pinfo.piclinfo.accessmode & PICL_READ)) 389 picld_return_error(in->in.cnum, PICL_NOTREADABLE); 390 391 /* 392 * allocate the minimum of piclinfo.size and input bufsize 393 */ 394 vbufsize = pinfo.piclinfo.size; 395 vbufsize = MIN((size_t)in->req_attrvalbyname.bufsize, vbufsize); 396 len = sizeof (picl_retattrvalbyname_t) + vbufsize; 397 ret = alloca(len); 398 if (ret == NULL) 399 picld_return_error(in->in.cnum, PICL_FAILURE); 400 ret->cnum = PICL_CNUM_GETATTRVALBYNAME; 401 ret->nodeh = in->req_attrvalbyname.nodeh; 402 (void) strcpy(ret->propname, in->req_attrvalbyname.propname); 403 ret->nbytes = (uint32_t)vbufsize; 404 405 err = xptree_get_propval_by_name_with_cred(ptreeh, 406 in->req_attrvalbyname.propname, ret->ret_buf, vbufsize, 407 cred); 408 if (err != PICL_SUCCESS) 409 picld_return_error(in->in.cnum, err); 410 /* 411 * adjust returned value size for charstrings 412 */ 413 if (pinfo.piclinfo.type == PICL_PTYPE_CHARSTRING) 414 ret->nbytes = (uint32_t)strlen(ret->ret_buf) + 1; 415 416 if ((pinfo.piclinfo.type == PICL_PTYPE_TABLE) || 417 (pinfo.piclinfo.type == PICL_PTYPE_REFERENCE)) 418 cvt_ptree2picl(&ret->ret_nodeh); 419 420 (void) rw_unlock(&init_lk); 421 (void) door_return((char *)ret, sizeof (picl_retattrvalbyname_t) + 422 (size_t)ret->nbytes, NULL, 0); 423 } 424 425 /* 426 * This function sets a property value 427 */ 428 static void 429 picld_set_attrval(picl_service_t *in) 430 { 431 picl_retsetattrval_t ret; 432 int err; 433 door_cred_t cred; 434 picl_prophdl_t ptreeh; 435 ptree_propinfo_t pinfo; 436 437 if (door_cred(&cred) < 0) 438 picld_return_error(in->in.cnum, PICL_FAILURE); 439 440 err = cvt_picl2ptree(in->req_setattrval.attr, &ptreeh); 441 if (err != PICL_SUCCESS) 442 picld_return_error(in->in.cnum, err); 443 444 err = ptree_get_propinfo(ptreeh, &pinfo); 445 if (err != PICL_SUCCESS) 446 picld_return_error(in->in.cnum, err); 447 448 if (!(pinfo.piclinfo.accessmode & PICL_WRITE)) 449 picld_return_error(in->in.cnum, PICL_NOTWRITABLE); 450 /* 451 * For non-volatile prop, only super user can set its value. 452 */ 453 if (!(pinfo.piclinfo.accessmode & PICL_VOLATILE) && 454 (cred.dc_euid != SUPER_USER)) 455 picld_return_error(in->in.cnum, PICL_PERMDENIED); 456 457 ret.cnum = PICL_CNUM_SETATTRVAL; 458 ret.attr = in->req_setattrval.attr; 459 460 err = xptree_update_propval_with_cred(ptreeh, in->req_setattrval.valbuf, 461 (size_t)in->req_setattrval.bufsize, cred); 462 463 if (err != PICL_SUCCESS) 464 picld_return_error(in->in.cnum, err); 465 466 (void) rw_unlock(&init_lk); 467 (void) door_return((char *)&ret, sizeof (picl_retsetattrval_t), NULL, 468 0); 469 } 470 471 /* 472 * This function sets the value of a property specified by its name. 473 */ 474 static void 475 picld_set_attrval_by_name(picl_service_t *in) 476 { 477 picl_retsetattrvalbyname_t ret; 478 int err; 479 door_cred_t cred; 480 picl_prophdl_t ptreeh; 481 ptree_propinfo_t pinfo; 482 483 if (door_cred(&cred) < 0) 484 picld_return_error(in->in.cnum, PICL_FAILURE); 485 486 err = cvt_picl2ptree(in->req_setattrvalbyname.nodeh, &ptreeh); 487 if (err != PICL_SUCCESS) 488 picld_return_error(in->in.cnum, err); 489 490 err = xptree_get_propinfo_by_name(ptreeh, 491 in->req_setattrvalbyname.propname, &pinfo); 492 if (err != PICL_SUCCESS) 493 picld_return_error(in->in.cnum, err); 494 495 if (!(pinfo.piclinfo.accessmode & PICL_WRITE)) 496 picld_return_error(in->in.cnum, PICL_NOTWRITABLE); 497 498 /* 499 * For non-volatile prop, only super user can set its value. 500 */ 501 if (!(pinfo.piclinfo.accessmode & PICL_VOLATILE) && 502 (cred.dc_euid != SUPER_USER)) 503 picld_return_error(in->in.cnum, PICL_PERMDENIED); 504 505 ret.cnum = PICL_CNUM_SETATTRVALBYNAME; 506 ret.nodeh = in->req_setattrvalbyname.nodeh; 507 (void) strcpy(ret.propname, in->req_setattrvalbyname.propname); 508 509 err = xptree_update_propval_by_name_with_cred(ptreeh, 510 in->req_setattrvalbyname.propname, 511 in->req_setattrvalbyname.valbuf, 512 (size_t)in->req_setattrvalbyname.bufsize, 513 cred); 514 515 if (err != PICL_SUCCESS) 516 picld_return_error(in->in.cnum, err); 517 518 (void) rw_unlock(&init_lk); 519 (void) door_return((char *)&ret, sizeof (picl_retsetattrvalbyname_t), 520 NULL, 0); 521 } 522 523 /* 524 * This function returns the property information 525 */ 526 static void 527 picld_get_attrinfo(picl_service_t *in) 528 { 529 picl_retattrinfo_t ret; 530 int err; 531 ptree_propinfo_t pinfo; 532 picl_prophdl_t ptreeh; 533 534 err = cvt_picl2ptree(in->req_attrinfo.attr, &ptreeh); 535 if (err != PICL_SUCCESS) 536 picld_return_error(in->in.cnum, err); 537 538 ret.cnum = PICL_CNUM_GETATTRINFO; 539 ret.attr = in->req_attrinfo.attr; 540 541 err = ptree_get_propinfo(ptreeh, &pinfo); 542 if (err != PICL_SUCCESS) 543 picld_return_error(in->in.cnum, err); 544 545 ret.type = pinfo.piclinfo.type; 546 ret.accessmode = pinfo.piclinfo.accessmode; 547 ret.size = (uint32_t)pinfo.piclinfo.size; 548 (void) strcpy(ret.name, pinfo.piclinfo.name); 549 (void) rw_unlock(&init_lk); 550 (void) door_return((char *)&ret, sizeof (picl_retattrinfo_t), NULL, 0); 551 } 552 553 /* 554 * This function returns the node's first property handle 555 */ 556 static void 557 picld_get_first_attr(picl_service_t *in) 558 { 559 picl_retfirstattr_t ret; 560 int err; 561 picl_prophdl_t ptreeh; 562 563 err = cvt_picl2ptree(in->req_firstattr.nodeh, &ptreeh); 564 if (err != PICL_SUCCESS) 565 picld_return_error(in->in.cnum, err); 566 567 ret.cnum = PICL_CNUM_GETFIRSTATTR; 568 ret.nodeh = in->req_firstattr.nodeh; 569 570 err = ptree_get_first_prop(ptreeh, &ret.attr); 571 if (err != PICL_SUCCESS) 572 picld_return_error(in->in.cnum, err); 573 cvt_ptree2picl(&ret.attr); 574 (void) rw_unlock(&init_lk); 575 (void) door_return((char *)&ret, sizeof (picl_retfirstattr_t), NULL, 0); 576 } 577 578 /* 579 * This function returns the next property handle in list 580 */ 581 static void 582 picld_get_next_attr(picl_service_t *in) 583 { 584 picl_retnextattr_t ret; 585 int err; 586 picl_prophdl_t ptreeh; 587 588 err = cvt_picl2ptree(in->req_nextattr.attr, &ptreeh); 589 if (err != PICL_SUCCESS) 590 picld_return_error(in->in.cnum, err); 591 592 ret.cnum = PICL_CNUM_GETNEXTATTR; 593 ret.attr = in->req_nextattr.attr; 594 595 err = ptree_get_next_prop(ptreeh, &ret.nextattr); 596 if (err != PICL_SUCCESS) 597 picld_return_error(in->in.cnum, err); 598 599 cvt_ptree2picl(&ret.nextattr); 600 601 (void) rw_unlock(&init_lk); 602 (void) door_return((char *)&ret, sizeof (picl_retnextattr_t), NULL, 0); 603 } 604 605 /* 606 * This function returns the handle of a property specified by its name 607 */ 608 static void 609 picld_get_attr_by_name(picl_service_t *in) 610 { 611 picl_retattrbyname_t ret; 612 int err; 613 picl_prophdl_t ptreeh; 614 615 err = cvt_picl2ptree(in->req_attrbyname.nodeh, &ptreeh); 616 if (err != PICL_SUCCESS) 617 picld_return_error(in->in.cnum, err); 618 619 ret.cnum = PICL_CNUM_GETATTRBYNAME; 620 ret.nodeh = in->req_attrbyname.nodeh; 621 (void) strcpy(ret.propname, in->req_attrbyname.propname); 622 623 err = ptree_get_prop_by_name(ptreeh, ret.propname, &ret.attr); 624 if (err != PICL_SUCCESS) 625 picld_return_error(in->in.cnum, err); 626 627 cvt_ptree2picl(&ret.attr); 628 (void) rw_unlock(&init_lk); 629 (void) door_return((char *)&ret, sizeof (picl_retattrbyname_t), NULL, 630 0); 631 } 632 633 /* 634 * This function gets the next property on the same row in the table 635 */ 636 static void 637 picld_get_attr_by_row(picl_service_t *in) 638 { 639 picl_retattrbyrow_t ret; 640 int err; 641 picl_prophdl_t ptreeh; 642 643 err = cvt_picl2ptree(in->req_attrbyrow.attr, &ptreeh); 644 if (err != PICL_SUCCESS) 645 picld_return_error(in->in.cnum, err); 646 647 ret.cnum = PICL_CNUM_GETATTRBYROW; 648 ret.attr = in->req_attrbyrow.attr; 649 650 err = ptree_get_next_by_row(ptreeh, &ret.rowattr); 651 if (err != PICL_SUCCESS) 652 picld_return_error(in->in.cnum, err); 653 cvt_ptree2picl(&ret.rowattr); 654 655 (void) rw_unlock(&init_lk); 656 (void) door_return((char *)&ret, sizeof (picl_retattrbyrow_t), NULL, 0); 657 } 658 659 /* 660 * This function returns the handle of the next property in the same column 661 * of the table. 662 */ 663 static void 664 picld_get_attr_by_col(picl_service_t *in) 665 { 666 picl_retattrbycol_t ret; 667 int err; 668 picl_prophdl_t ptreeh; 669 670 err = cvt_picl2ptree(in->req_attrbycol.attr, &ptreeh); 671 if (err != PICL_SUCCESS) 672 picld_return_error(in->in.cnum, err); 673 674 ret.cnum = PICL_CNUM_GETATTRBYCOL; 675 ret.attr = in->req_attrbycol.attr; 676 677 err = ptree_get_next_by_col(ptreeh, &ret.colattr); 678 if (err != PICL_SUCCESS) 679 picld_return_error(in->in.cnum, err); 680 681 cvt_ptree2picl(&ret.colattr); 682 683 (void) rw_unlock(&init_lk); 684 (void) door_return((char *)&ret, sizeof (picl_retattrbycol_t), NULL, 0); 685 } 686 687 /* 688 * This function finds the node in the PICLTREE that matches the given 689 * criteria and returns its handle. 690 */ 691 static void 692 picld_find_node(picl_service_t *in) 693 { 694 picl_retfindnode_t ret; 695 int err; 696 picl_nodehdl_t ptreeh; 697 698 err = cvt_picl2ptree(in->req_findnode.nodeh, &ptreeh); 699 if (err != PICL_SUCCESS) 700 picld_return_error(in->in.cnum, err); 701 702 ret.cnum = PICL_CNUM_FINDNODE; 703 704 err = ptree_find_node(ptreeh, in->req_findnode.propname, 705 in->req_findnode.ptype, in->req_findnode.valbuf, 706 in->req_findnode.valsize, &ret.rnodeh); 707 if (err != PICL_SUCCESS) 708 picld_return_error(in->in.cnum, err); 709 710 cvt_ptree2picl(&ret.rnodeh); 711 712 (void) rw_unlock(&init_lk); 713 (void) door_return((char *)&ret, sizeof (ret), NULL, 0); 714 } 715 716 /* 717 * This function finds the property/node that corresponds to the given path 718 * and returns its handle 719 */ 720 static void 721 picld_get_node_by_path(picl_service_t *in) 722 { 723 picl_retnodebypath_t ret; 724 int err; 725 726 ret.cnum = PICL_CNUM_NODEBYPATH; 727 err = ptree_get_node_by_path(in->req_nodebypath.pathbuf, &ret.nodeh); 728 if (err != PICL_SUCCESS) 729 picld_return_error(in->in.cnum, err); 730 cvt_ptree2picl(&ret.nodeh); 731 (void) rw_unlock(&init_lk); 732 (void) door_return((char *)&ret, sizeof (ret), NULL, 0); 733 } 734 735 /* 736 * This function returns finds the frutree parent node for a given node 737 * and returns its handle 738 */ 739 static void 740 picld_get_frutree_parent(picl_service_t *in) 741 { 742 picl_retfruparent_t ret; 743 int err; 744 picl_nodehdl_t ptreeh; 745 746 err = cvt_picl2ptree(in->req_fruparent.devh, &ptreeh); 747 if (err != PICL_SUCCESS) 748 picld_return_error(in->in.cnum, err); 749 750 ret.cnum = PICL_CNUM_FRUTREEPARENT; 751 752 err = ptree_get_frutree_parent(ptreeh, &ret.fruh); 753 if (err != PICL_SUCCESS) 754 picld_return_error(in->in.cnum, err); 755 cvt_ptree2picl(&ret.fruh); 756 757 (void) rw_unlock(&init_lk); 758 (void) door_return((char *)&ret, sizeof (ret), NULL, 0); 759 } 760 761 /* 762 * This function is called when an unknown client request is received. 763 */ 764 static void 765 picld_unknown_service(picl_service_t *in) 766 { 767 picld_return_error(in->in.cnum, PICL_UNKNOWNSERVICE); 768 } 769 770 static void 771 check_denial_of_service(int cnum) 772 { 773 hrtime_t window; 774 hrtime_t current; 775 int dos_flag; 776 777 current = gethrtime(); 778 dos_flag = 0; 779 780 if (pthread_mutex_lock(&dos_mutex) != 0) 781 picld_return_error(cnum, PICL_FAILURE); 782 783 ++service_requests; 784 window = current - orig_time; 785 if (window > MILLI_TO_NANO(sliding_interval_ms)) { 786 orig_time = current; 787 service_requests = 1; 788 } 789 790 if (service_requests > dos_req_limit) 791 dos_flag = 1; 792 793 if (pthread_mutex_unlock(&dos_mutex) != 0) 794 picld_return_error(cnum, PICL_FAILURE); 795 796 if (dos_flag) 797 (void) poll(NULL, 0, dos_ms); 798 } 799 800 /* ARGSUSED */ 801 static void 802 picld_door_handler(void *cookie, char *argp, size_t asize, 803 door_desc_t *dp, uint_t n_desc) 804 { 805 picl_service_t *req; 806 807 /*LINTED*/ 808 req = (picl_service_t *)argp; 809 810 if (req == NULL) 811 (void) door_return((char *)req, 0, NULL, 0); 812 813 check_denial_of_service(req->in.cnum); 814 815 (void) rw_rdlock(&init_lk); 816 switch (req->in.cnum) { /* client call number */ 817 case PICL_CNUM_INIT: 818 /*LINTED*/ 819 picld_init((picl_service_t *)argp); 820 break; 821 case PICL_CNUM_FINI: 822 /*LINTED*/ 823 picld_fini((picl_service_t *)argp); 824 break; 825 case PICL_CNUM_GETROOT: 826 /*LINTED*/ 827 picld_getroot((picl_service_t *)argp); 828 break; 829 case PICL_CNUM_GETATTRVAL: 830 /*LINTED*/ 831 picld_get_attrval((picl_service_t *)argp); 832 break; 833 case PICL_CNUM_GETATTRVALBYNAME: 834 /*LINTED*/ 835 picld_get_attrval_by_name((picl_service_t *)argp); 836 break; 837 case PICL_CNUM_GETATTRINFO: 838 /*LINTED*/ 839 picld_get_attrinfo((picl_service_t *)argp); 840 break; 841 case PICL_CNUM_GETFIRSTATTR: 842 /*LINTED*/ 843 picld_get_first_attr((picl_service_t *)argp); 844 break; 845 case PICL_CNUM_GETNEXTATTR: 846 /*LINTED*/ 847 picld_get_next_attr((picl_service_t *)argp); 848 break; 849 case PICL_CNUM_GETATTRBYNAME: 850 /*LINTED*/ 851 picld_get_attr_by_name((picl_service_t *)argp); 852 break; 853 case PICL_CNUM_GETATTRBYROW: 854 /*LINTED*/ 855 picld_get_attr_by_row((picl_service_t *)argp); 856 break; 857 case PICL_CNUM_GETATTRBYCOL: 858 /*LINTED*/ 859 picld_get_attr_by_col((picl_service_t *)argp); 860 break; 861 case PICL_CNUM_SETATTRVAL: 862 /*LINTED*/ 863 picld_set_attrval((picl_service_t *)argp); 864 break; 865 case PICL_CNUM_SETATTRVALBYNAME: 866 /*LINTED*/ 867 picld_set_attrval_by_name((picl_service_t *)argp); 868 break; 869 case PICL_CNUM_PING: 870 /*LINTED*/ 871 picld_ping((picl_service_t *)argp); 872 break; 873 case PICL_CNUM_WAIT: 874 /*LINTED*/ 875 picld_wait((picl_service_t *)argp); 876 break; 877 case PICL_CNUM_FINDNODE: 878 /*LINTED*/ 879 picld_find_node((picl_service_t *)argp); 880 break; 881 case PICL_CNUM_NODEBYPATH: 882 /*LINTED*/ 883 picld_get_node_by_path((picl_service_t *)argp); 884 break; 885 case PICL_CNUM_FRUTREEPARENT: 886 /*LINTED*/ 887 picld_get_frutree_parent((picl_service_t *)argp); 888 break; 889 default: 890 /*LINTED*/ 891 picld_unknown_service((picl_service_t *)argp); 892 break; 893 }; 894 /*NOTREACHED*/ 895 } 896 897 /* ARGSUSED */ 898 static void 899 hup_handler(int sig, siginfo_t *siginfo, void *sigctx) 900 { 901 doreinit = 1; 902 } 903 904 /* 905 * "ping" to see if a daemon is already running 906 */ 907 static int 908 daemon_exists(void) 909 { 910 door_arg_t darg; 911 picl_reqping_t req_ping; 912 picl_retping_t ret_ping; 913 int doorh; 914 door_info_t dinfo; 915 916 doorh = open(PICLD_DOOR, O_RDONLY); 917 if (doorh < 0) 918 return (0); 919 920 if (door_info(doorh, &dinfo) < 0) { 921 (void) close(doorh); 922 return (0); 923 } 924 925 if ((dinfo.di_attributes & DOOR_REVOKED) || 926 (dinfo.di_data != (uintptr_t)PICLD_DOOR_COOKIE)) { 927 (void) close(doorh); 928 return (0); 929 } 930 931 if (dinfo.di_target != getpid()) { 932 (void) close(doorh); 933 return (1); 934 } 935 936 req_ping.cnum = PICL_CNUM_PING; 937 938 darg.data_ptr = (char *)&req_ping; 939 darg.data_size = sizeof (picl_reqping_t); 940 darg.desc_ptr = NULL; 941 darg.desc_num = 0; 942 darg.rbuf = (char *)&ret_ping; 943 darg.rsize = sizeof (picl_retping_t); 944 945 if (door_call(doorh, &darg) < 0) { 946 (void) close(doorh); 947 return (0); 948 } 949 950 (void) close(doorh); 951 return (1); 952 } 953 954 /* 955 * picld_create_server_thread - binds the running thread to the private 956 * door pool, and sets the required cancellation state. 957 */ 958 /* ARGSUSED */ 959 static void * 960 picld_create_server_thread(void *arg) 961 { 962 /* 963 * wait for door descriptor to be initialized 964 */ 965 (void) pthread_mutex_lock(&door_mutex); 966 while (door_id == -1) { 967 (void) pthread_cond_wait(&door_cv, &door_mutex); 968 } 969 (void) pthread_mutex_unlock(&door_mutex); 970 971 /* 972 * Bind this thread to the door's private thread pool 973 */ 974 if (door_bind(door_id) < 0) { 975 perror("door_bind"); 976 } 977 978 /* 979 * Disable thread cancellation mechanism 980 */ 981 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 982 (void) door_return(NULL, 0, NULL, 0); /* wait for door invocation */ 983 return (NULL); 984 } 985 986 /* 987 * picld_server_create_fn - creates threads for the private door pool 988 * 989 */ 990 /* ARGSUSED */ 991 static void 992 picld_server_create_fn(door_info_t *dip) 993 { 994 pthread_attr_t attr; 995 996 (void) pthread_mutex_lock(&pool_mutex); 997 if (pool_count < MAX_POOL_SIZE) { 998 (void) pthread_attr_init(&attr); 999 (void) pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 1000 (void) pthread_attr_setdetachstate(&attr, 1001 PTHREAD_CREATE_DETACHED); 1002 if (pthread_create(NULL, &attr, picld_create_server_thread, 1003 NULL)) { 1004 perror("pthread_create"); 1005 } else { 1006 pool_count++; 1007 } 1008 } 1009 (void) pthread_mutex_unlock(&pool_mutex); 1010 } 1011 1012 /* 1013 * Create the picld door 1014 */ 1015 static int 1016 setup_door(void) 1017 { 1018 struct stat stbuf; 1019 1020 (void) door_server_create(picld_server_create_fn); 1021 (void) pthread_mutex_lock(&door_mutex); 1022 /* 1023 * Create the door 1024 */ 1025 door_id = door_create(picld_door_handler, PICLD_DOOR_COOKIE, 1026 DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_PRIVATE); 1027 1028 if (door_id < 0) { 1029 (void) pthread_mutex_unlock(&door_mutex); 1030 return (-1); 1031 } else { 1032 (void) pthread_cond_signal(&door_cv); 1033 (void) pthread_mutex_unlock(&door_mutex); 1034 } 1035 1036 if (stat(PICLD_DOOR, &stbuf) < 0) { 1037 int newfd; 1038 mode_t old_mask; 1039 /* ensure that the door file is world-readable */ 1040 old_mask = umask(0); 1041 newfd = creat(PICLD_DOOR, 0444); 1042 /* restore the file mode creation mask */ 1043 (void) umask(old_mask); 1044 if (newfd < 0) 1045 return (-1); 1046 (void) close(newfd); 1047 } 1048 1049 if (fattach(door_id, PICLD_DOOR) < 0) { 1050 if ((errno != EBUSY) || 1051 (fdetach(PICLD_DOOR) < 0) || 1052 (fattach(door_id, PICLD_DOOR) < 0)) 1053 return (-1); 1054 } 1055 return (0); 1056 } 1057 1058 /* 1059 * Main function of picl daemon 1060 */ 1061 int 1062 main(int argc, char **argv) 1063 { 1064 struct sigaction act; 1065 int c; 1066 sigset_t ublk; 1067 1068 1069 (void) setlocale(LC_ALL, ""); 1070 (void) textdomain(TEXT_DOMAIN); 1071 1072 if (getuid() != 0) { 1073 syslog(LOG_CRIT, MUST_BE_ROOT); 1074 return (0); 1075 } 1076 1077 (void) rwlock_init(&init_lk, USYNC_THREAD, NULL); 1078 doreinit = 0; 1079 logflag = 1; 1080 dos_req_limit = DOS_PICL_REQUESTS_LIMIT; 1081 sliding_interval_ms = SLIDING_INTERVAL_MILLISECONDS; 1082 dos_ms = DOS_SLEEPTIME_MS; 1083 verbose_level = 0; 1084 1085 /* 1086 * parse arguments 1087 */ 1088 while ((c = getopt(argc, argv, "is:t:l:r:v:d:")) != EOF) { 1089 switch (c) { 1090 case 'd': 1091 dos_ms = strtol(optarg, (char **)NULL, 0); 1092 break; 1093 case 'i': 1094 logflag = 0; 1095 break; 1096 case 's': 1097 sliding_interval_ms = strtoll(optarg, (char **)NULL, 0); 1098 break; 1099 case 't': 1100 dos_req_limit = strtol(optarg, (char **)NULL, 0); 1101 break; 1102 case 'v': 1103 verbose_level = strtol(optarg, (char **)NULL, 0); 1104 logflag = 0; 1105 break; 1106 default: 1107 break; 1108 } 1109 } 1110 1111 orig_time = gethrtime(); 1112 1113 /* 1114 * is there a daemon already running? 1115 */ 1116 1117 if (daemon_exists()) { 1118 syslog(LOG_CRIT, DAEMON_RUNNING); 1119 exit(1); 1120 } 1121 1122 /* 1123 * Mask off/block SIGALRM signal so that the environmental plug-in 1124 * (piclenvd) can use it to simulate sleep() without being affected 1125 * by time being set back. No other PICL plug-in should use SIGALRM 1126 * or alarm() for now. 1127 */ 1128 (void) sigemptyset(&ublk); 1129 (void) sigaddset(&ublk, SIGALRM); 1130 (void) sigprocmask(SIG_BLOCK, &ublk, NULL); 1131 1132 /* 1133 * Ignore SIGHUP until all the initialization is done. 1134 */ 1135 act.sa_handler = SIG_IGN; 1136 (void) sigemptyset(&act.sa_mask); 1137 act.sa_flags = 0; 1138 if (sigaction(SIGHUP, &act, NULL) == -1) 1139 syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGHUP), 1140 strerror(errno)); 1141 1142 if (logflag != 0) { /* daemonize */ 1143 pid_t pid; 1144 1145 pid = fork(); 1146 if (pid < 0) 1147 exit(1); 1148 if (pid > 0) 1149 /* parent */ 1150 exit(0); 1151 1152 /* child */ 1153 if (chdir("/") == -1) { 1154 syslog(LOG_CRIT, CD_ROOT_FAILED); 1155 exit(1); 1156 } 1157 1158 (void) setsid(); 1159 (void) close(STDIN_FILENO); 1160 (void) close(STDOUT_FILENO); 1161 (void) close(STDERR_FILENO); 1162 (void) open("/dev/null", O_RDWR, 0); 1163 (void) dup2(STDIN_FILENO, STDOUT_FILENO); 1164 (void) dup2(STDIN_FILENO, STDERR_FILENO); 1165 openlog(PICLD, LOG_PID, LOG_DAEMON); 1166 } 1167 1168 /* 1169 * Initialize the PICL Tree 1170 */ 1171 if (xptree_initialize(NULL) != PICL_SUCCESS) { 1172 syslog(LOG_CRIT, INIT_FAILED); 1173 exit(1); 1174 } 1175 1176 if (setup_door()) { 1177 syslog(LOG_CRIT, DOOR_FAILED); 1178 exit(1); 1179 } 1180 1181 /* 1182 * setup signal handlers for post-init 1183 */ 1184 act.sa_sigaction = hup_handler; 1185 (void) sigemptyset(&act.sa_mask); 1186 act.sa_flags = SA_SIGINFO; 1187 if (sigaction(SIGHUP, &act, NULL) == -1) 1188 syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGHUP), 1189 strerror(errno)); 1190 1191 /* 1192 * wait for requests 1193 */ 1194 for (;;) { 1195 (void) pause(); 1196 if (doreinit) { 1197 /* 1198 * Block SIGHUP during reinitialization. 1199 * Also mask off/block SIGALRM signal so that the 1200 * environmental plug-in (piclenvd) can use it to 1201 * simulate sleep() without being affected by time 1202 * being set back. No ohter PICL plug-in should use 1203 * SIGALRM or alarm() for now. 1204 */ 1205 (void) sigemptyset(&ublk); 1206 (void) sigaddset(&ublk, SIGHUP); 1207 (void) sigaddset(&ublk, SIGALRM); 1208 (void) sigprocmask(SIG_BLOCK, &ublk, NULL); 1209 (void) sigdelset(&ublk, SIGALRM); 1210 doreinit = 0; 1211 (void) rw_wrlock(&init_lk); 1212 xptree_destroy(); 1213 (void) xptree_reinitialize(); 1214 (void) rw_unlock(&init_lk); 1215 (void) sigprocmask(SIG_UNBLOCK, &ublk, NULL); 1216 } 1217 } 1218 } 1219