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(8) 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 = (uintptr_t)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 default: 123 event_id = 0; 124 } 125 if ((event_id != 0) && 126 (event = adt_alloc_event(ah, event_id)) == NULL) { 127 (void) fprintf(stderr, "%s: can't allocate audit event\n", 128 argv[0]); 129 } 130 switch (fcn) { 131 case AD_HALT: 132 fcn_id = ADT_UADMIN_FCN_AD_HALT; 133 break; 134 case AD_POWEROFF: 135 fcn_id = ADT_UADMIN_FCN_AD_POWEROFF; 136 break; 137 case AD_BOOT: 138 fcn_id = ADT_UADMIN_FCN_AD_BOOT; 139 break; 140 case AD_IBOOT: 141 fcn_id = ADT_UADMIN_FCN_AD_IBOOT; 142 break; 143 case AD_SBOOT: 144 fcn_id = ADT_UADMIN_FCN_AD_SBOOT; 145 break; 146 case AD_SIBOOT: 147 fcn_id = ADT_UADMIN_FCN_AD_SIBOOT; 148 break; 149 case AD_NOSYNC: 150 fcn_id = ADT_UADMIN_FCN_AD_NOSYNC; 151 break; 152 case AD_FASTREBOOT: 153 #ifdef __i386 154 fcn_id = ADT_UADMIN_FCN_AD_FASTREBOOT; 155 mdep = (uintptr_t)NULL; /* Ignore all arguments */ 156 #else /* __i386 */ 157 fcn = AD_BOOT; 158 fcn_id = ADT_UADMIN_FCN_AD_BOOT; 159 #endif /* __i386 */ 160 break; 161 case AD_FASTREBOOT_DRYRUN: 162 fcn_id = ADT_UADMIN_FCN_AD_FASTREBOOT_DRYRUN; 163 mdep = (uintptr_t)NULL; /* Ignore all arguments */ 164 break; 165 default: 166 fcn_id = 0; 167 } 168 if (cmd == A_FREEZE) { 169 switch (fcn) { 170 case AD_SUSPEND_TO_DISK: 171 fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_DISK; 172 break; 173 case AD_CHECK_SUSPEND_TO_DISK: 174 fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_DISK; 175 break; 176 case AD_FORCE: 177 fcn_id = ADT_UADMIN_FCN_AD_FORCE; 178 break; 179 case AD_SUSPEND_TO_RAM: 180 fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_RAM; 181 break; 182 case AD_CHECK_SUSPEND_TO_RAM: 183 fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_RAM; 184 break; 185 case AD_REUSEINIT: 186 fcn_id = ADT_UADMIN_FCN_AD_REUSEINIT; 187 break; 188 case AD_REUSABLE: 189 fcn_id = ADT_UADMIN_FCN_AD_REUSABLE; 190 break; 191 case AD_REUSEFINI: 192 fcn_id = ADT_UADMIN_FCN_AD_REUSEFINI; 193 break; 194 } 195 } else if (cmd == A_FTRACE) { 196 switch (fcn) { 197 case AD_FTRACE_START: 198 fcn_id = ADT_UADMIN_FCN_AD_FTRACE_START; 199 break; 200 case AD_FTRACE_STOP: 201 fcn_id = ADT_UADMIN_FCN_AD_FTRACE_STOP; 202 break; 203 } 204 #ifdef __i386 205 } else if (cmd == A_CONFIG) { 206 uint8_t boot_config = 0; 207 uint8_t boot_config_ovr = 0; 208 209 switch (fcn) { 210 case AD_UPDATE_BOOT_CONFIG: 211 fcn_id = ADT_UADMIN_FCN_AD_UPDATE_BOOT_CONFIG; 212 scf_get_boot_config(&boot_config); 213 boot_config_ovr = boot_config; 214 scf_get_boot_config_ovr(&boot_config_ovr); 215 boot_config &= boot_config_ovr; 216 mdep = (uintptr_t)(&boot_config); 217 break; 218 } 219 #endif /* __i386 */ 220 } 221 222 if (geteuid() == 0) { 223 if (event != NULL) { 224 switch (cmd) { 225 case A_SHUTDOWN: 226 event->adt_uadmin_shutdown.fcn = fcn_id; 227 event->adt_uadmin_shutdown.mdep = (char *)mdep; 228 break; 229 case A_REBOOT: 230 event->adt_uadmin_reboot.fcn = fcn_id; 231 event->adt_uadmin_reboot.mdep = (char *)mdep; 232 break; 233 case A_DUMP: 234 event->adt_uadmin_dump.fcn = fcn_id; 235 event->adt_uadmin_dump.mdep = (char *)mdep; 236 break; 237 case A_REMOUNT: 238 /* no parameters */ 239 break; 240 case A_FREEZE: 241 event->adt_uadmin_freeze.fcn = fcn_id; 242 event->adt_uadmin_freeze.mdep = (char *)mdep; 243 break; 244 case A_FTRACE: 245 event->adt_uadmin_ftrace.fcn = fcn_id; 246 event->adt_uadmin_ftrace.mdep = (char *)mdep; 247 break; 248 case A_CONFIG: 249 event->adt_uadmin_config.fcn = fcn_id; 250 event->adt_uadmin_config.mdep = (char *)mdep; 251 break; 252 case A_SWAPCTL: 253 event->adt_uadmin_swapctl.fcn = fcn_id; 254 break; 255 } 256 257 if (adt_put_event(event, ADT_SUCCESS, 0) != 0) { 258 (void) fprintf(stderr, 259 "%s: can't put audit event\n", argv[0]); 260 } 261 /* 262 * allow audit record to be processed in the kernel 263 * audit queue 264 */ 265 wait_for_auqueue(); 266 } 267 268 if (closeout_audit(cmd, fcn) == -1) 269 (void) fprintf(stderr, "%s: can't turn off auditd\n", 270 argv[0]); 271 272 if (cmd == A_SHUTDOWN || cmd == A_REBOOT) 273 (void) creat(SMF_RST, 0777); 274 } 275 276 (void) adt_free_event(event); 277 if (uadmin(cmd, fcn, mdep) < 0) { 278 perror("uadmin"); 279 280 (void) unlink(SMF_RST); 281 282 return (1); 283 } 284 285 /* If returning from a suspend, audit thaw */ 286 if ((cmd == A_FREEZE) && 287 ((fcn == AD_FORCE) || 288 (fcn == AD_REUSABLE) || 289 (fcn == AD_SUSPEND_TO_DISK) || 290 (fcn == AD_SUSPEND_TO_RAM))) { 291 if ((event = adt_alloc_event(ah, ADT_uadmin_thaw)) == NULL) { 292 (void) fprintf(stderr, "%s: can't allocate thaw audit " 293 "event\n", argv[0]); 294 } 295 event->adt_uadmin_thaw.fcn = fcn_id; 296 if (adt_put_event(event, ADT_SUCCESS, 0) != 0) { 297 (void) fprintf(stderr, "%s: can't put thaw audit " 298 "event\n", argv[0]); 299 } 300 (void) adt_free_event(event); 301 } 302 (void) adt_end_session(ah); 303 304 return (0); 305 } 306 307 static int 308 closeout_audit(int cmd, int fcn) 309 { 310 if (!adt_audit_state(AUC_AUDITING)) { 311 /* auditd not running, just return */ 312 return (0); 313 } 314 switch (cmd) { 315 case A_SHUTDOWN: 316 switch (fcn) { 317 case AD_FASTREBOOT_DRYRUN: 318 /* No system discontinuity, don't turn off auditd */ 319 return (0); 320 default: 321 break; /* For all the other shutdown functions */ 322 } 323 /* FALLTHROUGH */ 324 case A_REBOOT: 325 case A_DUMP: 326 /* system shutting down, turn off auditd */ 327 return (turnoff_auditd()); 328 case A_REMOUNT: 329 case A_SWAPCTL: 330 case A_FTRACE: 331 case A_CONFIG: 332 /* No system discontinuity, don't turn off auditd */ 333 return (0); 334 case A_FREEZE: 335 switch (fcn) { 336 case AD_CHECK_SUSPEND_TO_DISK: /* AD_CHECK */ 337 case AD_CHECK_SUSPEND_TO_RAM: 338 case AD_REUSEINIT: 339 case AD_REUSEFINI: 340 /* No system discontinuity, don't turn off auditd */ 341 return (0); 342 case AD_REUSABLE: 343 case AD_SUSPEND_TO_DISK: /* AD_COMPRESS */ 344 case AD_SUSPEND_TO_RAM: 345 case AD_FORCE: 346 /* suspend the system, change audit files */ 347 return (change_audit_file()); 348 default: 349 return (0); /* not an audit error */ 350 } 351 default: 352 return (0); /* not an audit error */ 353 } 354 } 355 356 static int 357 turnoff_auditd(void) 358 { 359 int rc; 360 int retries = RETRY_COUNT; 361 362 if ((rc = (int)fork()) == 0) { 363 (void) execl("/usr/sbin/audit", "audit", "-T", NULL); 364 (void) fprintf(stderr, "error disabling auditd: %s\n", 365 strerror(errno)); 366 _exit(-1); 367 } else if (rc == -1) { 368 (void) fprintf(stderr, "error disabling auditd: %s\n", 369 strerror(errno)); 370 return (-1); 371 } 372 373 /* 374 * wait for auditd to finish its work. auditd will change the 375 * auditstart from AUC_AUDITING (auditd up and running) to 376 * AUC_NOAUDIT. Other states are errors, so we're done as well. 377 */ 378 do { 379 int auditstate; 380 381 rc = -1; 382 if ((auditon(A_GETCOND, (caddr_t)&auditstate, 383 sizeof (auditstate)) == 0) && 384 (auditstate == AUC_AUDITING)) { 385 retries--; 386 (void) sleep(1); 387 } else { 388 rc = 0; 389 } 390 } while ((rc != 0) && (retries != 0)); 391 392 return (rc); 393 } 394 395 static int 396 change_audit_file(void) 397 { 398 pid_t pid; 399 400 if ((pid = fork()) == 0) { 401 (void) execl("/usr/sbin/audit", "audit", "-n", NULL); 402 (void) fprintf(stderr, "error changing audit files: %s\n", 403 strerror(errno)); 404 _exit(-1); 405 } else if (pid == -1) { 406 (void) fprintf(stderr, "error changing audit files: %s\n", 407 strerror(errno)); 408 return (-1); 409 } else { 410 pid_t rc; 411 int retries = RETRY_COUNT; 412 413 /* 414 * Wait for audit(8) -n process to complete 415 * 416 */ 417 do { 418 if ((rc = waitpid(pid, NULL, WNOHANG)) == pid) { 419 return (0); 420 } else if (rc == -1) { 421 return (-1); 422 } else { 423 (void) sleep(1); 424 retries--; 425 } 426 427 } while (retries != 0); 428 } 429 return (-1); 430 } 431 432 static void 433 wait_for_auqueue() 434 { 435 au_stat_t au_stat; 436 int retries = 10; 437 438 while (retries-- && auditon(A_GETSTAT, (caddr_t)&au_stat, 0) == 0) { 439 if (au_stat.as_enqueue == au_stat.as_written) { 440 break; 441 } 442 (void) sleep(1); 443 } 444 } 445