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