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