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