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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/acctctl.h>
33 #include <libdllink.h>
36 #include <auth_attr.h>
37 #include <nss_dbdefs.h>
46 #define FMRI_FLOW_ACCT "svc:/system/extended-accounting:flow"
47 #define FMRI_PROC_ACCT "svc:/system/extended-accounting:process"
48 #define FMRI_TASK_ACCT "svc:/system/extended-accounting:task"
49 #define FMRI_NET_ACCT "svc:/system/extended-accounting:net"
51 #define NELEM(x) (sizeof (x)) / (sizeof (x[0]))
53 typedef struct props
{
56 scf_transaction_entry_t
*entry
;
61 static void aconf_print_type(acctconf_t
*, FILE *, int);
62 static int aconf_get_bool(const char *, const char *, uint8_t *);
63 static int aconf_get_string(const char *, const char *, char *, size_t);
64 static props_t
*aconf_prop(const char *, int);
65 static int aconf_fmri2type(const char *);
67 static scf_handle_t
*handle
= NULL
;
68 static scf_instance_t
*inst
= NULL
;
69 static props_t
*props
= NULL
;
72 aconf_init(acctconf_t
*acp
, int type
)
78 if ((buf
= malloc(AC_BUFSIZE
)) == NULL
)
79 die(gettext("not enough memory\n"));
81 if (acctctl(type
| AC_STATE_GET
, &acp
->state
,
82 sizeof (acp
->state
)) == -1)
83 die(gettext("cannot get %s accounting state\n"),
86 (void) memset(acp
->file
, 0, sizeof (acp
->file
));
87 if (acctctl(type
| AC_FILE_GET
, acp
->file
, sizeof (acp
->file
)) == -1) {
88 if (errno
== ENOTACTIVE
)
89 (void) strlcpy(acp
->file
, AC_STR_NONE
,
92 die(gettext("cannot get %s accounting file name"),
95 (void) memset(buf
, 0, AC_BUFSIZE
);
96 if (acctctl(type
| AC_RES_GET
, buf
, AC_BUFSIZE
) == -1)
97 die(gettext("cannot obtain the list of enabled resources\n"));
99 tracked
= buf2str(buf
, AC_BUFSIZE
, AC_ON
, type
);
100 untracked
= buf2str(buf
, AC_BUFSIZE
, AC_OFF
, type
);
101 (void) strlcpy(acp
->tracked
, tracked
, sizeof (acp
->tracked
));
102 (void) strlcpy(acp
->untracked
, untracked
, sizeof (acp
->untracked
));
109 * SMF start method: configure extended accounting from properties stored in
110 * the repository. Any errors encountered while retrieving properties from
111 * the repository, such as missing properties or properties of the wrong type,
112 * are fatal as they indicate severe damage to the service (all required
113 * properties are delivered in the service manifest and should thus always be
114 * present). No attempts will be made to repair such damage; the service will
115 * be forced into maintenance state by returning SMF_EXIT_ERR_CONFIG. For all
116 * other errors we we try to configure as much as possible and return
117 * SMF_EXIT_ERR_FATAL.
120 aconf_setup(const char *fmri
)
122 char file
[MAXPATHLEN
];
123 char tracked
[MAXRESLEN
];
124 char untracked
[MAXRESLEN
];
129 int ret
= SMF_EXIT_OK
;
131 if ((type
= aconf_fmri2type(fmri
)) == -1) {
132 warn(gettext("no accounting type for %s\n"), fmri
);
133 return (SMF_EXIT_ERR_FATAL
);
137 * Net/Flow accounting is not available in non-global zones and
138 * the service instance should therefore never be 'enabled' in
139 * non-global zones. This is enforced by acctadm(1M), but there is
140 * nothing that prevents someone from calling svcadm enable directly,
141 * so we handle that case here by disabling the instance.
143 if ((type
== AC_FLOW
|| type
== AC_NET
) &&
144 getzoneid() != GLOBAL_ZONEID
) {
145 (void) smf_disable_instance(fmri
, 0);
146 warn(gettext("%s accounting cannot be configured in "
147 "non-global zones\n"), ac_type_name(type
));
148 return (SMF_EXIT_OK
);
151 if (aconf_scf_init(fmri
) == -1) {
152 warn(gettext("cannot connect to repository\n"));
153 return (SMF_EXIT_ERR_FATAL
);
155 if (aconf_get_string(AC_PGNAME
, AC_PROP_TRACKED
, tracked
,
156 sizeof (tracked
)) == -1) {
157 warn(gettext("cannot get %s property\n"), AC_PROP_TRACKED
);
158 ret
= SMF_EXIT_ERR_CONFIG
;
161 if (aconf_get_string(AC_PGNAME
, AC_PROP_UNTRACKED
, untracked
,
162 sizeof (untracked
)) == -1) {
163 warn(gettext("cannot get %s property\n"), AC_PROP_UNTRACKED
);
164 ret
= SMF_EXIT_ERR_CONFIG
;
167 if (aconf_get_string(AC_PGNAME
, AC_PROP_FILE
, file
,
168 sizeof (file
)) == -1) {
169 warn(gettext("cannot get %s property\n"), AC_PROP_FILE
);
170 ret
= SMF_EXIT_ERR_CONFIG
;
173 if (aconf_get_bool(AC_PGNAME
, AC_PROP_STATE
, &b
) == -1) {
174 warn(gettext("cannot get %s property\n"), AC_PROP_STATE
);
175 ret
= SMF_EXIT_ERR_CONFIG
;
178 state
= (b
? AC_ON
: AC_OFF
);
180 if ((buf
= malloc(AC_BUFSIZE
)) == NULL
) {
181 warn(gettext("not enough memory\n"));
182 ret
= SMF_EXIT_ERR_FATAL
;
185 (void) memset(buf
, 0, AC_BUFSIZE
);
186 str2buf(buf
, untracked
, AC_OFF
, type
);
187 str2buf(buf
, tracked
, AC_ON
, type
);
189 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
190 if (acctctl(type
| AC_RES_SET
, buf
, AC_BUFSIZE
) == -1) {
191 warn(gettext("cannot enable/disable %s accounting resources"),
193 ret
= SMF_EXIT_ERR_FATAL
;
197 if (strcmp(file
, AC_STR_NONE
) != 0) {
198 if (open_exacct_file(file
, type
) == -1)
199 ret
= SMF_EXIT_ERR_FATAL
;
201 if (acctctl(type
| AC_FILE_SET
, NULL
, 0) == -1) {
202 warn(gettext("cannot close %s accounting file"),
204 ret
= SMF_EXIT_ERR_FATAL
;
207 if (acctctl(type
| AC_STATE_SET
, &state
, sizeof (state
)) == -1) {
208 warn(gettext("cannot %s %s accounting"),
209 state
== AC_ON
? gettext("enable") : gettext("disable"),
211 ret
= SMF_EXIT_ERR_FATAL
;
213 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
, PRIV_SYS_ACCT
, NULL
);
215 if (state
== AC_ON
&& type
== AC_NET
) {
219 (void) priv_set(PRIV_ON
, PRIV_EFFECTIVE
, PRIV_SYS_DL_CONFIG
,
221 (void) dladm_start_usagelog(dld_handle
,
222 strncmp(tracked
, "basic", strlen("basic")) == 0 ?
223 DLADM_LOGTYPE_LINK
: DLADM_LOGTYPE_FLOW
, 20);
224 (void) priv_set(PRIV_OFF
, PRIV_EFFECTIVE
, PRIV_SYS_DL_CONFIG
,
233 aconf_print(FILE *fp
, int types
)
236 int print_order
[] = { AC_TASK
, AC_PROC
, AC_FLOW
, AC_NET
};
239 for (i
= 0; i
< NELEM(print_order
); i
++) {
240 if (types
& print_order
[i
]) {
241 aconf_init(&ac
, print_order
[i
]);
242 aconf_print_type(&ac
, fp
, print_order
[i
]);
248 aconf_print_type(acctconf_t
*acp
, FILE *fp
, int type
)
253 gettext(" Task accounting: %s\n"),
254 acp
->state
== AC_ON
?
255 gettext("active") : gettext("inactive"));
257 gettext(" Task accounting file: %s\n"),
260 gettext(" Tracked task resources: %s\n"),
263 gettext(" Untracked task resources: %s\n"),
268 gettext(" Process accounting: %s\n"),
269 acp
->state
== AC_ON
?
270 gettext("active") : gettext("inactive"));
272 gettext(" Process accounting file: %s\n"),
275 gettext(" Tracked process resources: %s\n"),
278 gettext("Untracked process resources: %s\n"),
283 gettext(" Flow accounting: %s\n"),
284 acp
->state
== AC_ON
?
285 gettext("active") : gettext("inactive"));
287 gettext(" Flow accounting file: %s\n"),
290 gettext(" Tracked flow resources: %s\n"),
293 gettext(" Untracked flow resources: %s\n"),
298 gettext(" Net accounting: %s\n"),
299 acp
->state
== AC_ON
?
300 gettext("active") : gettext("inactive"));
302 gettext(" Net accounting file: %s\n"),
305 gettext(" Tracked net resources: %s\n"),
308 gettext(" Untracked net resources: %s\n"),
315 * Modified properties are put on the 'props' linked list by aconf_set_string()
316 * and aconf_set_bool(). Walk the list of modified properties and write them
317 * to the repository. The list is deleted on exit.
322 scf_propertygroup_t
*pg
;
323 scf_transaction_t
*tx
;
331 if ((pg
= scf_pg_create(handle
)) == NULL
||
332 scf_instance_get_pg(inst
, AC_PGNAME
, pg
) == -1 ||
333 (tx
= scf_transaction_create(handle
)) == NULL
)
337 if (scf_pg_update(pg
) == -1 ||
338 scf_transaction_start(tx
, pg
) == -1)
341 for (p
= props
; p
!= NULL
; p
= p
->next
) {
342 if (scf_transaction_property_change(tx
, p
->entry
,
343 p
->propname
, p
->proptype
) == -1)
345 (void) scf_entry_add_value(p
->entry
, p
->value
);
347 tx_result
= scf_transaction_commit(tx
);
348 scf_transaction_reset(tx
);
349 } while (tx_result
== 0);
354 scf_value_destroy(p
->value
);
355 scf_entry_destroy(p
->entry
);
362 scf_transaction_destroy(tx
);
364 return ((tx_result
== 1) ? 0 : -1);
368 aconf_have_smf_auths(void)
370 char auth
[NSS_BUFLEN_AUTHATTR
];
373 if ((pw
= getpwuid(getuid())) == NULL
)
376 if (aconf_get_string("general", "action_authorization", auth
,
377 sizeof (auth
)) == -1 || chkauthattr(auth
, pw
->pw_name
) == 0)
380 if (aconf_get_string("general", "value_authorization", auth
,
381 sizeof (auth
)) == -1 || chkauthattr(auth
, pw
->pw_name
) == 0)
384 if (aconf_get_string("config", "value_authorization", auth
,
385 sizeof (auth
)) == -1 || chkauthattr(auth
, pw
->pw_name
) == 0)
392 aconf_type2fmri(int type
)
396 return (FMRI_PROC_ACCT
);
398 return (FMRI_TASK_ACCT
);
400 return (FMRI_FLOW_ACCT
);
402 return (FMRI_NET_ACCT
);
404 die(gettext("invalid type %d\n"), type
);
411 aconf_fmri2type(const char *fmri
)
413 if (strcmp(fmri
, FMRI_PROC_ACCT
) == 0)
415 else if (strcmp(fmri
, FMRI_TASK_ACCT
) == 0)
417 else if (strcmp(fmri
, FMRI_FLOW_ACCT
) == 0)
419 else if (strcmp(fmri
, FMRI_NET_ACCT
) == 0)
426 aconf_scf_init(const char *fmri
)
428 if ((handle
= scf_handle_create(SCF_VERSION
)) == NULL
||
429 scf_handle_bind(handle
) == -1 ||
430 (inst
= scf_instance_create(handle
)) == NULL
||
431 scf_handle_decode_fmri(handle
, fmri
, NULL
, NULL
, inst
, NULL
, NULL
,
432 SCF_DECODE_FMRI_EXACT
) == -1) {
442 scf_instance_destroy(inst
);
443 (void) scf_handle_unbind(handle
);
444 scf_handle_destroy(handle
);
448 aconf_get_string(const char *pgname
, const char *propname
, char *buf
,
451 scf_propertygroup_t
*pg
;
452 scf_property_t
*prop
;
456 if ((pg
= scf_pg_create(handle
)) == NULL
)
459 if (scf_instance_get_pg_composed(inst
, NULL
, pgname
, pg
) == -1) {
464 if ((prop
= scf_property_create(handle
)) == NULL
||
465 (value
= scf_value_create(handle
)) == NULL
||
466 scf_pg_get_property(pg
, propname
, prop
) == -1 ||
467 scf_property_get_value(prop
, value
) == -1 ||
468 scf_value_get_astring(value
, buf
, len
) == -1)
471 scf_value_destroy(value
);
472 scf_property_destroy(prop
);
478 aconf_get_bool(const char *pgname
, const char *propname
, uint8_t *rval
)
480 scf_propertygroup_t
*pg
;
481 scf_property_t
*prop
;
485 if ((pg
= scf_pg_create(handle
)) == NULL
)
488 if (scf_instance_get_pg_composed(inst
, NULL
, pgname
, pg
) == -1) {
493 if ((prop
= scf_property_create(handle
)) == NULL
||
494 (value
= scf_value_create(handle
)) == NULL
||
495 scf_pg_get_property(pg
, propname
, prop
) == -1 ||
496 scf_property_get_value(prop
, value
) == -1 ||
497 scf_value_get_boolean(value
, rval
) == -1)
500 scf_value_destroy(value
);
501 scf_property_destroy(prop
);
507 aconf_set_string(const char *propname
, const char *value
)
511 if ((p
= aconf_prop(propname
, SCF_TYPE_ASTRING
)) == NULL
)
514 if (scf_value_set_astring(p
->value
, value
) == -1)
520 aconf_set_bool(const char *propname
, boolean_t value
)
524 if ((p
= aconf_prop(propname
, SCF_TYPE_BOOLEAN
)) == NULL
)
527 scf_value_set_boolean(p
->value
, value
);
532 aconf_prop(const char *propname
, int proptype
)
536 if ((p
= malloc(sizeof (props_t
))) != NULL
) {
537 if ((p
->propname
= strdup(propname
)) == NULL
) {
541 if ((p
->entry
= scf_entry_create(handle
)) == NULL
) {
546 if ((p
->value
= scf_value_create(handle
)) == NULL
) {
547 scf_entry_destroy(p
->entry
);
552 p
->proptype
= proptype
;