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
picld_return_error(picl_callnumber_t cnum,picl_errno_t err)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
picld_init(picl_service_t * req)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
picld_fini(picl_service_t * in)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
picld_ping(picl_service_t * in)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
check_user(uid_t uid)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
done_user(uid_t uid)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
enter_picld_wait(uid_t uid)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
exit_picld_wait(uid_t uid)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
picld_wait(picl_service_t * in)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
picld_getroot(picl_service_t * in)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
picld_get_attrval(picl_service_t * in)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
picld_get_attrval_by_name(picl_service_t * in)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
picld_set_attrval(picl_service_t * in)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
picld_set_attrval_by_name(picl_service_t * in)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
picld_get_attrinfo(picl_service_t * in)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
picld_get_first_attr(picl_service_t * in)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
picld_get_next_attr(picl_service_t * in)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
picld_get_attr_by_name(picl_service_t * in)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
picld_get_attr_by_row(picl_service_t * in)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
picld_get_attr_by_col(picl_service_t * in)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
picld_find_node(picl_service_t * in)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
picld_get_node_by_path(picl_service_t * in)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
picld_get_frutree_parent(picl_service_t * in)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
picld_unknown_service(picl_service_t * in)763 picld_unknown_service(picl_service_t *in)
764 {
765 picld_return_error(in->in.cnum, PICL_UNKNOWNSERVICE);
766 }
767
768 static void
check_denial_of_service(int cnum)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
picld_door_handler(void * cookie,char * argp,size_t asize,door_desc_t * dp,uint_t n_desc)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
hup_handler(int sig,siginfo_t * siginfo,void * sigctx)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
daemon_exists(void)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 *
picld_create_server_thread(void * arg)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
picld_server_create_fn(door_info_t * dip)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
setup_door(void)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
main(int argc,char ** argv)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