Home | History | Annotate | Download | only in acctadm
      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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <sys/acctctl.h>
     29 #include <assert.h>
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <unistd.h>
     33 #include <string.h>
     34 #include <errno.h>
     35 #include <libintl.h>
     36 #include <locale.h>
     37 #include <priv.h>
     38 #include <libscf.h>
     39 #include <zone.h>
     40 
     41 #include "utils.h"
     42 #include "aconf.h"
     43 #include "res.h"
     44 
     45 static const char USAGE[] = "\
     46 Usage:\n\
     47     acctadm [ {process | task | flow} ]\n\
     48     acctadm -s\n\
     49     acctadm -r [ {process | task | flow} ]\n\
     50     acctadm -x|-E|-D {process | task | flow}\n\
     51     acctadm -f filename {process | task | flow}\n\
     52     acctadm -e resources -d resources {process | task | flow}\n";
     53 
     54 static const char OPTS[] = "rsxf:e:d:ED";
     55 
     56 static void
     57 usage()
     58 {
     59 	(void) fprintf(stderr, gettext(USAGE));
     60 	exit(E_USAGE);
     61 }
     62 
     63 static void
     64 setup_privs()
     65 {
     66 	priv_set_t *privset;
     67 
     68 	if (seteuid(getuid()) == -1 || setegid(getgid()) == -1)
     69 		die(gettext("seteuid()/setegid() failed"));
     70 
     71 	/*
     72 	 * Add our privileges and remove unneeded 'basic' privileges from the
     73 	 * permitted set.
     74 	 */
     75 	if ((privset = priv_str_to_set("basic", ",", NULL)) == NULL)
     76 		die(gettext("cannot setup privileges"));
     77 
     78 	(void) priv_addset(privset, PRIV_SYS_ACCT);
     79 	(void) priv_addset(privset, PRIV_FILE_DAC_WRITE);
     80 	(void) priv_delset(privset, PRIV_FILE_LINK_ANY);
     81 	(void) priv_delset(privset, PRIV_PROC_EXEC);
     82 	(void) priv_delset(privset, PRIV_PROC_FORK);
     83 	(void) priv_delset(privset, PRIV_PROC_INFO);
     84 	(void) priv_delset(privset, PRIV_PROC_SESSION);
     85 	priv_inverse(privset);
     86 	if (setppriv(PRIV_OFF, PRIV_PERMITTED, privset) == -1)
     87 		die(gettext("cannot setup privileges"));
     88 	priv_freeset(privset);
     89 
     90 	/*
     91 	 * Clear the Inheritable and Limit sets.
     92 	 */
     93 	if ((privset = priv_allocset()) == NULL)
     94 		die(gettext("cannot setup privileges"));
     95 	priv_emptyset(privset);
     96 	if (setppriv(PRIV_SET, PRIV_INHERITABLE, privset) == -1 ||
     97 	    setppriv(PRIV_SET, PRIV_LIMIT, privset) == -1)
     98 		die(gettext("cannot setup privileges"));
     99 
    100 	/*
    101 	 * Turn off the sys_acct and file_dac_write privileges until needed.
    102 	 */
    103 	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE,
    104 	    PRIV_SYS_ACCT, NULL);
    105 }
    106 
    107 int
    108 main(int argc, char *argv[])
    109 {
    110 	int c;			/* options character */
    111 	int type = 0;		/* type of accounting */
    112 	int modified = 0;	/* have we modified any properties? */
    113 	acctconf_t ac;		/* current configuration */
    114 	char *typestr = NULL;	/* type of accounting argument string */
    115 	char *enabled = NULL;	/* enabled resources string */
    116 	char *disabled = NULL;	/* disabled resources string */
    117 	char *file = NULL;
    118 	int Eflg = 0;
    119 	int Dflg = 0;
    120 	int rflg = 0;
    121 	int sflg = 0;
    122 	int xflg = 0;
    123 	int optcnt = 0;
    124 	int state;
    125 	const char *fmri;	/* FMRI for this instance */
    126 
    127 	setup_privs();
    128 
    129 	(void) setlocale(LC_ALL, "");
    130 	(void) textdomain(TEXT_DOMAIN);
    131 	(void) setprogname(argv[0]);
    132 
    133 	for (; optind < argc; optind++) {
    134 		while ((c = getopt(argc, argv, OPTS)) != (int)EOF) {
    135 			switch (c) {
    136 			case 'd':
    137 				disabled = optarg;
    138 				break;
    139 			case 'e':
    140 				enabled = optarg;
    141 				break;
    142 			case 'D':
    143 				Dflg = 1;
    144 				optcnt++;
    145 				break;
    146 			case 'E':
    147 				Eflg = 1;
    148 				optcnt++;
    149 				break;
    150 			case 'f':
    151 				file = optarg;
    152 				optcnt++;
    153 				break;
    154 			case 'r':
    155 				rflg = 1;
    156 				optcnt++;
    157 				break;
    158 			case 's':
    159 				sflg = 1;
    160 				optcnt++;
    161 				break;
    162 			case 'x':
    163 				xflg = 1;
    164 				optcnt++;
    165 				break;
    166 			case '?':
    167 			default:
    168 				usage();
    169 			}
    170 		}
    171 
    172 		/*
    173 		 * Permanently give up euid 0, egid 0 and privileges we
    174 		 * don't need for the specified options.
    175 		 */
    176 		if (!(file || sflg)) {
    177 			if (setreuid(getuid(), getuid()) == -1 ||
    178 			    setregid(getgid(), getgid()) == -1)
    179 				die(gettext("setreuid()/setregid() failed"));
    180 			(void) priv_set(PRIV_OFF, PRIV_PERMITTED,
    181 			    PRIV_FILE_DAC_WRITE, NULL);
    182 		}
    183 		if (!(disabled || enabled || Dflg || Eflg || file || sflg ||
    184 		    xflg))
    185 			(void) priv_set(PRIV_OFF, PRIV_PERMITTED,
    186 			    PRIV_SYS_ACCT, NULL);
    187 
    188 		if (optind < argc) {
    189 			if (typestr != NULL) {
    190 				warn(gettext("illegal argument -- %s\n"),
    191 				    argv[optind]);
    192 				usage();
    193 			} else {
    194 				typestr = argv[optind];
    195 			}
    196 		}
    197 	}
    198 	if (typestr != NULL) {
    199 		if (strcmp(typestr, "process") == 0 ||
    200 		    strcmp(typestr, "proc") == 0)
    201 			type |= AC_PROC;
    202 		else if (strcmp(typestr, "task") == 0)
    203 			type |= AC_TASK;
    204 		else if (strcmp(typestr, "flow") == 0)
    205 			type |= AC_FLOW;
    206 		else {
    207 			warn(gettext("unknown accounting type -- %s\n"),
    208 			    typestr);
    209 			usage();
    210 		}
    211 	} else
    212 		type = AC_PROC | AC_TASK | AC_FLOW;
    213 
    214 	/*
    215 	 * check for invalid options
    216 	 */
    217 	if (optcnt > 1)
    218 		usage();
    219 
    220 	if ((enabled || disabled) && (rflg || Dflg || sflg || xflg || Eflg))
    221 		usage();
    222 
    223 	if ((file || xflg || Dflg || Eflg || enabled || disabled) &&
    224 	    !typestr) {
    225 		warn(gettext("accounting type must be specified\n"));
    226 		usage();
    227 	}
    228 
    229 	if (rflg) {
    230 		printgroups(type);
    231 		return (E_SUCCESS);
    232 	}
    233 
    234 	/*
    235 	 * If no arguments have been passed then just print out the current
    236 	 * state and exit.
    237 	 */
    238 	if (!enabled && !disabled && !file &&
    239 	    !Eflg && !rflg && !Dflg && !sflg && !xflg) {
    240 		aconf_print(stdout, type);
    241 		return (E_SUCCESS);
    242 	}
    243 
    244 	/*
    245 	 * smf(5) start method.  The FMRI to operate on is retrieved from the
    246 	 * SMF_FMRI environment variable that the restarter provides.
    247 	 */
    248 	if (sflg) {
    249 		if ((fmri = getenv("SMF_FMRI")) != NULL)
    250 			return (aconf_setup(fmri));
    251 
    252 		warn(gettext("-s option should only be invoked by smf(5)\n"));
    253 		return (E_ERROR);
    254 	}
    255 
    256 	assert(type == AC_PROC || type == AC_TASK || type == AC_FLOW);
    257 
    258 	if (type == AC_FLOW && getzoneid() != GLOBAL_ZONEID)
    259 		die(gettext("%s accounting cannot be configured in "
    260 		    "non-global zones\n"), ac_type_name(type));
    261 
    262 	fmri = aconf_type2fmri(type);
    263 	if (aconf_scf_init(fmri) == -1)
    264 		die(gettext("cannot connect to repository for %s\n"), fmri);
    265 
    266 	/*
    267 	 * Since the sys_acct the privilege allows use of acctctl() regardless
    268 	 * of the accounting type, we check the smf(5) authorizations granted
    269 	 * to the user to determine whether the user is allowed to change the
    270 	 * configuration for this particular accounting type.
    271 	 */
    272 	if (!aconf_have_smf_auths())
    273 		die(gettext("insufficient authorization to change %s extended "
    274 		    "accounting configuration\n"), ac_type_name(type));
    275 
    276 	if (xflg) {
    277 		/*
    278 		 * Turn off the specified accounting and close its file
    279 		 */
    280 		state = AC_OFF;
    281 
    282 		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    283 		if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1)
    284 			die(gettext("cannot disable %s accounting"),
    285 			    ac_type_name(type));
    286 		if (acctctl(type | AC_FILE_SET, NULL, 0) == -1)
    287 			die(gettext("cannot close %s accounting file\n"),
    288 			    ac_type_name(type));
    289 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    290 
    291 		if (aconf_set_bool(AC_PROP_STATE, B_FALSE) == -1)
    292 			die(gettext("cannot update %s property\n"),
    293 			    AC_PROP_STATE);
    294 		if (aconf_set_string(AC_PROP_FILE, AC_STR_NONE) == -1)
    295 			die(gettext("cannot update %s property\n"),
    296 			    AC_PROP_FILE);
    297 		modified++;
    298 	}
    299 
    300 	if (enabled || disabled) {
    301 		char *tracked, *untracked;
    302 		ac_res_t *buf;
    303 
    304 		/*
    305 		 * Enable/disable resources
    306 		 */
    307 		if ((buf = malloc(AC_BUFSIZE)) == NULL)
    308 			die(gettext("not enough memory\n"));
    309 		(void) memset(buf, 0, AC_BUFSIZE);
    310 		if (acctctl(type | AC_RES_GET, buf, AC_BUFSIZE) == -1) {
    311 			free(buf);
    312 			die(gettext("cannot obtain list of resources\n"));
    313 		}
    314 		if (disabled)
    315 			str2buf(buf, disabled, AC_OFF, type);
    316 		if (enabled)
    317 			str2buf(buf, enabled, AC_ON, type);
    318 
    319 		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    320 		if (acctctl(type | AC_RES_SET, buf, AC_BUFSIZE) == -1) {
    321 			free(buf);
    322 			die(gettext("cannot enable/disable %s accounting "
    323 			    "resources\n"), ac_type_name(type));
    324 		}
    325 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    326 
    327 		tracked = buf2str(buf, AC_BUFSIZE, AC_ON, type);
    328 		untracked = buf2str(buf, AC_BUFSIZE, AC_OFF, type);
    329 		if (aconf_set_string(AC_PROP_TRACKED, tracked) == -1)
    330 			die(gettext("cannot update %s property\n"),
    331 			    AC_PROP_TRACKED);
    332 		if (aconf_set_string(AC_PROP_UNTRACKED, untracked) == -1)
    333 			die(gettext("cannot update %s property\n"),
    334 			    AC_PROP_UNTRACKED);
    335 		free(tracked);
    336 		free(untracked);
    337 		free(buf);
    338 		modified++;
    339 	}
    340 
    341 	if (file) {
    342 		/*
    343 		 * Open new accounting file
    344 		 */
    345 		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    346 		if (open_exacct_file(file, type) == -1)
    347 			exit(E_ERROR);
    348 		if (aconf_set_string(AC_PROP_FILE, file) == -1)
    349 			die(gettext("cannot update %s property\n"),
    350 			    AC_PROP_FILE);
    351 		state = AC_ON;
    352 
    353 		if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1)
    354 			die(gettext("cannot enable %s accounting"),
    355 			    ac_type_name(type));
    356 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    357 
    358 		if (aconf_set_bool(AC_PROP_STATE, B_TRUE) == -1)
    359 			die(gettext("cannot update %s property\n"),
    360 			    AC_PROP_STATE);
    361 		modified++;
    362 	}
    363 
    364 	if (Dflg) {
    365 		/*
    366 		 * Disable accounting
    367 		 */
    368 		state = AC_OFF;
    369 
    370 		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    371 		if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1)
    372 			die(gettext("cannot disable %s accounting"),
    373 			    ac_type_name(type));
    374 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    375 
    376 		if (aconf_set_bool(AC_PROP_STATE, B_FALSE) == -1)
    377 			die(gettext("cannot update %s property\n"),
    378 			    AC_PROP_STATE);
    379 		modified++;
    380 	}
    381 
    382 	if (Eflg) {
    383 		/*
    384 		 * Enable accounting
    385 		 */
    386 		state = AC_ON;
    387 
    388 		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    389 		if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1)
    390 			die(gettext("cannot enable %s accounting"),
    391 			    ac_type_name(type));
    392 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL);
    393 
    394 		if (aconf_set_bool(AC_PROP_STATE, B_TRUE) == -1)
    395 			die(gettext("cannot update %s property\n"),
    396 			    AC_PROP_STATE);
    397 		modified++;
    398 	}
    399 	(void) priv_set(PRIV_OFF, PRIV_PERMITTED, PRIV_SYS_ACCT, NULL);
    400 
    401 	if (modified) {
    402 		char *smf_state;
    403 
    404 		if (aconf_save() == -1)
    405 			die(gettext("cannot save %s accounting "
    406 			    "configuration\n"), ac_type_name(type));
    407 
    408 		/*
    409 		 * Enable or disable the instance depending on the effective
    410 		 * configuration.  If the effective configuration results in
    411 		 * extended accounting being 'on', the instance is enabled so
    412 		 * the configuration is applied at the next boot.
    413 		 */
    414 		smf_state = smf_get_state(fmri);
    415 		aconf_init(&ac, type);
    416 
    417 		if (ac.state == AC_ON ||
    418 		    strcmp(ac.file, AC_STR_NONE) != 0 ||
    419 		    strcmp(ac.tracked, AC_STR_NONE) != 0) {
    420 			if (strcmp(smf_state, SCF_STATE_STRING_ONLINE) != 0)
    421 				if (smf_enable_instance(fmri, 0) == -1)
    422 					die(gettext("cannot enable %s\n"),
    423 					    fmri);
    424 		} else {
    425 			if (strcmp(smf_state, SCF_STATE_STRING_ONLINE) == 0)
    426 				if (smf_disable_instance(fmri, 0) == -1)
    427 					die(gettext("cannot disable %s\n"),
    428 					    fmri);
    429 		}
    430 		free(smf_state);
    431 	}
    432 	aconf_scf_fini();
    433 	return (E_SUCCESS);
    434 }
    435