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