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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Routines used by inetd to read inetd's configuration from the repository,
28 * to validate it and setup inetd's data structures appropriately based on
29 * in.
30 */
31
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <netdb.h>
37 #include <netinet/in.h>
38 #include <libintl.h>
39 #include <nss_dbdefs.h>
40 #include <signal.h>
41 #include <wait.h>
42 #include "inetd_impl.h"
43
44
45 /* method timeout used if one isn't explicitly specified */
46 #define DEFAULT_METHOD_TIMEOUT 10
47
48
49 /* supported method properties and their attributes */
50 static inetd_prop_t method_props[] = {
51 {PR_EXEC_NAME, "", INET_TYPE_STRING, B_FALSE, IVE_UNSET, 0, B_FALSE},
52 {PR_ARG0_NAME, "", INET_TYPE_STRING, B_TRUE, IVE_UNSET, 0, B_FALSE},
53 {SCF_PROPERTY_TIMEOUT, "", INET_TYPE_COUNT, B_TRUE, IVE_UNSET, 0, B_FALSE},
54 {NULL},
55 };
56
57 /* enumeration of method properties; used to index into method_props[] */
58 typedef enum {
59 MP_EXEC,
60 MP_ARG0,
61 MP_TIMEOUT
62 } method_prop_t;
63
64
65 /* handle used for repository access in read_prop() */
66 static scf_handle_t *rep_handle = NULL;
67
68 /* pool used to create proto_info_t lists (generic proto info structure) */
69 static uu_list_pool_t *proto_info_pool = NULL;
70
71 static void destroy_method_props(inetd_prop_t *);
72 static int proto_info_compare(const void *, const void *, void *);
73
74 int
config_init(void)75 config_init(void)
76 {
77 if ((rep_handle = scf_handle_create(SCF_VERSION)) == NULL) {
78 error_msg("%s: %s",
79 gettext("Failed to create repository handle"),
80 scf_strerror(scf_error()));
81 return (-1);
82 } else if (make_handle_bound(rep_handle) == -1) {
83 /* let config_fini clean-up */
84 return (-1);
85 }
86
87 if ((proto_info_pool = uu_list_pool_create("proto_info_pool",
88 sizeof (proto_info_t), offsetof(proto_info_t, link),
89 proto_info_compare, UU_LIST_POOL_DEBUG)) == NULL) {
90 error_msg(gettext("Failed to create uu list pool: %s"),
91 uu_strerror(uu_error()));
92 return (-1);
93 }
94
95 return (0);
96 }
97
98 void
config_fini(void)99 config_fini(void)
100 {
101 if (rep_handle == NULL)
102 return;
103
104 if (proto_info_pool != NULL) {
105 uu_list_pool_destroy(proto_info_pool);
106 proto_info_pool = NULL;
107 }
108
109 (void) scf_handle_unbind(rep_handle);
110 scf_handle_destroy(rep_handle);
111 rep_handle = NULL;
112 }
113
114 static void
destroy_method_info(method_info_t * mi)115 destroy_method_info(method_info_t *mi)
116 {
117 if (mi == NULL)
118 return;
119
120 if (mi->wordexp_arg0_backup != NULL) {
121 /*
122 * Return the wordexp structure back to its original
123 * state so it can be consumed by wordfree.
124 */
125 free(mi->exec_args_we.we_wordv[0]);
126 mi->exec_args_we.we_wordv[0] =
127 (char *)mi->wordexp_arg0_backup;
128 }
129
130 free(mi->exec_path);
131
132 wordfree(&mi->exec_args_we);
133
134 free(mi);
135 }
136
137 /*
138 * Transforms the properties read from the repository for a method into a
139 * method_info_t and returns a pointer to it. If expansion of the exec
140 * property fails, due to an invalid string or memory allocation failure,
141 * NULL is returned and exec_invalid is set appropriately to indicate whether
142 * it was a memory allocation failure or an invalid exec string.
143 */
144 static method_info_t *
create_method_info(const inetd_prop_t * mprops,boolean_t * exec_invalid)145 create_method_info(const inetd_prop_t *mprops, boolean_t *exec_invalid)
146 {
147 method_info_t *ret;
148 int i;
149
150 if ((ret = calloc(1, sizeof (method_info_t))) == NULL)
151 goto alloc_fail;
152
153 /* Expand the exec string. */
154 if ((i = wordexp(get_prop_value_string(mprops, PR_EXEC_NAME),
155 &ret->exec_args_we, WRDE_NOCMD|WRDE_UNDEF)) != 0) {
156 if (i == WRDE_NOSPACE)
157 goto alloc_fail;
158
159 *exec_invalid = B_TRUE;
160 free(ret);
161 return (NULL);
162 }
163
164 if ((ret->exec_path = strdup(ret->exec_args_we.we_wordv[0])) == NULL)
165 goto alloc_fail;
166
167 if (mprops[MP_ARG0].ip_error == IVE_VALID) { /* arg0 is set */
168 /*
169 * Keep a copy of arg0 of the wordexp structure so that
170 * wordfree() gets passed what wordexp() originally returned,
171 * as documented as required in the man page.
172 */
173 ret->wordexp_arg0_backup = ret->exec_args_we.we_wordv[0];
174 if ((ret->exec_args_we.we_wordv[0] =
175 strdup(get_prop_value_string(mprops, PR_ARG0_NAME)))
176 == NULL)
177 goto alloc_fail;
178 }
179
180 if (mprops[MP_TIMEOUT].ip_error == IVE_VALID) {
181 ret->timeout = get_prop_value_count(mprops,
182 SCF_PROPERTY_TIMEOUT);
183 } else {
184 ret->timeout = DEFAULT_METHOD_TIMEOUT;
185 }
186
187 /* exec_invalid not set on success */
188
189 return (ret);
190
191 alloc_fail:
192 error_msg(strerror(errno));
193 destroy_method_info(ret);
194 *exec_invalid = B_FALSE;
195 return (NULL);
196 }
197
198 /*
199 * Returns B_TRUE if the contents of the 2 method_info_t structures are
200 * equivalent, else B_FALSE.
201 */
202 boolean_t
method_info_equal(const method_info_t * mi,const method_info_t * mi2)203 method_info_equal(const method_info_t *mi, const method_info_t *mi2)
204 {
205 int i;
206
207 if ((mi == NULL) && (mi2 == NULL)) {
208 return (B_TRUE);
209 } else if (((mi == NULL) || (mi2 == NULL)) ||
210 (mi->exec_args_we.we_wordc != mi2->exec_args_we.we_wordc) ||
211 (strcmp(mi->exec_path, mi2->exec_path) != 0)) {
212 return (B_FALSE);
213 }
214
215 for (i = 0; i < mi->exec_args_we.we_wordc; i++) {
216 if (strcmp(mi->exec_args_we.we_wordv[i],
217 mi2->exec_args_we.we_wordv[i]) != 0) {
218 return (B_FALSE);
219 }
220 }
221
222 return (B_TRUE);
223 }
224
225 /*
226 * Checks if the contents of the 2 socket_info_t structures are equivalent.
227 * If 'isrpc' is false, the address components of the two structures are
228 * compared for equality as part of this. If the two structures are
229 * equivalent B_TRUE is returned, else B_FALSE.
230 */
231 boolean_t
socket_info_equal(const socket_info_t * si,const socket_info_t * si2,boolean_t isrpc)232 socket_info_equal(const socket_info_t *si, const socket_info_t *si2,
233 boolean_t isrpc)
234 {
235 return ((isrpc || (memcmp(&si->local_addr, &si2->local_addr,
236 sizeof (si->local_addr)) == 0)) &&
237 (si->type == si2->type));
238
239 }
240
241 /*
242 * proto_info_t comparison function. Returns 0 on match, else -1, as required
243 * by uu_list_find().
244 */
245 static int
proto_info_compare(const void * lv,const void * rv,void * istlx)246 proto_info_compare(const void *lv, const void *rv, void *istlx)
247 {
248 proto_info_t *pi = (proto_info_t *)lv;
249 proto_info_t *pi2 = (proto_info_t *)rv;
250
251 /* check their RPC configuration matches */
252 if (pi->ri != NULL) {
253 if ((pi2->ri == NULL) || !rpc_info_equal(pi->ri, pi2->ri))
254 return (-1);
255 } else if (pi2->ri != NULL) {
256 return (-1);
257 }
258
259 if (pi->v6only != pi2->v6only)
260 return (-1);
261
262 if (*(boolean_t *)istlx) {
263 if (tlx_info_equal((tlx_info_t *)lv, (tlx_info_t *)rv,
264 pi->ri != NULL))
265 return (0);
266 } else {
267 if (socket_info_equal((socket_info_t *)lv,
268 (socket_info_t *)rv, pi->ri != NULL))
269 return (0);
270 }
271 return (-1);
272 }
273
274 /*
275 * Returns B_TRUE if the bind configuration of the two instance_cfg_t
276 * structures are equivalent, else B_FALSE.
277 */
278 boolean_t
bind_config_equal(const basic_cfg_t * c1,const basic_cfg_t * c2)279 bind_config_equal(const basic_cfg_t *c1, const basic_cfg_t *c2)
280 {
281 proto_info_t *pi;
282
283 if ((c1->iswait != c2->iswait) ||
284 (c1->istlx != c2->istlx))
285 return (B_FALSE);
286
287 if (uu_list_numnodes(c1->proto_list) !=
288 uu_list_numnodes(c2->proto_list))
289 return (B_FALSE);
290 /*
291 * For each element in the first configuration's socket/tlx list,
292 * check there's a matching one in the other list.
293 */
294 for (pi = uu_list_first(c1->proto_list); pi != NULL;
295 pi = uu_list_next(c1->proto_list, pi)) {
296 uu_list_index_t idx;
297
298 if (uu_list_find(c2->proto_list, pi, (void *)&c1->istlx,
299 &idx) == NULL)
300 return (B_FALSE);
301 }
302
303 return (B_TRUE);
304 }
305
306 /*
307 * Write the default values contained in 'bprops', read by
308 * read_instance_props(), into 'cfg'.
309 * Returns -1 if memory allocation fails, else 0.
310 */
311 static int
populate_defaults(inetd_prop_t * bprops,basic_cfg_t * cfg)312 populate_defaults(inetd_prop_t *bprops, basic_cfg_t *cfg)
313 {
314 cfg->do_tcp_wrappers = get_prop_value_boolean(bprops,
315 PR_DO_TCP_WRAPPERS_NAME);
316 cfg->do_tcp_trace = get_prop_value_boolean(bprops,
317 PR_DO_TCP_TRACE_NAME);
318 cfg->do_tcp_keepalive = get_prop_value_boolean(bprops,
319 PR_DO_TCP_KEEPALIVE_NAME);
320 cfg->inherit_env = get_prop_value_boolean(bprops, PR_INHERIT_ENV_NAME);
321 cfg->wait_fail_cnt = get_prop_value_int(bprops,
322 PR_MAX_FAIL_RATE_CNT_NAME);
323 cfg->wait_fail_interval = get_prop_value_int(bprops,
324 PR_MAX_FAIL_RATE_INTVL_NAME);
325 cfg->max_copies = get_prop_value_int(bprops, PR_MAX_COPIES_NAME);
326 cfg->conn_rate_offline = get_prop_value_int(bprops,
327 PR_CON_RATE_OFFLINE_NAME);
328 cfg->conn_rate_max = get_prop_value_int(bprops, PR_CON_RATE_MAX_NAME);
329 cfg->bind_fail_interval = get_prop_value_int(bprops,
330 PR_BIND_FAIL_INTVL_NAME);
331 cfg->bind_fail_max = get_prop_value_int(bprops, PR_BIND_FAIL_MAX_NAME);
332 cfg->conn_backlog = get_prop_value_int(bprops,
333 PR_CONNECTION_BACKLOG_NAME);
334 if ((cfg->bind_addr =
335 strdup(get_prop_value_string(bprops, PR_BIND_ADDR_NAME))) == NULL) {
336 error_msg(strerror(errno));
337 return (-1);
338 }
339 return (0);
340 }
341
342 void
destroy_method_infos(method_info_t ** mis)343 destroy_method_infos(method_info_t **mis)
344 {
345 int i;
346
347 for (i = 0; i < NUM_METHODS; i++) {
348 destroy_method_info(mis[i]);
349 mis[i] = NULL;
350 }
351 }
352
353 /*
354 * For each method, if it was specifed convert its entry in 'mprops',
355 * into an entry in 'mis'. Returns -1 if memory allocation fails or one of the
356 * exec strings was invalid, else 0.
357 */
358 static int
create_method_infos(const char * fmri,inetd_prop_t ** mprops,method_info_t ** mis)359 create_method_infos(const char *fmri, inetd_prop_t **mprops,
360 method_info_t **mis)
361 {
362 int i;
363
364 for (i = 0; i < NUM_METHODS; i++) {
365 /*
366 * Only create a method info structure if the method properties
367 * contain an exec string, which we take to mean the method
368 * is specified.
369 */
370 if (mprops[i][MP_EXEC].ip_error == IVE_VALID) {
371 boolean_t exec_invalid;
372
373 if ((mis[i] = create_method_info(mprops[i],
374 &exec_invalid)) == NULL) {
375 if (exec_invalid) {
376 error_msg(gettext("Property %s for "
377 "method %s of instance %s is "
378 "invalid"), PR_EXEC_NAME,
379 methods[i].name, fmri);
380 }
381 return (-1);
382 }
383 }
384 }
385 return (0);
386 }
387
388 /*
389 * Try and read each of the method properties for the method 'method' of
390 * instance 'inst', and return a table containing all method properties. If an
391 * error occurs, NULL is returned, with 'err' set to indicate the cause.
392 * Otherwise, a pointer to an inetd_prop_t table is returned containing all
393 * the method properties, and each of the properties is flagged according to
394 * whether it was present or not, and if it was present its value is set in
395 * the property's entry in the table.
396 */
397 static inetd_prop_t *
read_method_props(const char * inst,instance_method_t method,scf_error_t * err)398 read_method_props(const char *inst, instance_method_t method, scf_error_t *err)
399 {
400 inetd_prop_t *ret;
401 int i;
402
403 if ((ret = calloc(1, sizeof (method_props))) == NULL) {
404 *err = SCF_ERROR_NO_MEMORY;
405 return (NULL);
406 }
407
408 (void) memcpy(ret, method_props, sizeof (method_props));
409 for (i = 0; ret[i].ip_name != NULL; i++) {
410 *err = read_prop(rep_handle, &ret[i], i, inst,
411 methods[method].name);
412 if ((*err != 0) && (*err != SCF_ERROR_NOT_FOUND)) {
413 destroy_method_props(ret);
414 return (NULL);
415 }
416 }
417
418 return (ret);
419 }
420
421 static void
destroy_method_props(inetd_prop_t * mprop)422 destroy_method_props(inetd_prop_t *mprop)
423 {
424 int i;
425
426 if (mprop == NULL)
427 return;
428
429 for (i = 0; mprop[i].ip_name != NULL; i++) {
430 if (mprop[i].ip_type == INET_TYPE_STRING &&
431 mprop[i].ip_error == IVE_VALID)
432 free(mprop[i].ip_value.iv_string);
433 }
434
435 free(mprop);
436 }
437
438 /*
439 * Destroy the basic and method properties returned by read_inst_props().
440 */
441 static void
destroy_inst_props(inetd_prop_t * bprops,inetd_prop_t ** mprops)442 destroy_inst_props(inetd_prop_t *bprops, inetd_prop_t **mprops)
443 {
444 int i;
445
446 free_instance_props(bprops);
447 for (i = 0; i < NUM_METHODS; i++)
448 destroy_method_props(mprops[i]);
449 }
450
451 /*
452 * Read all the basic and method properties for instance 'inst', as inetd_prop_t
453 * tables, into the spaces referenced by 'bprops' and 'mprops' respectively.
454 * Each of the properties in the tables are flagged to indicate if the
455 * property was present or not, and if it was the value is stored within it.
456 * If an error occurs at any time -1 is returned and 'err' is set to
457 * indicate the reason, else 0 is returned.
458 */
459 static int
read_inst_props(const char * fmri,inetd_prop_t ** bprops,inetd_prop_t ** mprops,scf_error_t * err)460 read_inst_props(const char *fmri, inetd_prop_t **bprops,
461 inetd_prop_t **mprops, scf_error_t *err)
462 {
463 size_t nprops;
464 int i;
465
466 if ((*bprops = read_instance_props(rep_handle, (char *)fmri, &nprops,
467 err)) == NULL)
468 return (-1);
469
470 for (i = 0; i < NUM_METHODS; i++) {
471 if ((mprops[i] =
472 read_method_props(fmri, (instance_method_t)i, err)) ==
473 NULL) {
474 for (i--; i >= 0; i--)
475 destroy_method_props(mprops[i]);
476 free_instance_props(*bprops);
477 return (-1);
478 }
479 }
480
481 return (0);
482 }
483
484 /*
485 * Returns B_TRUE if all required properties were read from the repository
486 * (whether taken from the defaults or directly from the instance), they
487 * all had valid values, all the required methods were present, and they
488 * each had the required properties with valid values. Else, returns B_FALSE.
489 * If the function returns B_TRUE, the storage referenced by 'cfg' is set
490 * to point at an allocated instance_cfg_t initialized based on the basic
491 * properties (not method or defaults).
492 */
493 static boolean_t
valid_inst_props(const char * fmri,inetd_prop_t * bprops,inetd_prop_t ** mprops,basic_cfg_t ** cfg)494 valid_inst_props(const char *fmri, inetd_prop_t *bprops, inetd_prop_t **mprops,
495 basic_cfg_t **cfg)
496 {
497 boolean_t valid;
498 size_t num_bprops;
499 int i;
500
501 valid = valid_props(bprops, fmri, cfg, proto_info_pool, conn_ind_pool);
502
503 /*
504 * Double check we've got all necessary properties (valid_props()
505 * doesn't enforce the presence of defaults), and output error messages
506 * for each invalid/ missing property.
507 */
508 (void) get_prop_table(&num_bprops);
509 for (i = 0; bprops[i].ip_name != NULL; i++) {
510 switch (bprops[i].ip_error) {
511 case IVE_UNSET:
512 if (!bprops[i].ip_default)
513 continue;
514 if ((i == PT_ARG0_INDEX) || (i == PT_EXEC_INDEX))
515 continue;
516 /* FALLTHROUGH */
517 case IVE_INVALID:
518 error_msg(gettext("Property '%s' of instance "
519 "%s is missing, inconsistent or invalid"),
520 bprops[i].ip_name, fmri);
521 valid = B_FALSE;
522 }
523 }
524
525 for (i = 0; i < NUM_METHODS; i++) {
526 int j;
527
528 /* check if any properties are set */
529 for (j = 0; mprops[i][j].ip_name != NULL; j++) {
530 if (mprops[i][j].ip_error != IVE_UNSET)
531 break;
532 }
533
534 if (mprops[i][j].ip_name == NULL) {
535 /* an unspecified method */
536 if ((instance_method_t)i == IM_START) {
537 error_msg(gettext(
538 "Unspecified %s method for instance %s"),
539 START_METHOD_NAME, fmri);
540 valid = B_FALSE;
541 }
542 } else if (mprops[i][MP_EXEC].ip_error == IVE_UNSET) {
543 error_msg(gettext("Missing %s property from method %s "
544 "of instance %s"), PR_EXEC_NAME,
545 methods[(instance_method_t)i].name, fmri);
546 valid = B_FALSE;
547 }
548 }
549
550 if (!valid) {
551 destroy_basic_cfg(*cfg);
552 *cfg = NULL;
553 }
554
555 return (valid);
556 }
557
558 void
destroy_instance_cfg(instance_cfg_t * cfg)559 destroy_instance_cfg(instance_cfg_t *cfg)
560 {
561 if (cfg != NULL) {
562 destroy_basic_cfg(cfg->basic);
563 destroy_method_infos(cfg->methods);
564 free(cfg);
565 }
566 }
567
568 /*
569 * Returns an allocated instance_cfg_t representation of an instance's
570 * configuration read from the repository. If the configuration is invalid, a
571 * repository error occurred, or a memory allocation occurred returns NULL,
572 * else returns a pointer to the allocated instance_cfg_t.
573 */
574 instance_cfg_t *
read_instance_cfg(const char * fmri)575 read_instance_cfg(const char *fmri)
576 {
577 uint_t retries;
578 inetd_prop_t *bprops;
579 inetd_prop_t *mprops[NUM_METHODS];
580 instance_cfg_t *ret = NULL;
581 scf_error_t err;
582
583 if ((ret = calloc(1, sizeof (instance_cfg_t))) == NULL)
584 return (NULL);
585
586 for (retries = 0; retries <= REP_OP_RETRIES; retries++) {
587 if (make_handle_bound(rep_handle) == -1) {
588 err = scf_error();
589 goto read_error;
590 }
591
592 if (read_inst_props(fmri, &bprops, mprops, &err) == 0)
593 break;
594 if (err != SCF_ERROR_CONNECTION_BROKEN)
595 goto read_error;
596 (void) scf_handle_unbind(rep_handle);
597 }
598 if (retries > REP_OP_RETRIES)
599 goto read_error;
600
601 /*
602 * Switch off validation of the start method's exec string, since
603 * during boot the filesystem it resides on may not have been
604 * mounted yet, which would result in a false validation failure.
605 * We'll catch any real errors when the start method is first run
606 * in passes_basic_exec_checks().
607 */
608 bprops[PT_EXEC_INDEX].ip_error = IVE_UNSET;
609
610 if ((!valid_inst_props(fmri, bprops, mprops, &ret->basic)) ||
611 (populate_defaults(bprops, ret->basic) != 0) ||
612 (create_method_infos(fmri, mprops, ret->methods) != 0)) {
613 destroy_instance_cfg(ret);
614 ret = NULL;
615 }
616
617 destroy_inst_props(bprops, mprops);
618 return (ret);
619
620 read_error:
621 error_msg(gettext(
622 "Failed to read the configuration of instance %s: %s"), fmri,
623 scf_strerror(err));
624 free(ret);
625 return (NULL);
626 }
627
628 /*
629 * Returns a pointer to an allocated method context for the specified method
630 * of the specified instance if it could retrieve it. Else, if there were
631 * errors retrieving it, NULL is returned and the pointer referenced by
632 * 'errstr' is set to point at an appropriate error string.
633 */
634 struct method_context *
read_method_context(const char * inst_fmri,const char * method,const char * path)635 read_method_context(const char *inst_fmri, const char *method, const char *path)
636 {
637 scf_instance_t *scf_inst = NULL;
638 struct method_context *ret;
639 uint_t retries;
640 mc_error_t *tmperr;
641 char *fail;
642
643 fail = gettext("Failed to retrieve method context for the %s method of "
644 "instance %s : %s");
645 for (retries = 0; retries <= REP_OP_RETRIES; retries++) {
646 if (make_handle_bound(rep_handle) == -1)
647 goto inst_failure;
648
649 if (((scf_inst = scf_instance_create(rep_handle)) != NULL) &&
650 (scf_handle_decode_fmri(rep_handle, inst_fmri, NULL, NULL,
651 scf_inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0))
652 break;
653 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) {
654 scf_instance_destroy(scf_inst);
655 goto inst_failure;
656 }
657
658 (void) scf_instance_destroy(scf_inst);
659 scf_inst = NULL;
660
661 (void) scf_handle_unbind(rep_handle);
662 }
663 if (retries > REP_OP_RETRIES)
664 goto inst_failure;
665
666 if ((tmperr = restarter_get_method_context(
667 RESTARTER_METHOD_CONTEXT_VERSION, scf_inst, NULL, method, path,
668 &ret)) != NULL) {
669 ret = NULL;
670 error_msg(fail, method, inst_fmri, tmperr->msg);
671 restarter_mc_error_destroy(tmperr);
672 }
673
674 scf_instance_destroy(scf_inst);
675 return (ret);
676
677 inst_failure:
678 /*
679 * We can rely on this string not becoming invalid
680 * since we don't call bind_textdomain_codeset() or
681 * setlocale(3C) after initialization.
682 */
683 error_msg(fail, method, inst_fmri,
684 gettext("failed to get instance from repository"));
685 return (NULL);
686 }
687
688 /*
689 * Reads the value of the enabled property from the named property group
690 * of the given instance.
691 * If an error occurs, the SCF error code is returned. The possible errors are:
692 * - SCF_ERROR_INVALID_ARGUMENT: The enabled property is not a boolean.
693 * - SCF_ERROR_NONE: No value exists for the enabled property.
694 * - SCF_ERROR_CONNECTION_BROKEN: Repository connection broken.
695 * - SCF_ERROR_NOT_FOUND: The property wasn't found.
696 * - SCF_ERROR_NO_MEMORY: allocation failure.
697 * Else 0 is returned and 'enabled' set appropriately.
698 */
699 static scf_error_t
read_enable_prop(const char * fmri,boolean_t * enabled,const char * pg)700 read_enable_prop(const char *fmri, boolean_t *enabled, const char *pg)
701 {
702 scf_simple_prop_t *sp;
703 uint8_t *u8p;
704
705 if ((sp = scf_simple_prop_get(rep_handle, fmri, pg,
706 SCF_PROPERTY_ENABLED)) == NULL)
707 return (scf_error());
708
709 if ((u8p = scf_simple_prop_next_boolean(sp)) == NULL) {
710 scf_simple_prop_free(sp);
711 return (scf_error());
712 }
713
714 *enabled = (*u8p != 0);
715 scf_simple_prop_free(sp);
716 return (0);
717 }
718
719 /*
720 * Reads the enabled value for the given instance FMRI. The read value
721 * is based on a merge of the 'standard' enabled property, and the temporary
722 * override one; the merge involves using the latter properties value if
723 * present, else resporting to the formers. If an error occurs -1 is returned,
724 * else 0 is returned and 'enabled' set approriately.
725 */
726 int
read_enable_merged(const char * fmri,boolean_t * enabled)727 read_enable_merged(const char *fmri, boolean_t *enabled)
728 {
729 uint_t retries;
730
731 for (retries = 0; retries <= REP_OP_RETRIES; retries++) {
732 if (make_handle_bound(rep_handle) == -1)
733 goto gen_fail;
734
735 switch (read_enable_prop(fmri, enabled, SCF_PG_GENERAL_OVR)) {
736 case 0:
737 debug_msg("read %d from override", *enabled);
738 return (0);
739 case SCF_ERROR_CONNECTION_BROKEN:
740 break;
741 case SCF_ERROR_NOT_FOUND:
742 case SCF_ERROR_NONE:
743 case SCF_ERROR_INVALID_ARGUMENT:
744 switch (read_enable_prop(fmri, enabled,
745 SCF_PG_GENERAL)) {
746 case 0:
747 debug_msg("read %d from non_override",
748 *enabled);
749 return (0);
750 case SCF_ERROR_CONNECTION_BROKEN:
751 break;
752 case SCF_ERROR_NOT_FOUND:
753 case SCF_ERROR_NONE:
754 case SCF_ERROR_INVALID_ARGUMENT:
755 error_msg(gettext("Missing %s property/value "
756 "for instance %s"), SCF_PROPERTY_ENABLED,
757 fmri);
758 return (-1);
759 default:
760 goto gen_fail;
761 }
762 break;
763 default:
764 goto gen_fail;
765 }
766
767 (void) scf_handle_unbind(rep_handle);
768 continue;
769 }
770
771 gen_fail:
772 error_msg(gettext("Failed to read the %s property of instance %s: %s"),
773 SCF_PROPERTY_ENABLED, fmri, scf_strerror(scf_error()));
774 return (-1);
775 }
776
777 /*
778 * Refresh the value of debug property under the property group "config"
779 * for network/inetd service.
780 */
781 void
refresh_debug_flag(void)782 refresh_debug_flag(void)
783 {
784 scf_simple_prop_t *sprop;
785 uint8_t *tmp_bool;
786
787 if ((sprop = scf_simple_prop_get(rep_handle, INETD_INSTANCE_FMRI,
788 PG_NAME_APPLICATION_CONFIG, PR_NAME_DEBUG_FLAG)) == NULL) {
789 error_msg(gettext("Unable to read %s property from %s property "
790 "group. scf_simple_prop_get() failed: %s"),
791 PR_NAME_DEBUG_FLAG, PG_NAME_APPLICATION_CONFIG,
792 scf_strerror(scf_error()));
793 return;
794 } else if ((tmp_bool = scf_simple_prop_next_boolean(sprop)) == NULL) {
795 error_msg(gettext("Unable to read %s property for %s service. "
796 "scf_simple_prop_next_boolean() failed: %s"),
797 PR_NAME_DEBUG_FLAG, INETD_INSTANCE_FMRI,
798 scf_strerror(scf_error()));
799 } else {
800 debug_enabled = ((*tmp_bool == 0) ? B_FALSE : B_TRUE);
801 }
802
803 scf_simple_prop_free(sprop);
804 }
805