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 (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 29 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <signal.h> 37 #include <unistd.h> 38 #ifdef __i386 39 #include <libscf_priv.h> 40 #endif /* __i386 */ 41 42 #include <bsm/adt.h> 43 #include <bsm/adt_event.h> 44 45 #include <sys/types.h> 46 #include <sys/uadmin.h> 47 #include <sys/wait.h> 48 49 #define SMF_RST "/etc/svc/volatile/resetting" 50 #define RETRY_COUNT 15 /* number of 1 sec retries for audit(1M) to complete */ 51 52 static const char *Usage = "Usage: %s cmd fcn [mdep]\n"; 53 54 static int closeout_audit(int, int); 55 static int turnoff_auditd(void); 56 static void wait_for_auqueue(); 57 static int change_audit_file(void); 58 59 int 60 main(int argc, char *argv[]) 61 { 62 int cmd, fcn; 63 uintptr_t mdep = NULL; 64 sigset_t set; 65 adt_session_data_t *ah; /* audit session handle */ 66 adt_event_data_t *event = NULL; /* event to be generated */ 67 au_event_t event_id; 68 enum adt_uadmin_fcn fcn_id; 69 70 if (argc < 3 || argc > 4) { 71 (void) fprintf(stderr, Usage, argv[0]); 72 return (1); 73 } 74 75 (void) sigfillset(&set); 76 (void) sigprocmask(SIG_BLOCK, &set, NULL); 77 78 cmd = atoi(argv[1]); 79 fcn = atoi(argv[2]); 80 if (argc == 4) { /* mdep argument given */ 81 if (cmd != A_REBOOT && cmd != A_SHUTDOWN && cmd != A_DUMP && 82 cmd != A_FREEZE) { 83 (void) fprintf(stderr, "%s: mdep argument not " 84 "allowed for this cmd value\n", argv[0]); 85 (void) fprintf(stderr, Usage, argv[0]); 86 return (1); 87 } else { 88 mdep = (uintptr_t)argv[3]; 89 } 90 } 91 92 /* set up audit session and event */ 93 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) { 94 (void) fprintf(stderr, "%s: can't start audit session\n", 95 argv[0]); 96 } 97 switch (cmd) { 98 case A_SHUTDOWN: 99 event_id = ADT_uadmin_shutdown; 100 break; 101 case A_REBOOT: 102 event_id = ADT_uadmin_reboot; 103 break; 104 case A_DUMP: 105 event_id = ADT_uadmin_dump; 106 break; 107 case A_REMOUNT: 108 event_id = ADT_uadmin_remount; 109 break; 110 case A_FREEZE: 111 event_id = ADT_uadmin_freeze; 112 break; 113 case A_FTRACE: 114 event_id = ADT_uadmin_ftrace; 115 break; 116 case A_CONFIG: 117 event_id = ADT_uadmin_config; 118 break; 119 case A_SWAPCTL: 120 event_id = ADT_uadmin_swapctl; 121 break; 122 case A_INTRD: 123 event_id = ADT_uadmin_intrd; 124 break; 125 default: 126 event_id = 0; 127 } 128 if ((event_id != 0) && 129 (event = adt_alloc_event(ah, event_id)) == NULL) { 130 (void) fprintf(stderr, "%s: can't allocate audit event\n", 131 argv[0]); 132 } 133 switch (fcn) { 134 case AD_HALT: 135 fcn_id = ADT_UADMIN_FCN_AD_HALT; 136 break; 137 case AD_POWEROFF: 138 fcn_id = ADT_UADMIN_FCN_AD_POWEROFF; 139 break; 140 case AD_BOOT: 141 fcn_id = ADT_UADMIN_FCN_AD_BOOT; 142 break; 143 case AD_IBOOT: 144 fcn_id = ADT_UADMIN_FCN_AD_IBOOT; 145 break; 146 case AD_SBOOT: 147 fcn_id = ADT_UADMIN_FCN_AD_SBOOT; 148 break; 149 case AD_SIBOOT: 150 fcn_id = ADT_UADMIN_FCN_AD_SIBOOT; 151 break; 152 case AD_NOSYNC: 153 fcn_id = ADT_UADMIN_FCN_AD_NOSYNC; 154 break; 155 case AD_FASTREBOOT: 156 #ifdef __i386 157 fcn_id = ADT_UADMIN_FCN_AD_FASTREBOOT; 158 mdep = NULL; /* Ignore all arguments */ 159 #else /* __i386 */ 160 fcn = AD_BOOT; 161 fcn_id = ADT_UADMIN_FCN_AD_BOOT; 162 #endif /* __i386 */ 163 break; 164 case AD_FASTREBOOT_DRYRUN: 165 fcn_id = ADT_UADMIN_FCN_AD_FASTREBOOT_DRYRUN; 166 mdep = NULL; /* Ignore all arguments */ 167 break; 168 default: 169 fcn_id = 0; 170 } 171 if (cmd == A_FREEZE) { 172 switch (fcn) { 173 case AD_SUSPEND_TO_DISK: 174 fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_DISK; 175 break; 176 case AD_CHECK_SUSPEND_TO_DISK: 177 fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_DISK; 178 break; 179 case AD_FORCE: 180 fcn_id = ADT_UADMIN_FCN_AD_FORCE; 181 break; 182 case AD_SUSPEND_TO_RAM: 183 fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_RAM; 184 break; 185 case AD_CHECK_SUSPEND_TO_RAM: 186 fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_RAM; 187 break; 188 case AD_REUSEINIT: 189 fcn_id = ADT_UADMIN_FCN_AD_REUSEINIT; 190 break; 191 case AD_REUSABLE: 192 fcn_id = ADT_UADMIN_FCN_AD_REUSABLE; 193 break; 194 case AD_REUSEFINI: 195 fcn_id = ADT_UADMIN_FCN_AD_REUSEFINI; 196 break; 197 } 198 } else if (cmd == A_FTRACE) { 199 switch (fcn) { 200 case AD_FTRACE_START: 201 fcn_id = ADT_UADMIN_FCN_AD_FTRACE_START; 202 break; 203 case AD_FTRACE_STOP: 204 fcn_id = ADT_UADMIN_FCN_AD_FTRACE_STOP; 205 break; 206 } 207 #ifdef __i386 208 } else if (cmd == A_CONFIG) { 209 uint8_t boot_config = 0; 210 uint8_t boot_config_ovr = 0; 211 212 switch (fcn) { 213 case AD_UPDATE_BOOT_CONFIG: 214 fcn_id = ADT_UADMIN_FCN_AD_UPDATE_BOOT_CONFIG; 215 scf_get_boot_config(&boot_config); 216 boot_config_ovr = boot_config; 217 scf_get_boot_config_ovr(&boot_config_ovr); 218 boot_config &= boot_config_ovr; 219 mdep = (uintptr_t)(&boot_config); 220 break; 221 } 222 #endif /* __i386 */ 223 } 224 225 if (geteuid() == 0) { 226 if (event != NULL) { 227 switch (cmd) { 228 case A_SHUTDOWN: 229 event->adt_uadmin_shutdown.fcn = fcn_id; 230 event->adt_uadmin_shutdown.mdep = (char *)mdep; 231 break; 232 case A_REBOOT: 233 event->adt_uadmin_reboot.fcn = fcn_id; 234 event->adt_uadmin_reboot.mdep = (char *)mdep; 235 break; 236 case A_DUMP: 237 event->adt_uadmin_dump.fcn = fcn_id; 238 event->adt_uadmin_dump.mdep = (char *)mdep; 239 break; 240 case A_REMOUNT: 241 /* no parameters */ 242 break; 243 case A_FREEZE: 244 event->adt_uadmin_freeze.fcn = fcn_id; 245 event->adt_uadmin_freeze.mdep = (char *)mdep; 246 break; 247 case A_FTRACE: 248 event->adt_uadmin_ftrace.fcn = fcn_id; 249 event->adt_uadmin_ftrace.mdep = (char *)mdep; 250 break; 251 case A_CONFIG: 252 event->adt_uadmin_config.fcn = fcn_id; 253 event->adt_uadmin_config.mdep = (char *)mdep; 254 break; 255 case A_SWAPCTL: 256 event->adt_uadmin_swapctl.fcn = fcn_id; 257 break; 258 case A_INTRD: 259 event->adt_uadmin_intrd.fcn = fcn_id; 260 break; 261 } 262 263 if (adt_put_event(event, ADT_SUCCESS, 0) != 0) { 264 (void) fprintf(stderr, 265 "%s: can't put audit event\n", argv[0]); 266 } 267 /* 268 * allow audit record to be processed in the kernel 269 * audit queue 270 */ 271 wait_for_auqueue(); 272 } 273 274 if (closeout_audit(cmd, fcn) == -1) 275 (void) fprintf(stderr, "%s: can't turn off auditd\n", 276 argv[0]); 277 278 if (cmd == A_SHUTDOWN || cmd == A_REBOOT) 279 (void) creat(SMF_RST, 0777); 280 } 281 282 (void) adt_free_event(event); 283 if (uadmin(cmd, fcn, mdep) < 0) { 284 perror("uadmin"); 285 286 (void) unlink(SMF_RST); 287 288 return (1); 289 } 290 291 /* If returning from a suspend, audit thaw */ 292 if ((cmd == A_FREEZE) && 293 ((fcn == AD_FORCE) || 294 (fcn == AD_REUSABLE) || 295 (fcn == AD_SUSPEND_TO_DISK) || 296 (fcn == AD_SUSPEND_TO_RAM))) { 297 if ((event = adt_alloc_event(ah, ADT_uadmin_thaw)) == NULL) { 298 (void) fprintf(stderr, "%s: can't allocate thaw audit " 299 "event\n", argv[0]); 300 } 301 event->adt_uadmin_thaw.fcn = fcn_id; 302 if (adt_put_event(event, ADT_SUCCESS, 0) != 0) { 303 (void) fprintf(stderr, "%s: can't put thaw audit " 304 "event\n", argv[0]); 305 } 306 (void) adt_free_event(event); 307 } 308 (void) adt_end_session(ah); 309 310 return (0); 311 } 312 313 static int 314 closeout_audit(int cmd, int fcn) 315 { 316 if (!adt_audit_state(AUC_AUDITING)) { 317 /* auditd not running, just return */ 318 return (0); 319 } 320 switch (cmd) { 321 case A_SHUTDOWN: 322 switch (fcn) { 323 case AD_FASTREBOOT_DRYRUN: 324 /* No system discontinuity, don't turn off auditd */ 325 return (0); 326 default: 327 break; /* For all the other shutdown functions */ 328 } 329 /* FALLTHROUGH */ 330 case A_REBOOT: 331 case A_DUMP: 332 /* system shutting down, turn off auditd */ 333 return (turnoff_auditd()); 334 case A_REMOUNT: 335 case A_SWAPCTL: 336 case A_FTRACE: 337 case A_CONFIG: 338 /* No system discontinuity, don't turn off auditd */ 339 return (0); 340 case A_FREEZE: 341 switch (fcn) { 342 case AD_CHECK_SUSPEND_TO_DISK: /* AD_CHECK */ 343 case AD_CHECK_SUSPEND_TO_RAM: 344 case AD_REUSEINIT: 345 case AD_REUSEFINI: 346 /* No system discontinuity, don't turn off auditd */ 347 return (0); 348 case AD_REUSABLE: 349 case AD_SUSPEND_TO_DISK: /* AD_COMPRESS */ 350 case AD_SUSPEND_TO_RAM: 351 case AD_FORCE: 352 /* suspend the system, change audit files */ 353 return (change_audit_file()); 354 default: 355 return (0); /* not an audit error */ 356 } 357 default: 358 return (0); /* not an audit error */ 359 } 360 } 361 362 static int 363 turnoff_auditd(void) 364 { 365 int rc; 366 int retries = RETRY_COUNT; 367 368 if ((rc = (int)fork()) == 0) { 369 (void) execl("/usr/sbin/audit", "audit", "-T", NULL); 370 (void) fprintf(stderr, "error disabling auditd: %s\n", 371 strerror(errno)); 372 _exit(-1); 373 } else if (rc == -1) { 374 (void) fprintf(stderr, "error disabling auditd: %s\n", 375 strerror(errno)); 376 return (-1); 377 } 378 379 /* 380 * wait for auditd to finish its work. auditd will change the 381 * auditstart from AUC_AUDITING (auditd up and running) to 382 * AUC_NOAUDIT. Other states are errors, so we're done as well. 383 */ 384 do { 385 int auditstate; 386 387 rc = -1; 388 if ((auditon(A_GETCOND, (caddr_t)&auditstate, 389 sizeof (auditstate)) == 0) && 390 (auditstate == AUC_AUDITING)) { 391 retries--; 392 (void) sleep(1); 393 } else { 394 rc = 0; 395 } 396 } while ((rc != 0) && (retries != 0)); 397 398 return (rc); 399 } 400 401 static int 402 change_audit_file(void) 403 { 404 pid_t pid; 405 406 if ((pid = fork()) == 0) { 407 (void) execl("/usr/sbin/audit", "audit", "-n", NULL); 408 (void) fprintf(stderr, "error changing audit files: %s\n", 409 strerror(errno)); 410 _exit(-1); 411 } else if (pid == -1) { 412 (void) fprintf(stderr, "error changing audit files: %s\n", 413 strerror(errno)); 414 return (-1); 415 } else { 416 pid_t rc; 417 int retries = RETRY_COUNT; 418 419 /* 420 * Wait for audit(1M) -n process to complete 421 * 422 */ 423 do { 424 if ((rc = waitpid(pid, NULL, WNOHANG)) == pid) { 425 return (0); 426 } else if (rc == -1) { 427 return (-1); 428 } else { 429 (void) sleep(1); 430 retries--; 431 } 432 433 } while (retries != 0); 434 } 435 return (-1); 436 } 437 438 static void 439 wait_for_auqueue() 440 { 441 au_stat_t au_stat; 442 int retries = 10; 443 444 while (retries-- && auditon(A_GETSTAT, (caddr_t)&au_stat, NULL) == 0) { 445 if (au_stat.as_enqueue == au_stat.as_written) { 446 break; 447 } 448 (void) sleep(1); 449 } 450 }