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