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