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