xref: /onnv-gate/usr/src/cmd/uadmin/uadmin.c (revision 6680:db68cb3d2133)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52334Ssetje  * Common Development and Distribution License (the "License").
62334Ssetje  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
226066Sgww  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
310Sstevel@tonic-gate 
326425Sgww #include <errno.h>
330Sstevel@tonic-gate #include <fcntl.h>
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <stdlib.h>
366425Sgww #include <string.h>
376425Sgww #include <strings.h>
380Sstevel@tonic-gate #include <signal.h>
396425Sgww #include <unistd.h>
406425Sgww 
415319Stz204579 #include <bsm/adt.h>
425319Stz204579 #include <bsm/adt_event.h>
436425Sgww 
44*6680Sgww #include <sys/types.h>
456425Sgww #include <sys/uadmin.h>
46*6680Sgww #include <sys/wait.h>
470Sstevel@tonic-gate 
485319Stz204579 #define	SMF_RST	"/etc/svc/volatile/resetting"
49*6680Sgww #define	RETRY_COUNT 15	/* number of 1 sec retries for audit(1M) to complete */
502334Ssetje 
510Sstevel@tonic-gate static const char *Usage = "Usage: %s cmd fcn [mdep]\n";
520Sstevel@tonic-gate 
53*6680Sgww static int closeout_audit(int, int);
54*6680Sgww static int turnoff_auditd(void);
555319Stz204579 static void wait_for_auqueue();
56*6680Sgww static int change_audit_file(void);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate int
590Sstevel@tonic-gate main(int argc, char *argv[])
600Sstevel@tonic-gate {
610Sstevel@tonic-gate 	int cmd, fcn;
620Sstevel@tonic-gate 	uintptr_t mdep = NULL;
630Sstevel@tonic-gate 	sigset_t set;
645319Stz204579 	adt_session_data_t *ah;  /* audit session handle */
655319Stz204579 	adt_event_data_t *event = NULL; /* event to be generated */
665319Stz204579 	au_event_t event_id;
675319Stz204579 	enum adt_uadmin_fcn fcn_id;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	if (argc < 3 || argc > 4) {
700Sstevel@tonic-gate 		(void) fprintf(stderr, Usage, argv[0]);
710Sstevel@tonic-gate 		return (1);
720Sstevel@tonic-gate 	}
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	(void) sigfillset(&set);
750Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &set, NULL);
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	cmd = atoi(argv[1]);
780Sstevel@tonic-gate 	fcn = atoi(argv[2]);
790Sstevel@tonic-gate 	if (argc == 4) {	/* mdep argument given */
805295Srandyf 		if (cmd != A_REBOOT && cmd != A_SHUTDOWN && cmd != A_DUMP &&
815295Srandyf 		    cmd != A_FREEZE) {
820Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: mdep argument not "
830Sstevel@tonic-gate 			    "allowed for this cmd value\n", argv[0]);
840Sstevel@tonic-gate 			(void) fprintf(stderr, Usage, argv[0]);
850Sstevel@tonic-gate 			return (1);
860Sstevel@tonic-gate 		} else {
870Sstevel@tonic-gate 			mdep = (uintptr_t)argv[3];
880Sstevel@tonic-gate 		}
890Sstevel@tonic-gate 	}
900Sstevel@tonic-gate 
915319Stz204579 	/* set up audit session and event */
925319Stz204579 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
935319Stz204579 		(void) fprintf(stderr, "%s: can't start audit session\n",
945319Stz204579 		    argv[0]);
955319Stz204579 	}
965319Stz204579 	switch (cmd) {
975319Stz204579 	case A_SHUTDOWN:
985319Stz204579 		event_id = ADT_uadmin_shutdown;
995319Stz204579 		break;
1005319Stz204579 	case A_REBOOT:
1015319Stz204579 		event_id = ADT_uadmin_reboot;
1025319Stz204579 		break;
1035319Stz204579 	case A_DUMP:
1045319Stz204579 		event_id = ADT_uadmin_dump;
1055319Stz204579 		break;
1065319Stz204579 	case A_REMOUNT:
1075319Stz204579 		event_id = ADT_uadmin_remount;
1085319Stz204579 		break;
1095319Stz204579 	case A_FREEZE:
1105319Stz204579 		event_id = ADT_uadmin_freeze;
1115319Stz204579 		break;
1125319Stz204579 	case A_FTRACE:
1135319Stz204579 		event_id = ADT_uadmin_ftrace;
1145319Stz204579 		break;
1155319Stz204579 	case A_SWAPCTL:
1165319Stz204579 		event_id = ADT_uadmin_swapctl;
1175319Stz204579 		break;
1185319Stz204579 	default:
1195319Stz204579 		event_id = 0;
1205319Stz204579 	}
1215319Stz204579 	if ((event_id != 0) &&
1225319Stz204579 	    (event = adt_alloc_event(ah, event_id)) == NULL) {
1235319Stz204579 		(void) fprintf(stderr, "%s: can't allocate audit event\n",
1245319Stz204579 		    argv[0]);
1255319Stz204579 	}
1265319Stz204579 	switch (fcn) {
1275319Stz204579 	case AD_HALT:
1285319Stz204579 		fcn_id = ADT_UADMIN_FCN_AD_HALT;
1295319Stz204579 		break;
1305319Stz204579 	case AD_POWEROFF:
1315319Stz204579 		fcn_id = ADT_UADMIN_FCN_AD_POWEROFF;
1325319Stz204579 		break;
1335319Stz204579 	case AD_BOOT:
1345319Stz204579 		fcn_id = ADT_UADMIN_FCN_AD_BOOT;
1355319Stz204579 		break;
1365319Stz204579 	case AD_IBOOT:
1375319Stz204579 		fcn_id = ADT_UADMIN_FCN_AD_IBOOT;
1385319Stz204579 		break;
1395319Stz204579 	case AD_SBOOT:
1405319Stz204579 		fcn_id = ADT_UADMIN_FCN_AD_SBOOT;
1415319Stz204579 		break;
1425319Stz204579 	case AD_SIBOOT:
1435319Stz204579 		fcn_id = ADT_UADMIN_FCN_AD_SIBOOT;
1445319Stz204579 		break;
1455319Stz204579 	case AD_NOSYNC:
1465319Stz204579 		fcn_id = ADT_UADMIN_FCN_AD_NOSYNC;
1475319Stz204579 		break;
1485319Stz204579 	default:
1495319Stz204579 		fcn_id = 0;
1505319Stz204579 	}
1515319Stz204579 	if (cmd == A_FREEZE) {
1525319Stz204579 		switch (fcn) {
1535319Stz204579 		case AD_SUSPEND_TO_DISK:
1545319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_DISK;
1555319Stz204579 			break;
1565319Stz204579 		case AD_CHECK_SUSPEND_TO_DISK:
1575319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_DISK;
1585319Stz204579 			break;
1595319Stz204579 		case AD_FORCE:
1605319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_FORCE;
1615319Stz204579 			break;
1625319Stz204579 		case AD_SUSPEND_TO_RAM:
1635319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_SUSPEND_TO_RAM;
1645319Stz204579 			break;
1655319Stz204579 		case AD_CHECK_SUSPEND_TO_RAM:
1665319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_CHECK_SUSPEND_TO_RAM;
1675319Stz204579 			break;
1685319Stz204579 		case AD_REUSEINIT:
1695319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_REUSEINIT;
1705319Stz204579 			break;
1715319Stz204579 		case AD_REUSABLE:
1725319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_REUSABLE;
1735319Stz204579 			break;
1745319Stz204579 		case AD_REUSEFINI:
1755319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_REUSEFINI;
1765319Stz204579 			break;
1775319Stz204579 		}
1785319Stz204579 	} else if (cmd == A_FTRACE) {
1795319Stz204579 		switch (fcn) {
1805319Stz204579 		case AD_FTRACE_START:
1815319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_FTRACE_START;
1825319Stz204579 			break;
1835319Stz204579 		case AD_FTRACE_STOP:
1845319Stz204579 			fcn_id = ADT_UADMIN_FCN_AD_FTRACE_STOP;
1855319Stz204579 			break;
1865319Stz204579 		}
1875319Stz204579 	}
1885319Stz204579 
1890Sstevel@tonic-gate 	if (geteuid() == 0) {
1905319Stz204579 		if (event != NULL) {
1915319Stz204579 			switch (cmd) {
1925319Stz204579 			case A_SHUTDOWN:
1935319Stz204579 				event->adt_uadmin_shutdown.fcn = fcn_id;
1945319Stz204579 				event->adt_uadmin_shutdown.mdep = (char *)mdep;
1955319Stz204579 				break;
1965319Stz204579 			case A_REBOOT:
1975319Stz204579 				event->adt_uadmin_reboot.fcn = fcn_id;
1985319Stz204579 				event->adt_uadmin_reboot.mdep = (char *)mdep;
1995319Stz204579 				break;
2005319Stz204579 			case A_DUMP:
2015319Stz204579 				event->adt_uadmin_dump.fcn = fcn_id;
2025319Stz204579 				event->adt_uadmin_dump.mdep = (char *)mdep;
2035319Stz204579 				break;
2045319Stz204579 			case A_REMOUNT:
2055319Stz204579 				/* no parameters */
2065319Stz204579 				break;
2075319Stz204579 			case A_FREEZE:
2085319Stz204579 				event->adt_uadmin_freeze.fcn = fcn_id;
2095319Stz204579 				event->adt_uadmin_freeze.mdep = (char *)mdep;
2105319Stz204579 				break;
2115319Stz204579 			case A_FTRACE:
2125319Stz204579 				event->adt_uadmin_ftrace.fcn = fcn_id;
2135319Stz204579 				break;
2145319Stz204579 			case A_SWAPCTL:
2155319Stz204579 				event->adt_uadmin_swapctl.fcn = fcn_id;
2165319Stz204579 				break;
2175319Stz204579 			}
2185319Stz204579 
2195319Stz204579 			if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
2205319Stz204579 				(void) fprintf(stderr,
2215319Stz204579 				    "%s: can't put audit event\n", argv[0]);
2225319Stz204579 			}
2235319Stz204579 			/*
2245319Stz204579 			 * allow audit record to be processed in the kernel
2255319Stz204579 			 * audit queue
2265319Stz204579 			 */
2275319Stz204579 			wait_for_auqueue();
2285319Stz204579 		}
2295319Stz204579 
230*6680Sgww 		if (closeout_audit(cmd, fcn) == -1)
2310Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: can't turn off auditd\n",
2320Sstevel@tonic-gate 			    argv[0]);
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 		if (cmd == A_SHUTDOWN || cmd == A_REBOOT)
2352334Ssetje 			(void) creat(SMF_RST, 0777);
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 
2385319Stz204579 	(void) adt_free_event(event);
2390Sstevel@tonic-gate 	if (uadmin(cmd, fcn, mdep) < 0) {
2400Sstevel@tonic-gate 		perror("uadmin");
2410Sstevel@tonic-gate 
2422334Ssetje 		(void) unlink(SMF_RST);
2432334Ssetje 
2440Sstevel@tonic-gate 		return (1);
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 
247*6680Sgww 	/* If returning from a suspend, audit thaw */
248*6680Sgww 	if ((cmd == A_FREEZE) &&
249*6680Sgww 	    ((fcn == AD_FORCE) ||
250*6680Sgww 	    (fcn == AD_REUSABLE) ||
251*6680Sgww 	    (fcn == AD_SUSPEND_TO_DISK) ||
252*6680Sgww 	    (fcn == AD_SUSPEND_TO_RAM))) {
253*6680Sgww 		if ((event = adt_alloc_event(ah, ADT_uadmin_thaw)) == NULL) {
254*6680Sgww 			(void) fprintf(stderr, "%s: can't allocate thaw audit "
255*6680Sgww 			    "event\n", argv[0]);
256*6680Sgww 		}
257*6680Sgww 		event->adt_uadmin_thaw.fcn = fcn_id;
258*6680Sgww 		if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
259*6680Sgww 			(void) fprintf(stderr, "%s: can't put thaw audit "
260*6680Sgww 			    "event\n", argv[0]);
261*6680Sgww 		}
262*6680Sgww 		(void) adt_free_event(event);
263*6680Sgww 	}
264*6680Sgww 	(void) adt_end_session(ah);
265*6680Sgww 
2660Sstevel@tonic-gate 	return (0);
2670Sstevel@tonic-gate }
2685319Stz204579 
2695319Stz204579 static int
270*6680Sgww closeout_audit(int cmd, int fcn)
2715319Stz204579 {
272*6680Sgww 	if (!adt_audit_state(AUC_AUDITING)) {
273*6680Sgww 		/* auditd not running, just return */
274*6680Sgww 		return (0);
275*6680Sgww 	}
2766066Sgww 	switch (cmd) {
2776066Sgww 	case A_SHUTDOWN:
2786066Sgww 	case A_REBOOT:
2796066Sgww 	case A_DUMP:
2806066Sgww 		/* system shutting down, turn off auditd */
281*6680Sgww 		return (turnoff_auditd());
2826066Sgww 	case A_REMOUNT:
2836066Sgww 	case A_SWAPCTL:
2846066Sgww 	case A_FTRACE:
2856066Sgww 		/* No system discontinuity, don't turn off auditd */
2866066Sgww 		return (0);
2876066Sgww 	case A_FREEZE:
2886066Sgww 		switch (fcn) {
2896066Sgww 		case AD_CHECK_SUSPEND_TO_DISK:	/* AD_CHECK */
2906066Sgww 		case AD_CHECK_SUSPEND_TO_RAM:
2916066Sgww 		case AD_REUSEINIT:
2926066Sgww 		case AD_REUSEFINI:
2936066Sgww 			/* No system discontinuity, don't turn off auditd */
2946066Sgww 			return (0);
2956066Sgww 		case AD_REUSABLE:
2966066Sgww 		case AD_SUSPEND_TO_DISK:	/* AD_COMPRESS */
2976066Sgww 		case AD_SUSPEND_TO_RAM:
2986066Sgww 		case AD_FORCE:
2996066Sgww 			/* suspend the system, change audit files */
300*6680Sgww 			return (change_audit_file());
3016066Sgww 		default:
302*6680Sgww 			return (0);	/* not an audit error */
3036066Sgww 		}
3046066Sgww 	default:
305*6680Sgww 		return (0);	/* not an audit error */
3066066Sgww 	}
307*6680Sgww }
308*6680Sgww 
309*6680Sgww static int
310*6680Sgww turnoff_auditd(void)
311*6680Sgww {
312*6680Sgww 	int	rc;
313*6680Sgww 	int	retries = RETRY_COUNT;
3146066Sgww 
315*6680Sgww 	if ((rc = (int)fork()) == 0) {
316*6680Sgww 		(void) execl("/usr/sbin/audit", "audit", "-t", NULL);
317*6680Sgww 		(void) fprintf(stderr, "error disabling auditd: %s\n",
318*6680Sgww 		    strerror(errno));
319*6680Sgww 		_exit(-1);
320*6680Sgww 	} else if (rc == -1) {
321*6680Sgww 		(void) fprintf(stderr, "error disabling auditd: %s\n",
322*6680Sgww 		    strerror(errno));
323*6680Sgww 		return (-1);
3245319Stz204579 	}
3255319Stz204579 
3266425Sgww 	/*
3276425Sgww 	 * wait for auditd to finish its work.  auditd will change the
3286425Sgww 	 * auditstart from AUC_AUDITING (auditd up and running) to
3296425Sgww 	 * AUC_NOAUDIT.  Other states are errors, so we're done as well.
3306425Sgww 	 */
3315319Stz204579 	do {
3326425Sgww 		int	auditstate;
3335319Stz204579 
3346425Sgww 		rc = -1;
3356425Sgww 		if ((auditon(A_GETCOND, (caddr_t)&auditstate,
3366425Sgww 		    sizeof (auditstate)) == 0) &&
3376425Sgww 		    (auditstate == AUC_AUDITING)) {
3385319Stz204579 			retries--;
3395319Stz204579 			(void) sleep(1);
3405319Stz204579 		} else {
3415319Stz204579 			rc = 0;
3425319Stz204579 		}
3436425Sgww 	} while ((rc != 0) && (retries != 0));
3445319Stz204579 
3455319Stz204579 	return (rc);
3465319Stz204579 }
3475319Stz204579 
348*6680Sgww static int
349*6680Sgww change_audit_file(void)
350*6680Sgww {
351*6680Sgww 	pid_t	pid;
352*6680Sgww 
353*6680Sgww 	if ((pid = fork()) == 0) {
354*6680Sgww 		(void) execl("/usr/sbin/audit", "audit", "-n", NULL);
355*6680Sgww 		(void) fprintf(stderr, "error changing audit files: %s\n",
356*6680Sgww 		    strerror(errno));
357*6680Sgww 		_exit(-1);
358*6680Sgww 	} else if (pid == -1) {
359*6680Sgww 		(void) fprintf(stderr, "error changing audit files: %s\n",
360*6680Sgww 		    strerror(errno));
361*6680Sgww 		return (-1);
362*6680Sgww 	} else {
363*6680Sgww 		pid_t	rc;
364*6680Sgww 		int	retries = RETRY_COUNT;
365*6680Sgww 
366*6680Sgww 		/*
367*6680Sgww 		 * Wait for audit(1M) -n process to complete
368*6680Sgww 		 *
369*6680Sgww 		 */
370*6680Sgww 		do {
371*6680Sgww 			if ((rc = waitpid(pid, NULL, WNOHANG)) == pid) {
372*6680Sgww 				return (0);
373*6680Sgww 			} else if (rc == -1) {
374*6680Sgww 				return (-1);
375*6680Sgww 			} else {
376*6680Sgww 				(void) sleep(1);
377*6680Sgww 				retries--;
378*6680Sgww 			}
379*6680Sgww 
380*6680Sgww 		} while (retries != 0);
381*6680Sgww 	}
382*6680Sgww 	return (-1);
383*6680Sgww }
384*6680Sgww 
3855319Stz204579 static void
3865319Stz204579 wait_for_auqueue()
3875319Stz204579 {
3885319Stz204579 	au_stat_t	au_stat;
3895319Stz204579 	int		retries = 10;
3905319Stz204579 
3915319Stz204579 	while (retries-- && auditon(A_GETSTAT, (caddr_t)&au_stat, NULL) == 0) {
3925319Stz204579 		if (au_stat.as_enqueue == au_stat.as_written) {
3935319Stz204579 			break;
3945319Stz204579 		}
3955319Stz204579 		(void) sleep(1);
3965319Stz204579 	}
3975319Stz204579 }
398