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