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