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