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 /* 23 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <sys/acctctl.h> 27 #include <assert.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <string.h> 32 #include <errno.h> 33 #include <libintl.h> 34 #include <libdllink.h> 35 #include <locale.h> 36 #include <priv.h> 37 #include <libscf.h> 38 #include <zone.h> 39 40 #include "utils.h" 41 #include "aconf.h" 42 #include "res.h" 43 44 #define ACCTADM_NET_LOG_INTERVAL 20 45 46 static const char USAGE[] = "\ 47 Usage:\n\ 48 acctadm [ {process | task | flow | net} ]\n\ 49 acctadm -s\n\ 50 acctadm -r [ {process | task | flow | net} ]\n\ 51 acctadm -x|-E|-D {process | task | flow | net}\n\ 52 acctadm -f filename {process | task | flow | net}\n\ 53 acctadm -e resources -d resources {process | task | flow | net}\n"; 54 55 static const char OPTS[] = "rsxf:e:d:ED"; 56 57 dladm_handle_t dld_handle = NULL; 58 59 static void 60 usage() 61 { 62 (void) fprintf(stderr, gettext(USAGE)); 63 exit(E_USAGE); 64 } 65 66 static void 67 setup_privs() 68 { 69 priv_set_t *privset; 70 71 if (seteuid(getuid()) == -1 || setegid(getgid()) == -1) 72 die(gettext("seteuid()/setegid() failed")); 73 74 /* 75 * Add our privileges and remove unneeded 'basic' privileges from the 76 * permitted set. 77 */ 78 if ((privset = priv_str_to_set("basic", ",", NULL)) == NULL) 79 die(gettext("cannot setup privileges")); 80 81 (void) priv_addset(privset, PRIV_SYS_ACCT); 82 (void) priv_addset(privset, PRIV_FILE_DAC_WRITE); 83 (void) priv_addset(privset, PRIV_SYS_DL_CONFIG); 84 (void) priv_delset(privset, PRIV_FILE_LINK_ANY); 85 (void) priv_delset(privset, PRIV_PROC_EXEC); 86 (void) priv_delset(privset, PRIV_PROC_FORK); 87 (void) priv_delset(privset, PRIV_PROC_INFO); 88 (void) priv_delset(privset, PRIV_PROC_SESSION); 89 priv_inverse(privset); 90 if (setppriv(PRIV_OFF, PRIV_PERMITTED, privset) == -1) 91 die(gettext("cannot setup privileges")); 92 priv_freeset(privset); 93 94 /* 95 * Clear the Inheritable and Limit sets. 96 */ 97 if ((privset = priv_allocset()) == NULL) 98 die(gettext("cannot setup privileges")); 99 priv_emptyset(privset); 100 if (setppriv(PRIV_SET, PRIV_INHERITABLE, privset) == -1 || 101 setppriv(PRIV_SET, PRIV_LIMIT, privset) == -1) 102 die(gettext("cannot setup privileges")); 103 104 /* 105 * Turn off the sys_acct, file_dac_write and dl_config privileges 106 * until needed. 107 */ 108 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, 109 PRIV_SYS_ACCT, PRIV_SYS_DL_CONFIG, NULL); 110 } 111 112 int 113 main(int argc, char *argv[]) 114 { 115 int c; /* options character */ 116 int type = 0; /* type of accounting */ 117 int modified = 0; /* have we modified any properties? */ 118 acctconf_t ac; /* current configuration */ 119 char *typestr = NULL; /* type of accounting argument string */ 120 char *enabled = NULL; /* enabled resources string */ 121 char *disabled = NULL; /* disabled resources string */ 122 char *file = NULL; 123 int Eflg = 0; 124 int Dflg = 0; 125 int rflg = 0; 126 int sflg = 0; 127 int xflg = 0; 128 int optcnt = 0; 129 int state; 130 const char *fmri; /* FMRI for this instance */ 131 int err = 0; 132 133 setup_privs(); 134 135 (void) setlocale(LC_ALL, ""); 136 (void) textdomain(TEXT_DOMAIN); 137 (void) setpname(argv[0]); 138 139 for (; optind < argc; optind++) { 140 while ((c = getopt(argc, argv, OPTS)) != (int)EOF) { 141 switch (c) { 142 case 'd': 143 disabled = optarg; 144 break; 145 case 'e': 146 enabled = optarg; 147 break; 148 case 'D': 149 Dflg = 1; 150 optcnt++; 151 break; 152 case 'E': 153 Eflg = 1; 154 optcnt++; 155 break; 156 case 'f': 157 file = optarg; 158 optcnt++; 159 break; 160 case 'r': 161 rflg = 1; 162 optcnt++; 163 break; 164 case 's': 165 sflg = 1; 166 optcnt++; 167 break; 168 case 'x': 169 xflg = 1; 170 optcnt++; 171 break; 172 case '?': 173 default: 174 usage(); 175 } 176 } 177 178 /* 179 * Permanently give up euid 0, egid 0 and privileges we 180 * don't need for the specified options. 181 */ 182 if (!(file || sflg)) { 183 if (setreuid(getuid(), getuid()) == -1 || 184 setregid(getgid(), getgid()) == -1) 185 die(gettext("setreuid()/setregid() failed")); 186 (void) priv_set(PRIV_OFF, PRIV_PERMITTED, 187 PRIV_FILE_DAC_WRITE, NULL); 188 } 189 if (!(disabled || enabled || Dflg || Eflg || file || sflg || 190 xflg)) 191 (void) priv_set(PRIV_OFF, PRIV_PERMITTED, 192 PRIV_SYS_ACCT, PRIV_SYS_DL_CONFIG, NULL); 193 194 if (optind < argc) { 195 if (typestr != NULL) { 196 warn(gettext("illegal argument -- %s\n"), 197 argv[optind]); 198 usage(); 199 } else { 200 typestr = argv[optind]; 201 } 202 } 203 } 204 if (typestr != NULL) { 205 if (strcmp(typestr, "process") == 0 || 206 strcmp(typestr, "proc") == 0) 207 type |= AC_PROC; 208 else if (strcmp(typestr, "task") == 0) 209 type |= AC_TASK; 210 else if (strcmp(typestr, "flow") == 0) 211 type |= AC_FLOW; 212 else if (strcmp(typestr, "net") == 0) 213 type |= AC_NET; 214 else { 215 warn(gettext("unknown accounting type -- %s\n"), 216 typestr); 217 usage(); 218 } 219 } else 220 type = AC_PROC | AC_TASK | AC_FLOW | AC_NET; 221 222 /* 223 * Drop the DL config privilege if we are not working with 224 * net. 225 */ 226 if ((type & AC_NET) == 0) { 227 (void) priv_set(PRIV_OFF, PRIV_PERMITTED, 228 PRIV_SYS_DL_CONFIG, NULL); 229 } 230 /* 231 * check for invalid options 232 */ 233 if (optcnt > 1) 234 usage(); 235 236 /* 237 * XXX For AC_NET, enabled/disabled should only be "basic" or 238 * "extended" - need to check it here. 239 */ 240 if ((enabled || disabled) && (rflg || Dflg || sflg || xflg || Eflg)) 241 usage(); 242 243 if ((file || xflg || Dflg || Eflg || enabled || disabled) && 244 !typestr) { 245 warn(gettext("accounting type must be specified\n")); 246 usage(); 247 } 248 249 if (rflg) { 250 printgroups(type); 251 return (E_SUCCESS); 252 } 253 254 /* 255 * If no arguments have been passed then just print out the current 256 * state and exit. 257 */ 258 if (!enabled && !disabled && !file && 259 !Eflg && !rflg && !Dflg && !sflg && !xflg) { 260 aconf_print(stdout, type); 261 return (E_SUCCESS); 262 } 263 264 /* Open the libdladm handle */ 265 if (dladm_open(&dld_handle) != DLADM_STATUS_OK) 266 die(gettext("failed to open dladm handle\n")); 267 268 /* 269 * smf(7) start method. The FMRI to operate on is retrieved from the 270 * SMF_FMRI environment variable that the restarter provides. 271 */ 272 if (sflg) { 273 if ((fmri = getenv("SMF_FMRI")) != NULL) { 274 int ret = aconf_setup(fmri); 275 dladm_close(dld_handle); 276 return (ret); 277 } 278 279 die(gettext("-s option should only be invoked by smf(7)\n")); 280 } 281 282 assert(type == AC_PROC || type == AC_TASK || type == AC_FLOW || 283 type == AC_NET); 284 285 if ((type == AC_FLOW || type == AC_NET) && getzoneid() != GLOBAL_ZONEID) 286 die(gettext("%s accounting cannot be configured in " 287 "non-global zones\n"), ac_type_name(type)); 288 289 fmri = aconf_type2fmri(type); 290 if (aconf_scf_init(fmri) == -1) 291 die(gettext("cannot connect to repository for %s\n"), fmri); 292 293 /* 294 * Since the sys_acct the privilege allows use of acctctl() regardless 295 * of the accounting type, we check the smf(7) authorizations granted 296 * to the user to determine whether the user is allowed to change the 297 * configuration for this particular accounting type. 298 */ 299 if (!aconf_have_smf_auths()) 300 die(gettext("insufficient authorization to change %s extended " 301 "accounting configuration\n"), ac_type_name(type)); 302 303 if (xflg) { 304 /* 305 * Turn off the specified accounting and close its file 306 */ 307 308 /* 309 * Stop net logging before turning it off so that the last 310 * set of logs can be written. 311 */ 312 if (type & AC_NET) { 313 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 314 PRIV_SYS_DL_CONFIG, NULL); 315 err = dladm_stop_usagelog(dld_handle, 316 DLADM_LOGTYPE_FLOW); 317 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 318 PRIV_SYS_DL_CONFIG, NULL); 319 if (err != DLADM_STATUS_OK) { 320 die(gettext("failed to stop logging network " 321 "information, error %d\n"), errno); 322 } 323 } 324 state = AC_OFF; 325 326 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 327 if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1) 328 die(gettext("cannot disable %s accounting"), 329 ac_type_name(type)); 330 if (acctctl(type | AC_FILE_SET, NULL, 0) == -1) 331 die(gettext("cannot close %s accounting file\n"), 332 ac_type_name(type)); 333 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 334 335 if (aconf_set_bool(AC_PROP_STATE, B_FALSE) == -1) 336 die(gettext("cannot update %s property\n"), 337 AC_PROP_STATE); 338 if (aconf_set_string(AC_PROP_FILE, AC_STR_NONE) == -1) 339 die(gettext("cannot update %s property\n"), 340 AC_PROP_FILE); 341 modified++; 342 } 343 344 if (enabled || disabled) { 345 char *tracked, *untracked; 346 ac_res_t *buf; 347 348 /* 349 * Enable/disable resources 350 */ 351 if ((buf = malloc(AC_BUFSIZE)) == NULL) 352 die(gettext("not enough memory\n")); 353 (void) memset(buf, 0, AC_BUFSIZE); 354 if (acctctl(type | AC_RES_GET, buf, AC_BUFSIZE) == -1) { 355 free(buf); 356 die(gettext("cannot obtain list of resources\n")); 357 } 358 if (disabled) { 359 /* 360 * Stop net logging before turning it off so that the 361 * last set of logs can be written. 362 */ 363 if (type & AC_NET) { 364 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 365 PRIV_SYS_DL_CONFIG, NULL); 366 err = dladm_stop_usagelog(dld_handle, 367 strcmp(disabled, "basic") == 0 ? 368 DLADM_LOGTYPE_LINK : DLADM_LOGTYPE_FLOW); 369 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 370 PRIV_SYS_DL_CONFIG, NULL); 371 if (err != DLADM_STATUS_OK) { 372 die(gettext("failed to stop logging " 373 "network information, error %d\n"), 374 errno); 375 } 376 } 377 str2buf(buf, disabled, AC_OFF, type); 378 } else if (enabled) { 379 str2buf(buf, enabled, AC_ON, type); 380 } 381 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 382 if (acctctl(type | AC_RES_SET, buf, AC_BUFSIZE) == -1) { 383 free(buf); 384 die(gettext("cannot enable/disable %s accounting " 385 "resources\n"), ac_type_name(type)); 386 } 387 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 388 tracked = buf2str(buf, AC_BUFSIZE, AC_ON, type); 389 untracked = buf2str(buf, AC_BUFSIZE, AC_OFF, type); 390 if (aconf_set_string(AC_PROP_TRACKED, tracked) == -1) 391 die(gettext("cannot update %s property\n"), 392 AC_PROP_TRACKED); 393 if (aconf_set_string(AC_PROP_UNTRACKED, untracked) == -1) 394 die(gettext("cannot update %s property\n"), 395 AC_PROP_UNTRACKED); 396 free(tracked); 397 free(untracked); 398 free(buf); 399 modified++; 400 } 401 402 if (file) { 403 /* 404 * Open new accounting file 405 */ 406 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 407 if (open_exacct_file(file, type) == -1) { 408 dladm_close(dld_handle); 409 exit(E_ERROR); 410 } 411 if (aconf_set_string(AC_PROP_FILE, file) == -1) 412 die(gettext("cannot update %s property\n"), 413 AC_PROP_FILE); 414 state = AC_ON; 415 416 if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1) 417 die(gettext("cannot enable %s accounting"), 418 ac_type_name(type)); 419 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 420 421 if (aconf_set_bool(AC_PROP_STATE, B_TRUE) == -1) 422 die(gettext("cannot update %s property\n"), 423 AC_PROP_STATE); 424 modified++; 425 } 426 427 /* 428 * Let's get network logging started. We do this after turning on 429 * accounting and opening the file so that we can start writing 430 * immediately. 431 */ 432 if (enabled && (type & AC_NET)) { 433 /* 434 * Default logging interval for AC_NET is 435 * ACCTADM_NET_LOG_INTERVAL. 436 */ 437 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 438 PRIV_SYS_DL_CONFIG, NULL); 439 err = dladm_start_usagelog(dld_handle, 440 strcmp(enabled, "basic") == 0 ? 441 DLADM_LOGTYPE_LINK : DLADM_LOGTYPE_FLOW, 442 ACCTADM_NET_LOG_INTERVAL); 443 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 444 PRIV_SYS_DL_CONFIG, NULL); 445 if (err != DLADM_STATUS_OK) { 446 die(gettext("failed to start logging " 447 "network information, error %d\n"), 448 errno); 449 } 450 } 451 452 if (Dflg) { 453 /* 454 * Disable accounting 455 */ 456 457 /* 458 * Stop net logging before turning it off so that the last 459 * set of logs can be written. 460 */ 461 if (type & AC_NET) { 462 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 463 PRIV_SYS_DL_CONFIG, NULL); 464 err = dladm_stop_usagelog(dld_handle, 465 DLADM_LOGTYPE_FLOW); 466 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 467 PRIV_SYS_DL_CONFIG, NULL); 468 if (err != DLADM_STATUS_OK) { 469 die(gettext("failed to stop logging " 470 "network information, error %d\n"), errno); 471 } 472 } 473 state = AC_OFF; 474 475 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 476 if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1) 477 die(gettext("cannot disable %s accounting"), 478 ac_type_name(type)); 479 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 480 481 if (aconf_set_bool(AC_PROP_STATE, B_FALSE) == -1) 482 die(gettext("cannot update %s property\n"), 483 AC_PROP_STATE); 484 modified++; 485 } 486 487 if (Eflg) { 488 /* 489 * Enable accounting 490 */ 491 492 /* 493 * Let's get network logging started. 494 */ 495 if (type & AC_NET) { 496 /* 497 * Default logging interval for AC_NET is 498 * ACCTADM_NET_LOG_INTERVAL. 499 */ 500 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 501 PRIV_SYS_DL_CONFIG, NULL); 502 err = dladm_start_usagelog(dld_handle, 503 DLADM_LOGTYPE_FLOW, ACCTADM_NET_LOG_INTERVAL); 504 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 505 PRIV_SYS_DL_CONFIG, NULL); 506 if (err != DLADM_STATUS_OK) { 507 die(gettext("failed to start logging " 508 "network information, error %d\n"), errno); 509 } 510 } 511 state = AC_ON; 512 513 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 514 if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1) 515 die(gettext("cannot enable %s accounting"), 516 ac_type_name(type)); 517 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 518 519 if (aconf_set_bool(AC_PROP_STATE, B_TRUE) == -1) 520 die(gettext("cannot update %s property\n"), 521 AC_PROP_STATE); 522 modified++; 523 } 524 (void) priv_set(PRIV_OFF, PRIV_PERMITTED, PRIV_SYS_ACCT, NULL); 525 526 if (modified) { 527 char *smf_state; 528 529 if (aconf_save() == -1) 530 die(gettext("cannot save %s accounting " 531 "configuration\n"), ac_type_name(type)); 532 533 /* 534 * Enable or disable the instance depending on the effective 535 * configuration. If the effective configuration results in 536 * extended accounting being 'on', the instance is enabled so 537 * the configuration is applied at the next boot. 538 */ 539 smf_state = smf_get_state(fmri); 540 aconf_init(&ac, type); 541 542 if (ac.state == AC_ON || 543 strcmp(ac.file, AC_STR_NONE) != 0 || 544 strcmp(ac.tracked, AC_STR_NONE) != 0) { 545 if (strcmp(smf_state, SCF_STATE_STRING_ONLINE) != 0) 546 if (smf_enable_instance(fmri, 0) == -1) 547 die(gettext("cannot enable %s\n"), 548 fmri); 549 } else { 550 if (strcmp(smf_state, SCF_STATE_STRING_ONLINE) == 0) 551 if (smf_disable_instance(fmri, 0) == -1) 552 die(gettext("cannot disable %s\n"), 553 fmri); 554 } 555 free(smf_state); 556 } 557 aconf_scf_fini(); 558 dladm_close(dld_handle); 559 return (E_SUCCESS); 560 } 561