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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <sys/acctctl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <limits.h>
33 #include <libdllink.h>
34 #include <libscf.h>
35 #include <pwd.h>
36 #include <auth_attr.h>
37 #include <nss_dbdefs.h>
38 #include <secdb.h>
39 #include <priv.h>
40 #include <zone.h>
41
42 #include "aconf.h"
43 #include "utils.h"
44 #include "res.h"
45
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"
50
51 #define NELEM(x) (sizeof (x)) / (sizeof (x[0]))
52
53 typedef struct props {
54 char *propname;
55 int proptype;
56 scf_transaction_entry_t *entry;
57 scf_value_t *value;
58 struct props *next;
59 } props_t;
60
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 *);
66
67 static scf_handle_t *handle = NULL;
68 static scf_instance_t *inst = NULL;
69 static props_t *props = NULL;
70
71 void
aconf_init(acctconf_t * acp,int type)72 aconf_init(acctconf_t *acp, int type)
73 {
74 void *buf;
75 char *tracked;
76 char *untracked;
77
78 if ((buf = malloc(AC_BUFSIZE)) == NULL)
79 die(gettext("not enough memory\n"));
80
81 if (acctctl(type | AC_STATE_GET, &acp->state,
82 sizeof (acp->state)) == -1)
83 die(gettext("cannot get %s accounting state\n"),
84 ac_type_name(type));
85
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,
90 sizeof (acp->file));
91 else
92 die(gettext("cannot get %s accounting file name"),
93 ac_type_name(type));
94 }
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"));
98
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));
103 free(tracked);
104 free(untracked);
105 free(buf);
106 }
107
108 /*
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.
118 */
119 int
aconf_setup(const char * fmri)120 aconf_setup(const char *fmri)
121 {
122 char file[MAXPATHLEN];
123 char tracked[MAXRESLEN];
124 char untracked[MAXRESLEN];
125 void *buf;
126 int type;
127 int state;
128 uint8_t b;
129 int ret = SMF_EXIT_OK;
130
131 if ((type = aconf_fmri2type(fmri)) == -1) {
132 warn(gettext("no accounting type for %s\n"), fmri);
133 return (SMF_EXIT_ERR_FATAL);
134 }
135
136 /*
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(8), but there is
140 * nothing that prevents someone from calling svcadm enable directly,
141 * so we handle that case here by disabling the instance.
142 */
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);
149 }
150
151 if (aconf_scf_init(fmri) == -1) {
152 warn(gettext("cannot connect to repository\n"));
153 return (SMF_EXIT_ERR_FATAL);
154 }
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;
159 goto out;
160 }
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;
165 goto out;
166 }
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;
171 goto out;
172 }
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;
176 goto out;
177 }
178 state = (b ? AC_ON : AC_OFF);
179
180 if ((buf = malloc(AC_BUFSIZE)) == NULL) {
181 warn(gettext("not enough memory\n"));
182 ret = SMF_EXIT_ERR_FATAL;
183 goto out;
184 }
185 (void) memset(buf, 0, AC_BUFSIZE);
186 str2buf(buf, untracked, AC_OFF, type);
187 str2buf(buf, tracked, AC_ON, type);
188
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"),
192 ac_type_name(type));
193 ret = SMF_EXIT_ERR_FATAL;
194 }
195 free(buf);
196
197 if (strcmp(file, AC_STR_NONE) != 0) {
198 if (open_exacct_file(file, type) == -1)
199 ret = SMF_EXIT_ERR_FATAL;
200 } else {
201 if (acctctl(type | AC_FILE_SET, NULL, 0) == -1) {
202 warn(gettext("cannot close %s accounting file"),
203 ac_type_name(type));
204 ret = SMF_EXIT_ERR_FATAL;
205 }
206 }
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"),
210 ac_type_name(type));
211 ret = SMF_EXIT_ERR_FATAL;
212 }
213 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
214
215 if (state == AC_ON && type == AC_NET) {
216 /*
217 * Start logging.
218 */
219 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_DL_CONFIG,
220 NULL);
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,
225 NULL);
226 }
227 out:
228 aconf_scf_fini();
229 return (ret);
230 }
231
232 void
aconf_print(FILE * fp,int types)233 aconf_print(FILE *fp, int types)
234 {
235 acctconf_t ac;
236 int print_order[] = { AC_TASK, AC_PROC, AC_FLOW, AC_NET };
237 int i;
238
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]);
243 }
244 }
245 }
246
247 static void
aconf_print_type(acctconf_t * acp,FILE * fp,int type)248 aconf_print_type(acctconf_t *acp, FILE *fp, int type)
249 {
250 switch (type) {
251 case AC_TASK:
252 (void) fprintf(fp,
253 gettext(" Task accounting: %s\n"),
254 acp->state == AC_ON ?
255 gettext("active") : gettext("inactive"));
256 (void) fprintf(fp,
257 gettext(" Task accounting file: %s\n"),
258 acp->file);
259 (void) fprintf(fp,
260 gettext(" Tracked task resources: %s\n"),
261 acp->tracked);
262 (void) fprintf(fp,
263 gettext(" Untracked task resources: %s\n"),
264 acp->untracked);
265 break;
266 case AC_PROC:
267 (void) fprintf(fp,
268 gettext(" Process accounting: %s\n"),
269 acp->state == AC_ON ?
270 gettext("active") : gettext("inactive"));
271 (void) fprintf(fp,
272 gettext(" Process accounting file: %s\n"),
273 acp->file);
274 (void) fprintf(fp,
275 gettext(" Tracked process resources: %s\n"),
276 acp->tracked);
277 (void) fprintf(fp,
278 gettext("Untracked process resources: %s\n"),
279 acp->untracked);
280 break;
281 case AC_FLOW:
282 (void) fprintf(fp,
283 gettext(" Flow accounting: %s\n"),
284 acp->state == AC_ON ?
285 gettext("active") : gettext("inactive"));
286 (void) fprintf(fp,
287 gettext(" Flow accounting file: %s\n"),
288 acp->file);
289 (void) fprintf(fp,
290 gettext(" Tracked flow resources: %s\n"),
291 acp->tracked);
292 (void) fprintf(fp,
293 gettext(" Untracked flow resources: %s\n"),
294 acp->untracked);
295 break;
296 case AC_NET:
297 (void) fprintf(fp,
298 gettext(" Net accounting: %s\n"),
299 acp->state == AC_ON ?
300 gettext("active") : gettext("inactive"));
301 (void) fprintf(fp,
302 gettext(" Net accounting file: %s\n"),
303 acp->file);
304 (void) fprintf(fp,
305 gettext(" Tracked net resources: %s\n"),
306 acp->tracked);
307 (void) fprintf(fp,
308 gettext(" Untracked net resources: %s\n"),
309 acp->untracked);
310 break;
311 }
312 }
313
314 /*
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.
318 */
319 int
aconf_save(void)320 aconf_save(void)
321 {
322 scf_propertygroup_t *pg;
323 scf_transaction_t *tx;
324 props_t *p;
325 props_t *q;
326 int tx_result;
327
328 if (props == NULL)
329 return (0);
330
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)
334 goto out;
335
336 do {
337 if (scf_pg_update(pg) == -1 ||
338 scf_transaction_start(tx, pg) == -1)
339 goto out;
340
341 for (p = props; p != NULL; p = p->next) {
342 if (scf_transaction_property_change(tx, p->entry,
343 p->propname, p->proptype) == -1)
344 goto out;
345 (void) scf_entry_add_value(p->entry, p->value);
346 }
347 tx_result = scf_transaction_commit(tx);
348 scf_transaction_reset(tx);
349 } while (tx_result == 0);
350
351 out:
352 p = props;
353 while (p != NULL) {
354 scf_value_destroy(p->value);
355 scf_entry_destroy(p->entry);
356 free(p->propname);
357 q = p->next;
358 free(p);
359 p = q;
360 }
361 props = NULL;
362 scf_transaction_destroy(tx);
363 scf_pg_destroy(pg);
364 return ((tx_result == 1) ? 0 : -1);
365 }
366
367 boolean_t
aconf_have_smf_auths(void)368 aconf_have_smf_auths(void)
369 {
370 char auth[NSS_BUFLEN_AUTHATTR];
371 struct passwd *pw;
372
373 if ((pw = getpwuid(getuid())) == NULL)
374 return (B_FALSE);
375
376 if (aconf_get_string("general", "action_authorization", auth,
377 sizeof (auth)) == -1 || chkauthattr(auth, pw->pw_name) == 0)
378 return (B_FALSE);
379
380 if (aconf_get_string("general", "value_authorization", auth,
381 sizeof (auth)) == -1 || chkauthattr(auth, pw->pw_name) == 0)
382 return (B_FALSE);
383
384 if (aconf_get_string("config", "value_authorization", auth,
385 sizeof (auth)) == -1 || chkauthattr(auth, pw->pw_name) == 0)
386 return (B_FALSE);
387
388 return (B_TRUE);
389 }
390
391 const char *
aconf_type2fmri(int type)392 aconf_type2fmri(int type)
393 {
394 switch (type) {
395 case AC_PROC:
396 return (FMRI_PROC_ACCT);
397 case AC_TASK:
398 return (FMRI_TASK_ACCT);
399 case AC_FLOW:
400 return (FMRI_FLOW_ACCT);
401 case AC_NET:
402 return (FMRI_NET_ACCT);
403 default:
404 die(gettext("invalid type %d\n"), type);
405 }
406 /* NOTREACHED */
407 return (NULL);
408 }
409
410 static int
aconf_fmri2type(const char * fmri)411 aconf_fmri2type(const char *fmri)
412 {
413 if (strcmp(fmri, FMRI_PROC_ACCT) == 0)
414 return (AC_PROC);
415 else if (strcmp(fmri, FMRI_TASK_ACCT) == 0)
416 return (AC_TASK);
417 else if (strcmp(fmri, FMRI_FLOW_ACCT) == 0)
418 return (AC_FLOW);
419 else if (strcmp(fmri, FMRI_NET_ACCT) == 0)
420 return (AC_NET);
421 else
422 return (-1);
423 }
424
425 int
aconf_scf_init(const char * fmri)426 aconf_scf_init(const char *fmri)
427 {
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) {
433 aconf_scf_fini();
434 return (-1);
435 }
436 return (0);
437 }
438
439 void
aconf_scf_fini(void)440 aconf_scf_fini(void)
441 {
442 scf_instance_destroy(inst);
443 (void) scf_handle_unbind(handle);
444 scf_handle_destroy(handle);
445 }
446
447 static int
aconf_get_string(const char * pgname,const char * propname,char * buf,size_t len)448 aconf_get_string(const char *pgname, const char *propname, char *buf,
449 size_t len)
450 {
451 scf_propertygroup_t *pg;
452 scf_property_t *prop;
453 scf_value_t *value;
454 int ret = 0;
455
456 if ((pg = scf_pg_create(handle)) == NULL)
457 return (-1);
458
459 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) == -1) {
460 scf_pg_destroy(pg);
461 return (-1);
462 }
463
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)
469 ret = -1;
470
471 scf_value_destroy(value);
472 scf_property_destroy(prop);
473 scf_pg_destroy(pg);
474 return (ret);
475 }
476
477 static int
aconf_get_bool(const char * pgname,const char * propname,uint8_t * rval)478 aconf_get_bool(const char *pgname, const char *propname, uint8_t *rval)
479 {
480 scf_propertygroup_t *pg;
481 scf_property_t *prop;
482 scf_value_t *value;
483 int ret = 0;
484
485 if ((pg = scf_pg_create(handle)) == NULL)
486 return (-1);
487
488 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) == -1) {
489 scf_pg_destroy(pg);
490 return (-1);
491 }
492
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)
498 ret = -1;
499
500 scf_value_destroy(value);
501 scf_property_destroy(prop);
502 scf_pg_destroy(pg);
503 return (ret);
504 }
505
506 int
aconf_set_string(const char * propname,const char * value)507 aconf_set_string(const char *propname, const char *value)
508 {
509 props_t *p;
510
511 if ((p = aconf_prop(propname, SCF_TYPE_ASTRING)) == NULL)
512 return (-1);
513
514 if (scf_value_set_astring(p->value, value) == -1)
515 return (-1);
516 return (0);
517 }
518
519 int
aconf_set_bool(const char * propname,boolean_t value)520 aconf_set_bool(const char *propname, boolean_t value)
521 {
522 props_t *p;
523
524 if ((p = aconf_prop(propname, SCF_TYPE_BOOLEAN)) == NULL)
525 return (-1);
526
527 scf_value_set_boolean(p->value, value);
528 return (0);
529 }
530
531 static props_t *
aconf_prop(const char * propname,int proptype)532 aconf_prop(const char *propname, int proptype)
533 {
534 props_t *p;
535
536 if ((p = malloc(sizeof (props_t))) != NULL) {
537 if ((p->propname = strdup(propname)) == NULL) {
538 free(p);
539 return (NULL);
540 }
541 if ((p->entry = scf_entry_create(handle)) == NULL) {
542 free(p->propname);
543 free(p);
544 return (NULL);
545 }
546 if ((p->value = scf_value_create(handle)) == NULL) {
547 scf_entry_destroy(p->entry);
548 free(p->propname);
549 free(p);
550 return (NULL);
551 }
552 p->proptype = proptype;
553 p->next = props;
554 props = p;
555 }
556 return (p);
557 }
558