xref: /illumos-gate/usr/src/cmd/uadmin/uadmin.c (revision b6c3f786)
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