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