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
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 case A_INTRD:
123 event_id = ADT_uadmin_intrd;
124 break;
125 default:
126 event_id = 0;
127 }
128 if ((event_id != 0) &&
129 (event = adt_alloc_event(ah, event_id)) == NULL) {
130 (void) fprintf(stderr, "%s: can't allocate audit event\n",
131 argv[0]);
132 }
133 switch (fcn) {
134 case AD_HALT:
135 fcn_id = ADT_UADMIN_FCN_AD_HALT;
136 break;
137 case AD_POWEROFF:
138 fcn_id = ADT_UADMIN_FCN_AD_POWEROFF;
139 break;
140 case AD_BOOT:
141 fcn_id = ADT_UADMIN_FCN_AD_BOOT;
142 break;
143 case AD_IBOOT:
144 fcn_id = ADT_UADMIN_FCN_AD_IBOOT;
145 break;
146 case AD_SBOOT:
147 fcn_id = ADT_UADMIN_FCN_AD_SBOOT;
148 break;
149 case AD_SIBOOT:
150 fcn_id = ADT_UADMIN_FCN_AD_SIBOOT;
151 break;
152 case AD_NOSYNC:
153 fcn_id = ADT_UADMIN_FCN_AD_NOSYNC;
154 break;
155 case AD_FASTREBOOT:
156 #ifdef __i386
157 fcn_id = ADT_UADMIN_FCN_AD_FASTREBOOT;
158 mdep = NULL; /* Ignore all arguments */
159 #else /* __i386 */
160 fcn = AD_BOOT;
161 fcn_id = ADT_UADMIN_FCN_AD_BOOT;
162 #endif /* __i386 */
163 break;
164 case AD_FASTREBOOT_DRYRUN:
165 fcn_id = ADT_UADMIN_FCN_AD_FASTREBOOT_DRYRUN;
166 mdep = NULL; /* Ignore all arguments */
167 break;
168 default:
169 fcn_id = 0;
170 }
171 if (cmd == A_FREEZE) {
172 switch (fcn) {
173 case AD_SUSPEND_TO_DISK:
174 fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_DISK;
175 break;
176 case AD_CHECK_SUSPEND_TO_DISK:
177 fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_DISK;
178 break;
179 case AD_FORCE:
180 fcn_id = ADT_UADMIN_FCN_AD_FORCE;
181 break;
182 case AD_SUSPEND_TO_RAM:
183 fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_RAM;
184 break;
185 case AD_CHECK_SUSPEND_TO_RAM:
186 fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_RAM;
187 break;
188 case AD_REUSEINIT:
189 fcn_id = ADT_UADMIN_FCN_AD_REUSEINIT;
190 break;
191 case AD_REUSABLE:
192 fcn_id = ADT_UADMIN_FCN_AD_REUSABLE;
193 break;
194 case AD_REUSEFINI:
195 fcn_id = ADT_UADMIN_FCN_AD_REUSEFINI;
196 break;
197 }
198 } else if (cmd == A_FTRACE) {
199 switch (fcn) {
200 case AD_FTRACE_START:
201 fcn_id = ADT_UADMIN_FCN_AD_FTRACE_START;
202 break;
203 case AD_FTRACE_STOP:
204 fcn_id = ADT_UADMIN_FCN_AD_FTRACE_STOP;
205 break;
206 }
207 #ifdef __i386
208 } else if (cmd == A_CONFIG) {
209 uint8_t boot_config = 0;
210 uint8_t boot_config_ovr = 0;
211
212 switch (fcn) {
213 case AD_UPDATE_BOOT_CONFIG:
214 fcn_id = ADT_UADMIN_FCN_AD_UPDATE_BOOT_CONFIG;
215 scf_get_boot_config(&boot_config);
216 boot_config_ovr = boot_config;
217 scf_get_boot_config_ovr(&boot_config_ovr);
218 boot_config &= boot_config_ovr;
219 mdep = (uintptr_t)(&boot_config);
220 break;
221 }
222 #endif /* __i386 */
223 }
224
225 if (geteuid() == 0) {
226 if (event != NULL) {
227 switch (cmd) {
228 case A_SHUTDOWN:
229 event->adt_uadmin_shutdown.fcn = fcn_id;
230 event->adt_uadmin_shutdown.mdep = (char *)mdep;
231 break;
232 case A_REBOOT:
233 event->adt_uadmin_reboot.fcn = fcn_id;
234 event->adt_uadmin_reboot.mdep = (char *)mdep;
235 break;
236 case A_DUMP:
237 event->adt_uadmin_dump.fcn = fcn_id;
238 event->adt_uadmin_dump.mdep = (char *)mdep;
239 break;
240 case A_REMOUNT:
241 /* no parameters */
242 break;
243 case A_FREEZE:
244 event->adt_uadmin_freeze.fcn = fcn_id;
245 event->adt_uadmin_freeze.mdep = (char *)mdep;
246 break;
247 case A_FTRACE:
248 event->adt_uadmin_ftrace.fcn = fcn_id;
249 event->adt_uadmin_ftrace.mdep = (char *)mdep;
250 break;
251 case A_CONFIG:
252 event->adt_uadmin_config.fcn = fcn_id;
253 event->adt_uadmin_config.mdep = (char *)mdep;
254 break;
255 case A_SWAPCTL:
256 event->adt_uadmin_swapctl.fcn = fcn_id;
257 break;
258 case A_INTRD:
259 event->adt_uadmin_intrd.fcn = fcn_id;
260 break;
261 }
262
263 if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
264 (void) fprintf(stderr,
265 "%s: can't put audit event\n", argv[0]);
266 }
267 /*
268 * allow audit record to be processed in the kernel
269 * audit queue
270 */
271 wait_for_auqueue();
272 }
273
274 if (closeout_audit(cmd, fcn) == -1)
275 (void) fprintf(stderr, "%s: can't turn off auditd\n",
276 argv[0]);
277
278 if (cmd == A_SHUTDOWN || cmd == A_REBOOT)
279 (void) creat(SMF_RST, 0777);
280 }
281
282 (void) adt_free_event(event);
283 if (uadmin(cmd, fcn, mdep) < 0) {
284 perror("uadmin");
285
286 (void) unlink(SMF_RST);
287
288 return (1);
289 }
290
291 /* If returning from a suspend, audit thaw */
292 if ((cmd == A_FREEZE) &&
293 ((fcn == AD_FORCE) ||
294 (fcn == AD_REUSABLE) ||
295 (fcn == AD_SUSPEND_TO_DISK) ||
296 (fcn == AD_SUSPEND_TO_RAM))) {
297 if ((event = adt_alloc_event(ah, ADT_uadmin_thaw)) == NULL) {
298 (void) fprintf(stderr, "%s: can't allocate thaw audit "
299 "event\n", argv[0]);
300 }
301 event->adt_uadmin_thaw.fcn = fcn_id;
302 if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
303 (void) fprintf(stderr, "%s: can't put thaw audit "
304 "event\n", argv[0]);
305 }
306 (void) adt_free_event(event);
307 }
308 (void) adt_end_session(ah);
309
310 return (0);
311 }
312
313 static int
314 closeout_audit(int cmd, int fcn)
315 {
316 if (!adt_audit_state(AUC_AUDITING)) {
317 /* auditd not running, just return */
318 return (0);
319 }
320 switch (cmd) {
321 case A_SHUTDOWN:
322 switch (fcn) {
323 case AD_FASTREBOOT_DRYRUN:
324 /* No system discontinuity, don't turn off auditd */
325 return (0);
326 default:
327 break; /* For all the other shutdown functions */
328 }
329 /* FALLTHROUGH */
330 case A_REBOOT:
331 case A_DUMP:
332 /* system shutting down, turn off auditd */
333 return (turnoff_auditd());
334 case A_REMOUNT:
335 case A_SWAPCTL:
336 case A_FTRACE:
337 case A_CONFIG:
338 /* No system discontinuity, don't turn off auditd */
339 return (0);
340 case A_FREEZE:
341 switch (fcn) {
342 case AD_CHECK_SUSPEND_TO_DISK: /* AD_CHECK */
343 case AD_CHECK_SUSPEND_TO_RAM:
344 case AD_REUSEINIT:
345 case AD_REUSEFINI:
346 /* No system discontinuity, don't turn off auditd */
347 return (0);
348 case AD_REUSABLE:
349 case AD_SUSPEND_TO_DISK: /* AD_COMPRESS */
350 case AD_SUSPEND_TO_RAM:
351 case AD_FORCE:
352 /* suspend the system, change audit files */
353 return (change_audit_file());
354 default:
355 return (0); /* not an audit error */
356 }
357 default:
358 return (0); /* not an audit error */
359 }
360 }
361
362 static int
363 turnoff_auditd(void)
364 {
365 int rc;
366 int retries = RETRY_COUNT;
367
368 if ((rc = (int)fork()) == 0) {
369 (void) execl("/usr/sbin/audit", "audit", "-T", NULL);
370 (void) fprintf(stderr, "error disabling auditd: %s\n",
371 strerror(errno));
372 _exit(-1);
373 } else if (rc == -1) {
374 (void) fprintf(stderr, "error disabling auditd: %s\n",
375 strerror(errno));
376 return (-1);
377 }
378
379 /*
380 * wait for auditd to finish its work. auditd will change the
381 * auditstart from AUC_AUDITING (auditd up and running) to
382 * AUC_NOAUDIT. Other states are errors, so we're done as well.
383 */
384 do {
385 int auditstate;
386
387 rc = -1;
388 if ((auditon(A_GETCOND, (caddr_t)&auditstate,
389 sizeof (auditstate)) == 0) &&
390 (auditstate == AUC_AUDITING)) {
391 retries--;
392 (void) sleep(1);
393 } else {
394 rc = 0;
395 }
396 } while ((rc != 0) && (retries != 0));
397
398 return (rc);
399 }
400
401 static int
402 change_audit_file(void)
403 {
404 pid_t pid;
405
406 if ((pid = fork()) == 0) {
407 (void) execl("/usr/sbin/audit", "audit", "-n", NULL);
408 (void) fprintf(stderr, "error changing audit files: %s\n",
409 strerror(errno));
410 _exit(-1);
411 } else if (pid == -1) {
412 (void) fprintf(stderr, "error changing audit files: %s\n",
413 strerror(errno));
414 return (-1);
415 } else {
416 pid_t rc;
417 int retries = RETRY_COUNT;
418
419 /*
420 * Wait for audit(1M) -n process to complete
421 *
422 */
423 do {
424 if ((rc = waitpid(pid, NULL, WNOHANG)) == pid) {
425 return (0);
426 } else if (rc == -1) {
427 return (-1);
428 } else {
429 (void) sleep(1);
430 retries--;
431 }
432
433 } while (retries != 0);
434 }
435 return (-1);
436 }
437
438 static void
439 wait_for_auqueue()
440 {
441 au_stat_t au_stat;
442 int retries = 10;
443
444 while (retries-- && auditon(A_GETSTAT, (caddr_t)&au_stat, NULL) == 0) {
445 if (au_stat.as_enqueue == au_stat.as_written) {
446 break;
447 }
448 (void) sleep(1);
449 }
450 }