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 * Copyright 2005 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 != (door_ptr_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_UNREF | 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 if ((newfd = creat(PICLD_DOOR, 0444)) < 0) 882 return (-1); 883 (void) close(newfd); 884 } 885 886 if (fattach(door_id, PICLD_DOOR) < 0) { 887 if ((errno != EBUSY) || 888 (fdetach(PICLD_DOOR) < 0) || 889 (fattach(door_id, PICLD_DOOR) < 0)) 890 return (-1); 891 } 892 893 return (0); 894 } 895 896 /* 897 * Main function of picl daemon 898 */ 899 int 900 main(int argc, char **argv) 901 { 902 struct sigaction act; 903 int c; 904 sigset_t ublk; 905 906 907 (void) setlocale(LC_ALL, ""); 908 (void) textdomain(TEXT_DOMAIN); 909 910 if (getuid() != 0) { 911 syslog(LOG_CRIT, MUST_BE_ROOT); 912 return (0); 913 } 914 915 (void) rwlock_init(&init_lk, USYNC_THREAD, NULL); 916 doreinit = 0; 917 logflag = 1; 918 dos_req_limit = DOS_PICL_REQUESTS_LIMIT; 919 sliding_interval_ms = SLIDING_INTERVAL_MILLISECONDS; 920 dos_ms = DOS_SLEEPTIME_MS; 921 verbose_level = 0; 922 923 /* 924 * parse arguments 925 */ 926 while ((c = getopt(argc, argv, "is:t:l:r:v:d:")) != EOF) { 927 switch (c) { 928 case 'd': 929 dos_ms = strtol(optarg, (char **)NULL, 0); 930 break; 931 case 'i': 932 logflag = 0; 933 break; 934 case 's': 935 sliding_interval_ms = strtoll(optarg, (char **)NULL, 0); 936 break; 937 case 't': 938 dos_req_limit = strtol(optarg, (char **)NULL, 0); 939 break; 940 case 'v': 941 verbose_level = strtol(optarg, (char **)NULL, 0); 942 logflag = 0; 943 break; 944 default: 945 break; 946 } 947 } 948 949 orig_time = gethrtime(); 950 951 /* 952 * is there a daemon already running? 953 */ 954 955 if (daemon_exists()) { 956 syslog(LOG_CRIT, DAEMON_RUNNING); 957 exit(1); 958 } 959 960 /* 961 * Mask off/block SIGALRM signal so that the environmental plug-in 962 * (piclenvd) can use it to simulate sleep() without being affected 963 * by time being set back. No other PICL plug-in should use SIGALRM 964 * or alarm() for now. 965 */ 966 (void) sigemptyset(&ublk); 967 (void) sigaddset(&ublk, SIGALRM); 968 (void) sigprocmask(SIG_BLOCK, &ublk, NULL); 969 970 /* 971 * Ignore SIGHUP until all the initialization is done. 972 */ 973 act.sa_handler = SIG_IGN; 974 (void) sigemptyset(&act.sa_mask); 975 act.sa_flags = 0; 976 if (sigaction(SIGHUP, &act, NULL) == -1) 977 syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGHUP), 978 strerror(errno)); 979 980 if (logflag != 0) { /* daemonize */ 981 pid_t pid; 982 983 pid = fork(); 984 if (pid < 0) 985 exit(1); 986 if (pid > 0) 987 /* parent */ 988 exit(0); 989 990 /* child */ 991 if (chdir("/") == -1) { 992 syslog(LOG_CRIT, CD_ROOT_FAILED); 993 exit(1); 994 } 995 996 (void) setsid(); 997 (void) close(STDIN_FILENO); 998 (void) close(STDOUT_FILENO); 999 (void) close(STDERR_FILENO); 1000 (void) open("/dev/null", O_RDWR, 0); 1001 (void) dup2(STDIN_FILENO, STDOUT_FILENO); 1002 (void) dup2(STDIN_FILENO, STDERR_FILENO); 1003 openlog(PICLD, LOG_PID, LOG_DAEMON); 1004 } 1005 1006 /* 1007 * Initialize the PICL Tree 1008 */ 1009 if (xptree_initialize(NULL) != PICL_SUCCESS) { 1010 syslog(LOG_CRIT, INIT_FAILED); 1011 exit(1); 1012 } 1013 1014 if (setup_door()) { 1015 syslog(LOG_CRIT, DOOR_FAILED); 1016 exit(1); 1017 } 1018 1019 /* 1020 * setup signal handlers for post-init 1021 */ 1022 act.sa_sigaction = hup_handler; 1023 (void) sigemptyset(&act.sa_mask); 1024 act.sa_flags = SA_SIGINFO; 1025 if (sigaction(SIGHUP, &act, NULL) == -1) 1026 syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGHUP), 1027 strerror(errno)); 1028 1029 /* 1030 * wait for requests 1031 */ 1032 for (;;) { 1033 (void) pause(); 1034 if (doreinit) { 1035 /* 1036 * Block SIGHUP during reinitialization. 1037 * Also mask off/block SIGALRM signal so that the 1038 * environmental plug-in (piclenvd) can use it to 1039 * simulate sleep() without being affected by time 1040 * being set back. No ohter PICL plug-in should use 1041 * SIGALRM or alarm() for now. 1042 */ 1043 (void) sigemptyset(&ublk); 1044 (void) sigaddset(&ublk, SIGHUP); 1045 (void) sigaddset(&ublk, SIGALRM); 1046 (void) sigprocmask(SIG_BLOCK, &ublk, NULL); 1047 (void) sigdelset(&ublk, SIGALRM); 1048 doreinit = 0; 1049 (void) rw_wrlock(&init_lk); 1050 xptree_destroy(); 1051 (void) xptree_reinitialize(); 1052 (void) rw_unlock(&init_lk); 1053 (void) sigprocmask(SIG_UNBLOCK, &ublk, NULL); 1054 } 1055 } 1056 } 1057