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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 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) setprogname(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(5) 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(5)\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(5) 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 } 379 if (enabled) { 380 /* 381 * Lets us get network logging started. 382 */ 383 if (type & AC_NET) { 384 /* 385 * Default logging interval for AC_NET is 386 * ACCTADM_NET_LOG_INTERVAL. 387 */ 388 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 389 PRIV_SYS_DL_CONFIG, NULL); 390 err = dladm_start_usagelog(dld_handle, 391 strcmp(enabled, "basic") == 0 ? 392 DLADM_LOGTYPE_LINK : DLADM_LOGTYPE_FLOW, 393 ACCTADM_NET_LOG_INTERVAL); 394 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 395 PRIV_SYS_DL_CONFIG, NULL); 396 if (err != DLADM_STATUS_OK) { 397 die(gettext("failed to start logging " 398 "network information, error %d\n"), 399 errno); 400 } 401 } 402 str2buf(buf, enabled, AC_ON, type); 403 } 404 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 405 if (acctctl(type | AC_RES_SET, buf, AC_BUFSIZE) == -1) { 406 free(buf); 407 die(gettext("cannot enable/disable %s accounting " 408 "resources\n"), ac_type_name(type)); 409 } 410 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 411 412 tracked = buf2str(buf, AC_BUFSIZE, AC_ON, type); 413 untracked = buf2str(buf, AC_BUFSIZE, AC_OFF, type); 414 if (aconf_set_string(AC_PROP_TRACKED, tracked) == -1) 415 die(gettext("cannot update %s property\n"), 416 AC_PROP_TRACKED); 417 if (aconf_set_string(AC_PROP_UNTRACKED, untracked) == -1) 418 die(gettext("cannot update %s property\n"), 419 AC_PROP_UNTRACKED); 420 free(tracked); 421 free(untracked); 422 free(buf); 423 modified++; 424 } 425 426 if (file) { 427 /* 428 * Open new accounting file 429 */ 430 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 431 if (open_exacct_file(file, type) == -1) { 432 dladm_close(dld_handle); 433 exit(E_ERROR); 434 } 435 if (aconf_set_string(AC_PROP_FILE, file) == -1) 436 die(gettext("cannot update %s property\n"), 437 AC_PROP_FILE); 438 state = AC_ON; 439 440 if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1) 441 die(gettext("cannot enable %s accounting"), 442 ac_type_name(type)); 443 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 444 445 if (aconf_set_bool(AC_PROP_STATE, B_TRUE) == -1) 446 die(gettext("cannot update %s property\n"), 447 AC_PROP_STATE); 448 modified++; 449 } 450 451 if (Dflg) { 452 /* 453 * Disable accounting 454 */ 455 456 /* 457 * Stop net logging before turning it off so that the last 458 * set of logs can be written. 459 */ 460 if (type & AC_NET) { 461 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 462 PRIV_SYS_DL_CONFIG, NULL); 463 err = dladm_stop_usagelog(dld_handle, 464 DLADM_LOGTYPE_FLOW); 465 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 466 PRIV_SYS_DL_CONFIG, NULL); 467 if (err != DLADM_STATUS_OK) { 468 die(gettext("failed to stop logging " 469 "network information, error %d\n"), errno); 470 } 471 } 472 state = AC_OFF; 473 474 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 475 if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1) 476 die(gettext("cannot disable %s accounting"), 477 ac_type_name(type)); 478 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 479 480 if (aconf_set_bool(AC_PROP_STATE, B_FALSE) == -1) 481 die(gettext("cannot update %s property\n"), 482 AC_PROP_STATE); 483 modified++; 484 } 485 486 if (Eflg) { 487 /* 488 * Enable accounting 489 */ 490 491 /* 492 * Let's get network logging started. 493 */ 494 if (type & AC_NET) { 495 /* 496 * Default logging interval for AC_NET is 497 * ACCTADM_NET_LOG_INTERVAL. 498 */ 499 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, 500 PRIV_SYS_DL_CONFIG, NULL); 501 err = dladm_start_usagelog(dld_handle, 502 DLADM_LOGTYPE_FLOW, ACCTADM_NET_LOG_INTERVAL); 503 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, 504 PRIV_SYS_DL_CONFIG, NULL); 505 if (err != DLADM_STATUS_OK) { 506 die(gettext("failed to start logging " 507 "network information, error %d\n"), errno); 508 } 509 } 510 state = AC_ON; 511 512 (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 513 if (acctctl(type | AC_STATE_SET, &state, sizeof (int)) == -1) 514 die(gettext("cannot enable %s accounting"), 515 ac_type_name(type)); 516 (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_SYS_ACCT, NULL); 517 518 if (aconf_set_bool(AC_PROP_STATE, B_TRUE) == -1) 519 die(gettext("cannot update %s property\n"), 520 AC_PROP_STATE); 521 modified++; 522 } 523 (void) priv_set(PRIV_OFF, PRIV_PERMITTED, PRIV_SYS_ACCT, NULL); 524 525 if (modified) { 526 char *smf_state; 527 528 if (aconf_save() == -1) 529 die(gettext("cannot save %s accounting " 530 "configuration\n"), ac_type_name(type)); 531 532 /* 533 * Enable or disable the instance depending on the effective 534 * configuration. If the effective configuration results in 535 * extended accounting being 'on', the instance is enabled so 536 * the configuration is applied at the next boot. 537 */ 538 smf_state = smf_get_state(fmri); 539 aconf_init(&ac, type); 540 541 if (ac.state == AC_ON || 542 strcmp(ac.file, AC_STR_NONE) != 0 || 543 strcmp(ac.tracked, AC_STR_NONE) != 0) { 544 if (strcmp(smf_state, SCF_STATE_STRING_ONLINE) != 0) 545 if (smf_enable_instance(fmri, 0) == -1) 546 die(gettext("cannot enable %s\n"), 547 fmri); 548 } else { 549 if (strcmp(smf_state, SCF_STATE_STRING_ONLINE) == 0) 550 if (smf_disable_instance(fmri, 0) == -1) 551 die(gettext("cannot disable %s\n"), 552 fmri); 553 } 554 free(smf_state); 555 } 556 aconf_scf_fini(); 557 dladm_close(dld_handle); 558 return (E_SUCCESS); 559 } 560