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