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