18940SRandy.Fishel@Sun.COM /* 28940SRandy.Fishel@Sun.COM * CDDL HEADER START 38940SRandy.Fishel@Sun.COM * 48940SRandy.Fishel@Sun.COM * The contents of this file are subject to the terms of the 58940SRandy.Fishel@Sun.COM * Common Development and Distribution License (the "License"). 68940SRandy.Fishel@Sun.COM * You may not use this file except in compliance with the License. 78940SRandy.Fishel@Sun.COM * 88940SRandy.Fishel@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98940SRandy.Fishel@Sun.COM * or http://www.opensolaris.org/os/licensing. 108940SRandy.Fishel@Sun.COM * See the License for the specific language governing permissions 118940SRandy.Fishel@Sun.COM * and limitations under the License. 128940SRandy.Fishel@Sun.COM * 138940SRandy.Fishel@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 148940SRandy.Fishel@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158940SRandy.Fishel@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 168940SRandy.Fishel@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 178940SRandy.Fishel@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 188940SRandy.Fishel@Sun.COM * 198940SRandy.Fishel@Sun.COM * CDDL HEADER END 208940SRandy.Fishel@Sun.COM */ 218940SRandy.Fishel@Sun.COM /* 228940SRandy.Fishel@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 238940SRandy.Fishel@Sun.COM * Use is subject to license terms. 248940SRandy.Fishel@Sun.COM */ 258940SRandy.Fishel@Sun.COM 268940SRandy.Fishel@Sun.COM /* 278940SRandy.Fishel@Sun.COM * This code has a lot in common with the original sys-suspend 288940SRandy.Fishel@Sun.COM * code. Windowing facilities have been removed, and it has been 298940SRandy.Fishel@Sun.COM * updated to use more recent API's. 308940SRandy.Fishel@Sun.COM */ 318940SRandy.Fishel@Sun.COM #include <stdio.h> 328940SRandy.Fishel@Sun.COM #include <fcntl.h> 338940SRandy.Fishel@Sun.COM #include <stdlib.h> 348940SRandy.Fishel@Sun.COM #include <string.h> 358940SRandy.Fishel@Sun.COM #include <strings.h> 368940SRandy.Fishel@Sun.COM #include <unistd.h> 378940SRandy.Fishel@Sun.COM #include <libintl.h> 388940SRandy.Fishel@Sun.COM #include <locale.h> 398940SRandy.Fishel@Sun.COM #include <utility.h> 408940SRandy.Fishel@Sun.COM #include <signal.h> 418940SRandy.Fishel@Sun.COM #include <errno.h> 428940SRandy.Fishel@Sun.COM #include <setjmp.h> 438940SRandy.Fishel@Sun.COM #include <pwd.h> 448940SRandy.Fishel@Sun.COM #include <syslog.h> 458940SRandy.Fishel@Sun.COM #include <sys/types.h> 468940SRandy.Fishel@Sun.COM #include <sys/param.h> 478940SRandy.Fishel@Sun.COM #include <sys/utsname.h> 488940SRandy.Fishel@Sun.COM #include <sys/uadmin.h> 498940SRandy.Fishel@Sun.COM #include <auth_attr.h> 508940SRandy.Fishel@Sun.COM #include <auth_list.h> 518940SRandy.Fishel@Sun.COM #include <secdb.h> 528940SRandy.Fishel@Sun.COM #include <security/pam_appl.h> 538940SRandy.Fishel@Sun.COM #include <utmpx.h> 548940SRandy.Fishel@Sun.COM 558940SRandy.Fishel@Sun.COM /* For audit */ 568940SRandy.Fishel@Sun.COM #include <bsm/adt.h> 578940SRandy.Fishel@Sun.COM #include <bsm/adt_event.h> 588940SRandy.Fishel@Sun.COM 598940SRandy.Fishel@Sun.COM #include <sys/wait.h> 608940SRandy.Fishel@Sun.COM #include <sys/stat.h> 618940SRandy.Fishel@Sun.COM #include <sys/pm.h> 628940SRandy.Fishel@Sun.COM #include <dirent.h> 638940SRandy.Fishel@Sun.COM #include <sys/cpr.h> 648940SRandy.Fishel@Sun.COM 658940SRandy.Fishel@Sun.COM /* STATICUSED */ 668940SRandy.Fishel@Sun.COM struct utmpx utmp; 678940SRandy.Fishel@Sun.COM #define NMAX (sizeof (utmp.ut_name)) 688940SRandy.Fishel@Sun.COM 698940SRandy.Fishel@Sun.COM /* 708940SRandy.Fishel@Sun.COM * Authorizations used by Power Management 718940SRandy.Fishel@Sun.COM */ 728940SRandy.Fishel@Sun.COM #define AUTHNAME_SHUTDOWN "solaris.system.shutdown" 738940SRandy.Fishel@Sun.COM #define AUTHNAME_SUSPEND_RAM "solaris.system.power.suspend.ram" 748940SRandy.Fishel@Sun.COM #define AUTHNAME_SUSPEND_DISK "solaris.system.power.suspend.disk" 758940SRandy.Fishel@Sun.COM 768940SRandy.Fishel@Sun.COM /* Platform specific definitions */ 778940SRandy.Fishel@Sun.COM #ifdef i386 788940SRandy.Fishel@Sun.COM #define AD_CHECK_SUSPEND AD_CHECK_SUSPEND_TO_RAM 798940SRandy.Fishel@Sun.COM #define AD_SUSPEND AD_SUSPEND_TO_RAM 808940SRandy.Fishel@Sun.COM #define ADT_FCN ADT_UADMIN_FCN_AD_SUSPEND_TO_RAM 818940SRandy.Fishel@Sun.COM #define AUTHNAME_SUSPEND AUTHNAME_SUSPEND_RAM 828940SRandy.Fishel@Sun.COM #else 838940SRandy.Fishel@Sun.COM #define AD_CHECK_SUSPEND AD_CHECK_SUSPEND_TO_DISK 848940SRandy.Fishel@Sun.COM #define AD_SUSPEND AD_SUSPEND_TO_DISK 858940SRandy.Fishel@Sun.COM #define ADT_FCN ADT_UADMIN_FCN_AD_SUSPEND_TO_DISK 868940SRandy.Fishel@Sun.COM #define AUTHNAME_SUSPEND AUTHNAME_SUSPEND_DISK 878940SRandy.Fishel@Sun.COM #endif 888940SRandy.Fishel@Sun.COM 898940SRandy.Fishel@Sun.COM static int flags = 0; 908940SRandy.Fishel@Sun.COM static int no_tty = 0; 918940SRandy.Fishel@Sun.COM /* 928940SRandy.Fishel@Sun.COM * Flag definitions - could go in a header file, but there are just a few 938940SRandy.Fishel@Sun.COM */ 948940SRandy.Fishel@Sun.COM #define FORCE 0x001 958940SRandy.Fishel@Sun.COM #define NO_WARN 0x002 968940SRandy.Fishel@Sun.COM #define NO_XLOCK 0x004 978940SRandy.Fishel@Sun.COM #define SHUTDOWN 0x008 988940SRandy.Fishel@Sun.COM #define LOWPOWER 0x010 998940SRandy.Fishel@Sun.COM #define TEST 0x800 1008940SRandy.Fishel@Sun.COM 1018940SRandy.Fishel@Sun.COM static sigjmp_buf jmp_stack; 1028940SRandy.Fishel@Sun.COM static char user[NMAX + 1]; 1038940SRandy.Fishel@Sun.COM static char **argvl; 1048940SRandy.Fishel@Sun.COM 1058940SRandy.Fishel@Sun.COM 1068940SRandy.Fishel@Sun.COM 1078940SRandy.Fishel@Sun.COM /* 1088940SRandy.Fishel@Sun.COM * Forward Declarations. 1098940SRandy.Fishel@Sun.COM */ 1108940SRandy.Fishel@Sun.COM static void pm_poweroff(void); 1118940SRandy.Fishel@Sun.COM static int bringto_lowpower(void); 1128940SRandy.Fishel@Sun.COM static int is_mou3(void); 1138940SRandy.Fishel@Sun.COM static void suspend_error(int); 1148940SRandy.Fishel@Sun.COM static int pm_check_suspend(void); 1158940SRandy.Fishel@Sun.COM static void pm_suspend(void); 1168940SRandy.Fishel@Sun.COM static void pm_do_auth(adt_session_data_t *); 1178940SRandy.Fishel@Sun.COM 1188940SRandy.Fishel@Sun.COM /* 1198940SRandy.Fishel@Sun.COM * External Declarations. 1208940SRandy.Fishel@Sun.COM */ 1218940SRandy.Fishel@Sun.COM extern int pam_tty_conv(int, struct pam_message **, 1228940SRandy.Fishel@Sun.COM struct pam_response **, void *); 1238940SRandy.Fishel@Sun.COM extern char *optarg; 1248940SRandy.Fishel@Sun.COM 1258940SRandy.Fishel@Sun.COM /* 1268940SRandy.Fishel@Sun.COM * Audit related code. I would also think that some of this could be 1278940SRandy.Fishel@Sun.COM * in external code, as they could be useful of other apps. 1288940SRandy.Fishel@Sun.COM */ 1298940SRandy.Fishel@Sun.COM /* 1308940SRandy.Fishel@Sun.COM * Write audit event. Could be useful in the PM library, so it is 1318940SRandy.Fishel@Sun.COM * included here. For the most part it is only used by the PAM code. 1328940SRandy.Fishel@Sun.COM */ 1338940SRandy.Fishel@Sun.COM static void 1348940SRandy.Fishel@Sun.COM pm_audit_event(adt_session_data_t *ah, au_event_t event_id, int status) 1358940SRandy.Fishel@Sun.COM { 1368940SRandy.Fishel@Sun.COM adt_event_data_t *event; 1378940SRandy.Fishel@Sun.COM 1388940SRandy.Fishel@Sun.COM 1398940SRandy.Fishel@Sun.COM if ((event = adt_alloc_event(ah, event_id)) == NULL) { 1408940SRandy.Fishel@Sun.COM return; 1418940SRandy.Fishel@Sun.COM } 1428940SRandy.Fishel@Sun.COM 1438940SRandy.Fishel@Sun.COM (void) adt_put_event(event, 1448940SRandy.Fishel@Sun.COM status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE, 1458940SRandy.Fishel@Sun.COM status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM + status); 1468940SRandy.Fishel@Sun.COM 1478940SRandy.Fishel@Sun.COM adt_free_event(event); 1488940SRandy.Fishel@Sun.COM } 1498940SRandy.Fishel@Sun.COM 1508940SRandy.Fishel@Sun.COM #define RETRY_COUNT 15 1518940SRandy.Fishel@Sun.COM static int 1528940SRandy.Fishel@Sun.COM change_audit_file(void) 1538940SRandy.Fishel@Sun.COM { 1548940SRandy.Fishel@Sun.COM pid_t pid; 1558940SRandy.Fishel@Sun.COM 1568940SRandy.Fishel@Sun.COM if (!adt_audit_state(AUC_AUDITING)) { 1578940SRandy.Fishel@Sun.COM /* auditd not running, just return */ 1588940SRandy.Fishel@Sun.COM return (0); 1598940SRandy.Fishel@Sun.COM } 1608940SRandy.Fishel@Sun.COM 1618940SRandy.Fishel@Sun.COM if ((pid = fork()) == 0) { 1628940SRandy.Fishel@Sun.COM (void) execl("/usr/sbin/audit", "audit", "-n", NULL); 1638940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext("error changing audit files: " 1648940SRandy.Fishel@Sun.COM "%s\n"), strerror(errno)); 1658940SRandy.Fishel@Sun.COM _exit(-1); 1668940SRandy.Fishel@Sun.COM } else if (pid == -1) { 1678940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext("error changing audit files: " 1688940SRandy.Fishel@Sun.COM "%s\n"), strerror(errno)); 1698940SRandy.Fishel@Sun.COM return (-1); 1708940SRandy.Fishel@Sun.COM } else { 1718940SRandy.Fishel@Sun.COM pid_t rc; 1728940SRandy.Fishel@Sun.COM int retries = RETRY_COUNT; 1738940SRandy.Fishel@Sun.COM 1748940SRandy.Fishel@Sun.COM /* 1758940SRandy.Fishel@Sun.COM * Wait for audit(1M) -n process to complete 1768940SRandy.Fishel@Sun.COM * 1778940SRandy.Fishel@Sun.COM */ 1788940SRandy.Fishel@Sun.COM do { 1798940SRandy.Fishel@Sun.COM if ((rc = waitpid(pid, NULL, WNOHANG)) == pid) { 1808940SRandy.Fishel@Sun.COM return (0); 1818940SRandy.Fishel@Sun.COM } else if (rc == -1) { 1828940SRandy.Fishel@Sun.COM return (-1); 1838940SRandy.Fishel@Sun.COM } else { 1848940SRandy.Fishel@Sun.COM (void) sleep(1); 1858940SRandy.Fishel@Sun.COM retries--; 1868940SRandy.Fishel@Sun.COM } 1878940SRandy.Fishel@Sun.COM 1888940SRandy.Fishel@Sun.COM } while (retries != 0); 1898940SRandy.Fishel@Sun.COM } 1908940SRandy.Fishel@Sun.COM return (-1); 1918940SRandy.Fishel@Sun.COM } 1928940SRandy.Fishel@Sun.COM 1938940SRandy.Fishel@Sun.COM static void 1948940SRandy.Fishel@Sun.COM wait_for_auqueue() 1958940SRandy.Fishel@Sun.COM { 1968940SRandy.Fishel@Sun.COM au_stat_t au_stat; 1978940SRandy.Fishel@Sun.COM int retries = 10; 1988940SRandy.Fishel@Sun.COM 1998940SRandy.Fishel@Sun.COM while (retries-- && auditon(A_GETSTAT, (caddr_t)&au_stat, NULL) == 0) { 2008940SRandy.Fishel@Sun.COM if (au_stat.as_enqueue == au_stat.as_written) { 2018940SRandy.Fishel@Sun.COM break; 2028940SRandy.Fishel@Sun.COM } 2038940SRandy.Fishel@Sun.COM (void) sleep(1); 2048940SRandy.Fishel@Sun.COM } 2058940SRandy.Fishel@Sun.COM } 2068940SRandy.Fishel@Sun.COM 2078940SRandy.Fishel@Sun.COM /* End of Audit-related code */ 2088940SRandy.Fishel@Sun.COM 2098940SRandy.Fishel@Sun.COM /* ARGSUSED0 */ 2108940SRandy.Fishel@Sun.COM static void 2118940SRandy.Fishel@Sun.COM alarm_handler(int sig) 2128940SRandy.Fishel@Sun.COM { 2138940SRandy.Fishel@Sun.COM siglongjmp(jmp_stack, 1); 2148940SRandy.Fishel@Sun.COM } 2158940SRandy.Fishel@Sun.COM 2168940SRandy.Fishel@Sun.COM /* 2178940SRandy.Fishel@Sun.COM * These are functions that would be candidates for moving to a library. 2188940SRandy.Fishel@Sun.COM */ 2198940SRandy.Fishel@Sun.COM 2208940SRandy.Fishel@Sun.COM /* 2218940SRandy.Fishel@Sun.COM * pm_poweroff - similar to poweroff(1M) 2228940SRandy.Fishel@Sun.COM * This should do the same auditing as poweroff(1m) would do when it 2238940SRandy.Fishel@Sun.COM * becomes a libpower function. Till then we use poweroff(1m). 2248940SRandy.Fishel@Sun.COM */ 2258940SRandy.Fishel@Sun.COM static void 2268940SRandy.Fishel@Sun.COM pm_poweroff(void) 2278940SRandy.Fishel@Sun.COM { 2288940SRandy.Fishel@Sun.COM if (chkauthattr(AUTHNAME_SHUTDOWN, user) != 1) { 2298940SRandy.Fishel@Sun.COM (void) printf(gettext("User %s does not have correct " 2308940SRandy.Fishel@Sun.COM "authorizations to shutdown this machine.\n"), user); 2318940SRandy.Fishel@Sun.COM exit(1); 2328940SRandy.Fishel@Sun.COM } 2338940SRandy.Fishel@Sun.COM openlog("suspend", 0, LOG_DAEMON); 2348940SRandy.Fishel@Sun.COM syslog(LOG_NOTICE, "System is being shut down."); 2358940SRandy.Fishel@Sun.COM closelog(); 2368940SRandy.Fishel@Sun.COM 2378940SRandy.Fishel@Sun.COM /* 2388940SRandy.Fishel@Sun.COM * Call poweroff(1m) to shut down the system. 2398940SRandy.Fishel@Sun.COM */ 2408940SRandy.Fishel@Sun.COM (void) execl("/usr/sbin/poweroff", "poweroff", NULL); 2418940SRandy.Fishel@Sun.COM 2428940SRandy.Fishel@Sun.COM } 2438940SRandy.Fishel@Sun.COM 2448940SRandy.Fishel@Sun.COM /* 2458940SRandy.Fishel@Sun.COM * pm_check_suspend() - Check to see if suspend is supported/enabled 2468940SRandy.Fishel@Sun.COM * on this machine. 2478940SRandy.Fishel@Sun.COM * Ultimately, we would prefer to get the "default" suspend type from 2488940SRandy.Fishel@Sun.COM * a PM property or some other API, but for now, we know that STR is 2498940SRandy.Fishel@Sun.COM * only available on x86 and STD is only available on Sparc. It does 2508940SRandy.Fishel@Sun.COM * make this function quite easy, though. 2518940SRandy.Fishel@Sun.COM */ 2528940SRandy.Fishel@Sun.COM static int 2538940SRandy.Fishel@Sun.COM pm_check_suspend(void) { 2548940SRandy.Fishel@Sun.COM /* 2558940SRandy.Fishel@Sun.COM * Use the uadmin(2) "CHECK" command to see if suspend is supported 2568940SRandy.Fishel@Sun.COM */ 2578940SRandy.Fishel@Sun.COM return (uadmin(A_FREEZE, AD_CHECK_SUSPEND, 0)); 2588940SRandy.Fishel@Sun.COM } 2598940SRandy.Fishel@Sun.COM 2608940SRandy.Fishel@Sun.COM /* 2618940SRandy.Fishel@Sun.COM * This entry point _should_ be the common entry to suspend. It is in 2628940SRandy.Fishel@Sun.COM * it's entirety here, but would be best moved to libpower when that 2638940SRandy.Fishel@Sun.COM * is available. 2648940SRandy.Fishel@Sun.COM */ 2658940SRandy.Fishel@Sun.COM static void 2668940SRandy.Fishel@Sun.COM pm_suspend(void) 2678940SRandy.Fishel@Sun.COM { 2688940SRandy.Fishel@Sun.COM int cprarg = AD_SUSPEND; 2698940SRandy.Fishel@Sun.COM enum adt_uadmin_fcn fcn_id = ADT_FCN; 2708940SRandy.Fishel@Sun.COM au_event_t event_id = ADT_uadmin_freeze; 2718940SRandy.Fishel@Sun.COM adt_event_data_t *event = NULL; /* event to be generated */ 2728940SRandy.Fishel@Sun.COM adt_session_data_t *ah = NULL; /* audit session handle */ 2738940SRandy.Fishel@Sun.COM 2748940SRandy.Fishel@Sun.COM /* 2758940SRandy.Fishel@Sun.COM * Does the user have permission to use this command? 2768940SRandy.Fishel@Sun.COM */ 2778940SRandy.Fishel@Sun.COM if (chkauthattr(AUTHNAME_SUSPEND, user) != 1) { 2788940SRandy.Fishel@Sun.COM (void) printf(gettext("User %s does not have correct " 2798940SRandy.Fishel@Sun.COM "authorizations to suspend this machine.\n"), user); 2808940SRandy.Fishel@Sun.COM exit(1); 2818940SRandy.Fishel@Sun.COM } 2828940SRandy.Fishel@Sun.COM 2838940SRandy.Fishel@Sun.COM if (flags & LOWPOWER) { 2848940SRandy.Fishel@Sun.COM if (bringto_lowpower() == -1) { 2858940SRandy.Fishel@Sun.COM (void) printf(gettext("LowPower Failed\n")); 2868940SRandy.Fishel@Sun.COM exit(1); 2878940SRandy.Fishel@Sun.COM } 2888940SRandy.Fishel@Sun.COM } else if (flags & TEST) { 2898940SRandy.Fishel@Sun.COM /* 2908940SRandy.Fishel@Sun.COM * Test mode, do checks as if a real suspend, but 2918940SRandy.Fishel@Sun.COM * don't actually do the suspend. 2928940SRandy.Fishel@Sun.COM */ 2938940SRandy.Fishel@Sun.COM /* Check if suspend is supported */ 2948940SRandy.Fishel@Sun.COM if (pm_check_suspend() == -1) { 2958940SRandy.Fishel@Sun.COM suspend_error(errno); 2968940SRandy.Fishel@Sun.COM } 2978940SRandy.Fishel@Sun.COM 2988940SRandy.Fishel@Sun.COM (void) printf(gettext("TEST: Suspend would have been" 2998940SRandy.Fishel@Sun.COM " performed\n")); 3008940SRandy.Fishel@Sun.COM 3018940SRandy.Fishel@Sun.COM } else { 3028940SRandy.Fishel@Sun.COM /* Check if suspend is supported */ 3038940SRandy.Fishel@Sun.COM if (pm_check_suspend() == -1) { 3048940SRandy.Fishel@Sun.COM suspend_error(errno); 3058940SRandy.Fishel@Sun.COM } 3068940SRandy.Fishel@Sun.COM 3078940SRandy.Fishel@Sun.COM /* 3088940SRandy.Fishel@Sun.COM * We are about to suspend this machine, try and 3098940SRandy.Fishel@Sun.COM * lock the screen. We don't really care if this 3108940SRandy.Fishel@Sun.COM * succeeds or not, but that we actually tried. We 3118940SRandy.Fishel@Sun.COM * also know that we have sufficient privileges to 3128940SRandy.Fishel@Sun.COM * be here, so we lock the screen now, even if 3138940SRandy.Fishel@Sun.COM * suspend actually fails. 3148940SRandy.Fishel@Sun.COM * Note that garbage is sometimes displayed, and 3158940SRandy.Fishel@Sun.COM * we don't really care about it, so we toss all 3168940SRandy.Fishel@Sun.COM * text response. 3178940SRandy.Fishel@Sun.COM * it would also be good if there were another option 3188940SRandy.Fishel@Sun.COM * instead of launcing a file, as the disk might be 3198940SRandy.Fishel@Sun.COM * spun down if we are suspending due to idle. 3208940SRandy.Fishel@Sun.COM */ 3218940SRandy.Fishel@Sun.COM if (!(flags & NO_XLOCK)) { 3228940SRandy.Fishel@Sun.COM (void) system("/usr/bin/xdg-screensaver lock " 3238940SRandy.Fishel@Sun.COM " >/dev/null 2>&1"); 3248940SRandy.Fishel@Sun.COM } 3258940SRandy.Fishel@Sun.COM 3268940SRandy.Fishel@Sun.COM /* Time to do the actual deed! */ 3278940SRandy.Fishel@Sun.COM /* 3288940SRandy.Fishel@Sun.COM * Before we actually suspend, we need to audit and 3298940SRandy.Fishel@Sun.COM * "suspend" the audit files. 3308940SRandy.Fishel@Sun.COM */ 3318940SRandy.Fishel@Sun.COM /* set up audit session and event */ 3328940SRandy.Fishel@Sun.COM if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) == 0) { 3338940SRandy.Fishel@Sun.COM if ((event = adt_alloc_event(ah, event_id)) != NULL) { 3348940SRandy.Fishel@Sun.COM event->adt_uadmin_freeze.fcn = fcn_id; 3358940SRandy.Fishel@Sun.COM event->adt_uadmin_freeze.mdep = NULL; 3368940SRandy.Fishel@Sun.COM if (adt_put_event(event, ADT_SUCCESS, 0) != 0) { 3378940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext( 3388940SRandy.Fishel@Sun.COM "%s: can't put audit event\n"), 3398940SRandy.Fishel@Sun.COM argvl[0]); 3408940SRandy.Fishel@Sun.COM } else { 3418940SRandy.Fishel@Sun.COM wait_for_auqueue(); 3428940SRandy.Fishel@Sun.COM } 3438940SRandy.Fishel@Sun.COM } 3448940SRandy.Fishel@Sun.COM (void) change_audit_file(); 3458940SRandy.Fishel@Sun.COM } else { 3468940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext( 3478940SRandy.Fishel@Sun.COM "%s: can't start audit session\n"), argvl[0]); 3488940SRandy.Fishel@Sun.COM } 3498940SRandy.Fishel@Sun.COM 3508940SRandy.Fishel@Sun.COM if (uadmin(A_FREEZE, cprarg, 0) != 0) { 3518940SRandy.Fishel@Sun.COM (void) printf(gettext("Suspend Failed\n")); 3528940SRandy.Fishel@Sun.COM if (flags & FORCE) { 3538940SRandy.Fishel@Sun.COM /* 3548940SRandy.Fishel@Sun.COM * Note, that if we actually poweroff, 3558940SRandy.Fishel@Sun.COM * that the poweroff function will handle 3568940SRandy.Fishel@Sun.COM * that audit trail, and the resume 3578940SRandy.Fishel@Sun.COM * trail is effectively done. 3588940SRandy.Fishel@Sun.COM */ 3598940SRandy.Fishel@Sun.COM pm_poweroff(); 3608940SRandy.Fishel@Sun.COM } else { 3618940SRandy.Fishel@Sun.COM /* suspend_error() will exit. */ 3628940SRandy.Fishel@Sun.COM suspend_error(errno); 3638940SRandy.Fishel@Sun.COM /* 3648940SRandy.Fishel@Sun.COM * Audit the suspend failure and 3658940SRandy.Fishel@Sun.COM * reuse the event, but don't create one 3668940SRandy.Fishel@Sun.COM * if we don't already have one. 3678940SRandy.Fishel@Sun.COM */ 3688940SRandy.Fishel@Sun.COM if (event != NULL) { 369*11053SSurya.Prakki@Sun.COM (void) adt_put_event(event, 370*11053SSurya.Prakki@Sun.COM ADT_FAILURE, 0); 3718940SRandy.Fishel@Sun.COM } 3728940SRandy.Fishel@Sun.COM } 3738940SRandy.Fishel@Sun.COM } 3748940SRandy.Fishel@Sun.COM 3758940SRandy.Fishel@Sun.COM /* 3768940SRandy.Fishel@Sun.COM * Write the thaw event. 3778940SRandy.Fishel@Sun.COM */ 3788940SRandy.Fishel@Sun.COM if (ah != NULL) { 3798940SRandy.Fishel@Sun.COM if ((event == NULL) && 3808940SRandy.Fishel@Sun.COM ((event = adt_alloc_event(ah, ADT_uadmin_thaw)) 3818940SRandy.Fishel@Sun.COM == NULL)) { 3828940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext( 3838940SRandy.Fishel@Sun.COM "%s: can't allocate thaw audit event\n"), 3848940SRandy.Fishel@Sun.COM argvl[0]); 3858940SRandy.Fishel@Sun.COM } else { 3868940SRandy.Fishel@Sun.COM event->adt_uadmin_thaw.fcn = fcn_id; 3878940SRandy.Fishel@Sun.COM if (adt_put_event(event, ADT_SUCCESS, 0) != 0) { 3888940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext( 3898940SRandy.Fishel@Sun.COM "%s: can't put thaw audit event\n"), 3908940SRandy.Fishel@Sun.COM argvl[0]); 3918940SRandy.Fishel@Sun.COM } 3928940SRandy.Fishel@Sun.COM (void) adt_free_event(event); 3938940SRandy.Fishel@Sun.COM } 3948940SRandy.Fishel@Sun.COM } 3958940SRandy.Fishel@Sun.COM } 3968940SRandy.Fishel@Sun.COM if ((no_tty ? 0 : 1) && !(flags & NO_XLOCK)) { 3978940SRandy.Fishel@Sun.COM pm_do_auth(ah); 3988940SRandy.Fishel@Sun.COM } 3998940SRandy.Fishel@Sun.COM 4008940SRandy.Fishel@Sun.COM (void) adt_end_session(ah); 4018940SRandy.Fishel@Sun.COM } 4028940SRandy.Fishel@Sun.COM /* End of "library" functions */ 4038940SRandy.Fishel@Sun.COM 4048940SRandy.Fishel@Sun.COM /* 4058940SRandy.Fishel@Sun.COM * Print an appropriate error message and exit. 4068940SRandy.Fishel@Sun.COM */ 4078940SRandy.Fishel@Sun.COM 4088940SRandy.Fishel@Sun.COM static void 4098940SRandy.Fishel@Sun.COM suspend_error(int error) { 4108940SRandy.Fishel@Sun.COM 4118940SRandy.Fishel@Sun.COM switch (error) { 4128940SRandy.Fishel@Sun.COM case EBUSY: 4138940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 4148940SRandy.Fishel@Sun.COM "Suspend already in progress.\n\n")); 4158940SRandy.Fishel@Sun.COM exit(1); 4168940SRandy.Fishel@Sun.COM /*NOTREACHED*/ 4178940SRandy.Fishel@Sun.COM case ENOMEM: 4188940SRandy.Fishel@Sun.COM /*FALLTHROUGH*/ 4198940SRandy.Fishel@Sun.COM case ENOSPC: 4208940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 4218940SRandy.Fishel@Sun.COM "Not enough resources to suspend.\n\n")); 4228940SRandy.Fishel@Sun.COM exit(1); 4238940SRandy.Fishel@Sun.COM /*NOTREACHED*/ 4248940SRandy.Fishel@Sun.COM case ENOTSUP: 4258940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 4268940SRandy.Fishel@Sun.COM "Suspend is not supported.\n\n")); 4278940SRandy.Fishel@Sun.COM exit(1); 4288940SRandy.Fishel@Sun.COM /*NOTREACHED*/ 4298940SRandy.Fishel@Sun.COM case EPERM: 4308940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 4318940SRandy.Fishel@Sun.COM "Not sufficient privileges.\n\n")); 4328940SRandy.Fishel@Sun.COM exit(1); 4338940SRandy.Fishel@Sun.COM /*NOTREACHED*/ 4348940SRandy.Fishel@Sun.COM default: 4358940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 4368940SRandy.Fishel@Sun.COM "unknown error.\n\n")); 4378940SRandy.Fishel@Sun.COM exit(1); 4388940SRandy.Fishel@Sun.COM } 4398940SRandy.Fishel@Sun.COM 4408940SRandy.Fishel@Sun.COM } 4418940SRandy.Fishel@Sun.COM 4428940SRandy.Fishel@Sun.COM /* 4438940SRandy.Fishel@Sun.COM * refresh_dt() - Refresh screen when 'dtgreet' is running. 4448940SRandy.Fishel@Sun.COM * This is here for compatibility reasons, and could be removed once 4458940SRandy.Fishel@Sun.COM * dtgreet is no longer part of the system. 4468940SRandy.Fishel@Sun.COM */ 4478940SRandy.Fishel@Sun.COM static int 4488940SRandy.Fishel@Sun.COM refresh_dt() 4498940SRandy.Fishel@Sun.COM { 4508940SRandy.Fishel@Sun.COM int status; 4518940SRandy.Fishel@Sun.COM struct stat stat_buf; 4528940SRandy.Fishel@Sun.COM 4538940SRandy.Fishel@Sun.COM /* 4548940SRandy.Fishel@Sun.COM * If dtgreet exists, HUP it, otherwise just let screenlock 4558940SRandy.Fishel@Sun.COM * do it's thing. 4568940SRandy.Fishel@Sun.COM */ 4578940SRandy.Fishel@Sun.COM if ((stat("/usr/dt/bin/dtgreet", &stat_buf) == 0) && 4588940SRandy.Fishel@Sun.COM (stat_buf.st_mode & S_IXUSR)) { 4598940SRandy.Fishel@Sun.COM switch (fork()) { 4608940SRandy.Fishel@Sun.COM case -1: 4618940SRandy.Fishel@Sun.COM break; 4628940SRandy.Fishel@Sun.COM case 0: 4638940SRandy.Fishel@Sun.COM (void) close(1); 4648940SRandy.Fishel@Sun.COM (void) execl("/usr/bin/pkill", "pkill", 4658940SRandy.Fishel@Sun.COM "-HUP", "-u", "0", "-x", "dtgreet", NULL); 4668940SRandy.Fishel@Sun.COM break; 4678940SRandy.Fishel@Sun.COM default: 4688940SRandy.Fishel@Sun.COM (void) wait(&status); 4698940SRandy.Fishel@Sun.COM } 4708940SRandy.Fishel@Sun.COM } 4718940SRandy.Fishel@Sun.COM 4728940SRandy.Fishel@Sun.COM return (0); 4738940SRandy.Fishel@Sun.COM } 4748940SRandy.Fishel@Sun.COM 4758940SRandy.Fishel@Sun.COM #define DT_TMP "/var/dt/tmp" 4768940SRandy.Fishel@Sun.COM 4778940SRandy.Fishel@Sun.COM /* 4788940SRandy.Fishel@Sun.COM * On enter, the "xauthority" string has the value "XAUTHORITY=". On 4798940SRandy.Fishel@Sun.COM * return, if a Xauthority file is found, concatenate it to this string, 4808940SRandy.Fishel@Sun.COM * otherwise, return "xauthority" as it is. 4818940SRandy.Fishel@Sun.COM */ 4828940SRandy.Fishel@Sun.COM static char * 4838940SRandy.Fishel@Sun.COM get_xauthority(char *xauthority) 4848940SRandy.Fishel@Sun.COM { 4858940SRandy.Fishel@Sun.COM pid_t uid; 4868940SRandy.Fishel@Sun.COM char *home_dir; 4878940SRandy.Fishel@Sun.COM struct passwd *pwd; 4888940SRandy.Fishel@Sun.COM char filepath[MAXPATHLEN]; 4898940SRandy.Fishel@Sun.COM struct stat stat_buf; 4908940SRandy.Fishel@Sun.COM DIR *dirp; 4918940SRandy.Fishel@Sun.COM struct dirent *dp; 4928940SRandy.Fishel@Sun.COM char xauth[MAXPATHLEN] = ""; 4938940SRandy.Fishel@Sun.COM time_t latest = 0; 4948940SRandy.Fishel@Sun.COM 4958940SRandy.Fishel@Sun.COM uid = getuid(); 4968940SRandy.Fishel@Sun.COM 4978940SRandy.Fishel@Sun.COM /* 4988940SRandy.Fishel@Sun.COM * Determine home directory of the user. 4998940SRandy.Fishel@Sun.COM */ 5008940SRandy.Fishel@Sun.COM if ((home_dir = getenv("HOME")) == NULL) { 5018940SRandy.Fishel@Sun.COM if ((pwd = getpwuid(uid)) == NULL) { 502*11053SSurya.Prakki@Sun.COM (void) printf(gettext("Error: unable to get passwd " 5038940SRandy.Fishel@Sun.COM "entry for user.\n")); 5048940SRandy.Fishel@Sun.COM exit(1); 5058940SRandy.Fishel@Sun.COM } 5068940SRandy.Fishel@Sun.COM home_dir = pwd->pw_dir; 5078940SRandy.Fishel@Sun.COM } 5088940SRandy.Fishel@Sun.COM if ((strlen(home_dir) + sizeof ("/.Xauthority")) >= MAXPATHLEN) { 509*11053SSurya.Prakki@Sun.COM (void) printf(gettext("Error: path to home directory is too " 5108940SRandy.Fishel@Sun.COM "long.\n")); 5118940SRandy.Fishel@Sun.COM exit(1); 5128940SRandy.Fishel@Sun.COM } 5138940SRandy.Fishel@Sun.COM 5148940SRandy.Fishel@Sun.COM /* 5158940SRandy.Fishel@Sun.COM * If there is a .Xauthority file in home directory, reference it. 5168940SRandy.Fishel@Sun.COM */ 5178940SRandy.Fishel@Sun.COM /*LINTED*/ 5188940SRandy.Fishel@Sun.COM (void) sprintf(filepath, "%s/.Xauthority", home_dir); 5198940SRandy.Fishel@Sun.COM if (stat(filepath, &stat_buf) == 0) 5208940SRandy.Fishel@Sun.COM return (strcat(xauthority, filepath)); 5218940SRandy.Fishel@Sun.COM 5228940SRandy.Fishel@Sun.COM /* 5238940SRandy.Fishel@Sun.COM * If Xsession can not access user's home directory, it creates the 5248940SRandy.Fishel@Sun.COM * Xauthority file in "/var/dt/tmp" directory. Since the exact 5258940SRandy.Fishel@Sun.COM * name of the Xauthority is not known, search the directory and 5268940SRandy.Fishel@Sun.COM * find the last changed file that starts with ".Xauth" and owned 5278940SRandy.Fishel@Sun.COM * by the user. Hopefully, that is the valid Xauthority file for 5288940SRandy.Fishel@Sun.COM * the current X session. 5298940SRandy.Fishel@Sun.COM */ 5308940SRandy.Fishel@Sun.COM if ((dirp = opendir(DT_TMP)) == NULL) 5318940SRandy.Fishel@Sun.COM return (xauthority); 5328940SRandy.Fishel@Sun.COM 5338940SRandy.Fishel@Sun.COM while ((dp = readdir(dirp)) != NULL) { 5348940SRandy.Fishel@Sun.COM if (strstr(dp->d_name, ".Xauth") != NULL) { 5358940SRandy.Fishel@Sun.COM /*LINTED*/ 5368940SRandy.Fishel@Sun.COM (void) sprintf(filepath, "%s/%s", DT_TMP, dp->d_name); 5378940SRandy.Fishel@Sun.COM if (stat(filepath, &stat_buf) == -1) 5388940SRandy.Fishel@Sun.COM continue; 5398940SRandy.Fishel@Sun.COM if (stat_buf.st_uid != uid) 5408940SRandy.Fishel@Sun.COM continue; 5418940SRandy.Fishel@Sun.COM if (stat_buf.st_ctime > latest) { 5428940SRandy.Fishel@Sun.COM (void) strcpy(xauth, filepath); 5438940SRandy.Fishel@Sun.COM latest = stat_buf.st_ctime; 5448940SRandy.Fishel@Sun.COM } 5458940SRandy.Fishel@Sun.COM } 5468940SRandy.Fishel@Sun.COM } 5478940SRandy.Fishel@Sun.COM (void) closedir(dirp); 5488940SRandy.Fishel@Sun.COM 5498940SRandy.Fishel@Sun.COM return (strcat(xauthority, xauth)); 5508940SRandy.Fishel@Sun.COM } 5518940SRandy.Fishel@Sun.COM 5528940SRandy.Fishel@Sun.COM /* 5538940SRandy.Fishel@Sun.COM * suspend can be called in following ways: 5548940SRandy.Fishel@Sun.COM * 1. from daemon (powerd) for auto-shutdown. 5558940SRandy.Fishel@Sun.COM * a. there might be a OW/CDE environment 5568940SRandy.Fishel@Sun.COM * b. there might not be any windowing environment 5578940SRandy.Fishel@Sun.COM * 2. by a user entered command. 5588940SRandy.Fishel@Sun.COM * a. the command can be entered from a cmdtool type OW/CDE tool 5598940SRandy.Fishel@Sun.COM * b. the command can be entered by a user logged in on a dumb 5608940SRandy.Fishel@Sun.COM * terminal. 5618940SRandy.Fishel@Sun.COM * i) there might be a OW/CDE running on console 5628940SRandy.Fishel@Sun.COM * and we have permission to talk to it. 5638940SRandy.Fishel@Sun.COM * ii) there is no OW/CDE running on console or we 5648940SRandy.Fishel@Sun.COM * don't have permission to talk to it or console 5658940SRandy.Fishel@Sun.COM * itself is the dumb terminal we have logged into. 5668940SRandy.Fishel@Sun.COM * 5678940SRandy.Fishel@Sun.COM * In main(), we decide on the correct case and call appropriate functions. 5688940SRandy.Fishel@Sun.COM */ 5698940SRandy.Fishel@Sun.COM 5708940SRandy.Fishel@Sun.COM int 5718940SRandy.Fishel@Sun.COM main(int argc, char **argv) 5728940SRandy.Fishel@Sun.COM { 5738940SRandy.Fishel@Sun.COM int c; 5748940SRandy.Fishel@Sun.COM char display_name[MAXNAMELEN + 9] = "DISPLAY="; 5758940SRandy.Fishel@Sun.COM char xauthority[MAXPATHLEN + 12] = "XAUTHORITY="; 5768940SRandy.Fishel@Sun.COM struct passwd *pw; 5778940SRandy.Fishel@Sun.COM 5788940SRandy.Fishel@Sun.COM (void *) signal(SIGHUP, SIG_IGN); 5798940SRandy.Fishel@Sun.COM (void *) signal(SIGINT, SIG_IGN); 5808940SRandy.Fishel@Sun.COM (void *) signal(SIGQUIT, SIG_IGN); 5818940SRandy.Fishel@Sun.COM (void *) signal(SIGTSTP, SIG_IGN); 5828940SRandy.Fishel@Sun.COM (void *) signal(SIGTTIN, SIG_IGN); 5838940SRandy.Fishel@Sun.COM (void *) signal(SIGTTOU, SIG_IGN); 5848940SRandy.Fishel@Sun.COM 5858940SRandy.Fishel@Sun.COM /* 5868940SRandy.Fishel@Sun.COM * If suspend is invoked from a daemon (case 1 above), it 5878940SRandy.Fishel@Sun.COM * will not have a working stdin, stdout and stderr. We need 5888940SRandy.Fishel@Sun.COM * these to print proper error messages and possibly get user 5898940SRandy.Fishel@Sun.COM * input. We attach them to console and hope that attachment 5908940SRandy.Fishel@Sun.COM * works. 5918940SRandy.Fishel@Sun.COM */ 5928940SRandy.Fishel@Sun.COM if (ttyname(0) == NULL) { 5938940SRandy.Fishel@Sun.COM no_tty = 1; 594*11053SSurya.Prakki@Sun.COM (void) dup2(open("/dev/console", O_RDONLY), 0); 595*11053SSurya.Prakki@Sun.COM (void) dup2(open("/dev/console", O_WRONLY), 1); 596*11053SSurya.Prakki@Sun.COM (void) dup2(open("/dev/console", O_WRONLY), 2); 5978940SRandy.Fishel@Sun.COM } 5988940SRandy.Fishel@Sun.COM 5998940SRandy.Fishel@Sun.COM while ((c = getopt(argc, argv, "fnxhtd:")) != EOF) { 6008940SRandy.Fishel@Sun.COM switch (c) { 6018940SRandy.Fishel@Sun.COM case 'f': 6028940SRandy.Fishel@Sun.COM /* 6038940SRandy.Fishel@Sun.COM * Force machine to poweroff if 6048940SRandy.Fishel@Sun.COM * suspend fails 6058940SRandy.Fishel@Sun.COM */ 6068940SRandy.Fishel@Sun.COM flags |= FORCE; 6078940SRandy.Fishel@Sun.COM break; 6088940SRandy.Fishel@Sun.COM case 'n': 6098940SRandy.Fishel@Sun.COM /* No warning popups - Obsolete */ 6108940SRandy.Fishel@Sun.COM flags |= NO_WARN; 6118940SRandy.Fishel@Sun.COM break; 6128940SRandy.Fishel@Sun.COM case 'x': 6138940SRandy.Fishel@Sun.COM /* Don't try to screenlock */ 6148940SRandy.Fishel@Sun.COM flags |= NO_XLOCK; 6158940SRandy.Fishel@Sun.COM break; 6168940SRandy.Fishel@Sun.COM case 'h': 6178940SRandy.Fishel@Sun.COM /* Do a shutdown instead of suspend */ 6188940SRandy.Fishel@Sun.COM flags |= SHUTDOWN; 6198940SRandy.Fishel@Sun.COM break; 6208940SRandy.Fishel@Sun.COM case 'd': 6218940SRandy.Fishel@Sun.COM /* Needswork */ 6228940SRandy.Fishel@Sun.COM /* Set the DISPLAY value in the environment */ 6238940SRandy.Fishel@Sun.COM if (strlen(optarg) >= MAXNAMELEN) { 6248940SRandy.Fishel@Sun.COM (void) printf(gettext("Error: " 6258940SRandy.Fishel@Sun.COM "display name is too long.\n")); 6268940SRandy.Fishel@Sun.COM return (1); 6278940SRandy.Fishel@Sun.COM } 6288940SRandy.Fishel@Sun.COM (void) strcat(display_name, optarg); 6298940SRandy.Fishel@Sun.COM if (putenv(display_name) != 0) { 6308940SRandy.Fishel@Sun.COM (void) printf(gettext("Error: " 6318940SRandy.Fishel@Sun.COM "unable to set DISPLAY " 6328940SRandy.Fishel@Sun.COM "environment variable.\n")); 6338940SRandy.Fishel@Sun.COM return (1); 6348940SRandy.Fishel@Sun.COM } 6358940SRandy.Fishel@Sun.COM break; 6368940SRandy.Fishel@Sun.COM case 't': 6378940SRandy.Fishel@Sun.COM /* Test, don't actually do any operation */ 6388940SRandy.Fishel@Sun.COM flags |= TEST; 6398940SRandy.Fishel@Sun.COM break; 6408940SRandy.Fishel@Sun.COM default: 6418940SRandy.Fishel@Sun.COM (void) printf(gettext("USAGE: suspend " 6428940SRandy.Fishel@Sun.COM "[-fnxh] [-d <display>]\n")); 6438940SRandy.Fishel@Sun.COM return (1); 6448940SRandy.Fishel@Sun.COM break; 6458940SRandy.Fishel@Sun.COM } 6468940SRandy.Fishel@Sun.COM } 6478940SRandy.Fishel@Sun.COM 6488940SRandy.Fishel@Sun.COM /* 6498940SRandy.Fishel@Sun.COM * The action of pressing power key and power button on a MOU-3 machine 6508940SRandy.Fishel@Sun.COM * causes suspend being invoked with SYSSUSPENDDODEFAULT 6518940SRandy.Fishel@Sun.COM * enviromental variable set - indicating the default action is machine 6528940SRandy.Fishel@Sun.COM * dependent: for MOU-3 type machine, "LowPower" mode is the default, 6538940SRandy.Fishel@Sun.COM * for all the rest, "Suspend" is the default. Existing suspend 6548940SRandy.Fishel@Sun.COM * flags works the same. 6558940SRandy.Fishel@Sun.COM */ 6568940SRandy.Fishel@Sun.COM if (getenv("SYSSUSPENDDODEFAULT")) 6578940SRandy.Fishel@Sun.COM if (is_mou3()) 6588940SRandy.Fishel@Sun.COM flags |= LOWPOWER; 6598940SRandy.Fishel@Sun.COM 6608940SRandy.Fishel@Sun.COM if ((flags & FORCE) && (flags & LOWPOWER)) 6618940SRandy.Fishel@Sun.COM flags &= ~LOWPOWER; 6628940SRandy.Fishel@Sun.COM 6638940SRandy.Fishel@Sun.COM /* 6648940SRandy.Fishel@Sun.COM * Flag "-h" overrides flag "-f". 6658940SRandy.Fishel@Sun.COM */ 6668940SRandy.Fishel@Sun.COM if ((flags & SHUTDOWN) && (flags & FORCE)) 6678940SRandy.Fishel@Sun.COM flags &= ~(FORCE | LOWPOWER); 6688940SRandy.Fishel@Sun.COM 6698940SRandy.Fishel@Sun.COM if (flags & FORCE) 6708940SRandy.Fishel@Sun.COM flags |= NO_WARN; 6718940SRandy.Fishel@Sun.COM 6728940SRandy.Fishel@Sun.COM /* 6738940SRandy.Fishel@Sun.COM * Check initally if the user has the authorizations to 6748940SRandy.Fishel@Sun.COM * do either a suspend or shutdown. pm_suspend() will also 6758940SRandy.Fishel@Sun.COM * make this test, so we could defer till then, but if we 6768940SRandy.Fishel@Sun.COM * do it now, we at least prevent a lot of unneeded setup. 6778940SRandy.Fishel@Sun.COM */ 6788940SRandy.Fishel@Sun.COM pw = getpwuid(getuid()); 679*11053SSurya.Prakki@Sun.COM (void) strncpy(user, pw->pw_name, NMAX); 6808940SRandy.Fishel@Sun.COM 6818940SRandy.Fishel@Sun.COM if ((flags & (FORCE|SHUTDOWN)) && 6828940SRandy.Fishel@Sun.COM (chkauthattr(AUTHNAME_SHUTDOWN, pw->pw_name) != 1)) { 6838940SRandy.Fishel@Sun.COM (void) printf(gettext("User does not have correct " 6848940SRandy.Fishel@Sun.COM "authorizations to shutdown the machine.\n")); 6858940SRandy.Fishel@Sun.COM exit(1); 6868940SRandy.Fishel@Sun.COM } 6878940SRandy.Fishel@Sun.COM if (!(flags & SHUTDOWN) && 6888940SRandy.Fishel@Sun.COM (chkauthattr(AUTHNAME_SUSPEND, pw->pw_name) != 1)) { 6898940SRandy.Fishel@Sun.COM (void) printf(gettext("User does not have correct " 6908940SRandy.Fishel@Sun.COM "authorizations to suspend.\n")); 6918940SRandy.Fishel@Sun.COM exit(1); 6928940SRandy.Fishel@Sun.COM } 6938940SRandy.Fishel@Sun.COM 6948940SRandy.Fishel@Sun.COM /* 6958940SRandy.Fishel@Sun.COM * If we are only shutting down, there isn't much to do, just 6968940SRandy.Fishel@Sun.COM * call pm_poweroff(), and let it do all the work. 6978940SRandy.Fishel@Sun.COM */ 6988940SRandy.Fishel@Sun.COM if (flags & SHUTDOWN) { 6998940SRandy.Fishel@Sun.COM /* 7008940SRandy.Fishel@Sun.COM * pm_poweroff either powers off or exits, 7018940SRandy.Fishel@Sun.COM * so there is no return. 7028940SRandy.Fishel@Sun.COM */ 7038940SRandy.Fishel@Sun.COM if (flags & TEST) { 7048940SRandy.Fishel@Sun.COM (void) printf("TEST: This machine would have " 7058940SRandy.Fishel@Sun.COM "powered off\n"); 7068940SRandy.Fishel@Sun.COM exit(1); 7078940SRandy.Fishel@Sun.COM } else { 7088940SRandy.Fishel@Sun.COM pm_poweroff(); 7098940SRandy.Fishel@Sun.COM } 7108940SRandy.Fishel@Sun.COM /* NOTREACHED */ 7118940SRandy.Fishel@Sun.COM } 7128940SRandy.Fishel@Sun.COM 7138940SRandy.Fishel@Sun.COM /* 7148940SRandy.Fishel@Sun.COM * If XAUTHORITY environment variable is not set, try to set 7158940SRandy.Fishel@Sun.COM * one up. 7168940SRandy.Fishel@Sun.COM */ 7178940SRandy.Fishel@Sun.COM if (getenv("XAUTHORITY") == NULL) 7188940SRandy.Fishel@Sun.COM (void) putenv(get_xauthority(xauthority)); 7198940SRandy.Fishel@Sun.COM 7208940SRandy.Fishel@Sun.COM /* 7218940SRandy.Fishel@Sun.COM * In case of "suspend" being called from daemon "powerd", 7228940SRandy.Fishel@Sun.COM * signal SIGALRM is blocked so use "sigset()" instead of "signal()". 7238940SRandy.Fishel@Sun.COM */ 7248940SRandy.Fishel@Sun.COM (void *) sigset(SIGALRM, alarm_handler); 7258940SRandy.Fishel@Sun.COM 7268940SRandy.Fishel@Sun.COM /* Call the "suspend" function to do the last of the work */ 7278940SRandy.Fishel@Sun.COM pm_suspend(); 7288940SRandy.Fishel@Sun.COM 7298940SRandy.Fishel@Sun.COM if (refresh_dt() == -1) { 730*11053SSurya.Prakki@Sun.COM (void) printf("%s: Failed to refresh screen.\n", argv[0]); 7318940SRandy.Fishel@Sun.COM return (1); 7328940SRandy.Fishel@Sun.COM } 7338940SRandy.Fishel@Sun.COM return (0); 7348940SRandy.Fishel@Sun.COM } 7358940SRandy.Fishel@Sun.COM 7368940SRandy.Fishel@Sun.COM #include <sys/pm.h> 7378940SRandy.Fishel@Sun.COM 7388940SRandy.Fishel@Sun.COM /* 7398940SRandy.Fishel@Sun.COM * Note that some of these functions are more relevant to Sparc platforms, 7408940SRandy.Fishel@Sun.COM * but they do function properly on other platforms, they just don't do 7418940SRandy.Fishel@Sun.COM * as much. 7428940SRandy.Fishel@Sun.COM */ 7438940SRandy.Fishel@Sun.COM /* 7448940SRandy.Fishel@Sun.COM * bringto_lowpower() 7458940SRandy.Fishel@Sun.COM * This tells the PM framework to put the devices it controls in an idle 7468940SRandy.Fishel@Sun.COM * state. The framework only complains if a device that *must* be idle 7478940SRandy.Fishel@Sun.COM * doesn't succeed in getting there. 7488940SRandy.Fishel@Sun.COM */ 7498940SRandy.Fishel@Sun.COM static int 7508940SRandy.Fishel@Sun.COM bringto_lowpower() 7518940SRandy.Fishel@Sun.COM { 7528940SRandy.Fishel@Sun.COM int fd; 7538940SRandy.Fishel@Sun.COM 7548940SRandy.Fishel@Sun.COM if ((fd = open("/dev/pm", O_RDWR)) < 0) { 755*11053SSurya.Prakki@Sun.COM (void) printf(gettext("Can't open /dev/pm\n")); 7568940SRandy.Fishel@Sun.COM return (-1); 7578940SRandy.Fishel@Sun.COM } 7588940SRandy.Fishel@Sun.COM 7598940SRandy.Fishel@Sun.COM if (ioctl(fd, PM_IDLE_DOWN, NULL) < 0) { 760*11053SSurya.Prakki@Sun.COM (void) printf(gettext("Failed to bring system " 761*11053SSurya.Prakki@Sun.COM "to low power mode.\n")); 762*11053SSurya.Prakki@Sun.COM (void) close(fd); 7638940SRandy.Fishel@Sun.COM return (-1); 7648940SRandy.Fishel@Sun.COM } 765*11053SSurya.Prakki@Sun.COM (void) close(fd); 7668940SRandy.Fishel@Sun.COM return (0); 7678940SRandy.Fishel@Sun.COM } 7688940SRandy.Fishel@Sun.COM 7698940SRandy.Fishel@Sun.COM #include <sys/cpr.h> 7708940SRandy.Fishel@Sun.COM 7718940SRandy.Fishel@Sun.COM /* 7728940SRandy.Fishel@Sun.COM * Though this test is predominantly used on Sparc, it will run on other 7738940SRandy.Fishel@Sun.COM * platforms, and might be usefull one day on those. 7748940SRandy.Fishel@Sun.COM */ 7758940SRandy.Fishel@Sun.COM static int 7768940SRandy.Fishel@Sun.COM is_mou3() 7778940SRandy.Fishel@Sun.COM { 7788940SRandy.Fishel@Sun.COM struct cprconfig cf; 7798940SRandy.Fishel@Sun.COM int fd; 7808940SRandy.Fishel@Sun.COM int found = 0; 7818940SRandy.Fishel@Sun.COM 7828940SRandy.Fishel@Sun.COM if ((fd = open(CPR_CONFIG, O_RDONLY)) < 0) { 783*11053SSurya.Prakki@Sun.COM (void) printf(gettext("Can't open /etc/.cpr_config file.")); 7848940SRandy.Fishel@Sun.COM return (found); 7858940SRandy.Fishel@Sun.COM } 7868940SRandy.Fishel@Sun.COM 7878940SRandy.Fishel@Sun.COM if (read(fd, (void *) &cf, sizeof (cf)) != sizeof (cf)) { 788*11053SSurya.Prakki@Sun.COM (void) printf(gettext("Can't read /etc/.cpr_config file.")); 7898940SRandy.Fishel@Sun.COM } else { 7908940SRandy.Fishel@Sun.COM found = cf.is_autopm_default; 7918940SRandy.Fishel@Sun.COM } 7928940SRandy.Fishel@Sun.COM 793*11053SSurya.Prakki@Sun.COM (void) close(fd); 7948940SRandy.Fishel@Sun.COM return (found); 7958940SRandy.Fishel@Sun.COM } 7968940SRandy.Fishel@Sun.COM 7978940SRandy.Fishel@Sun.COM /* 7988940SRandy.Fishel@Sun.COM * Reauthenticate the user on return from suspend. 7998940SRandy.Fishel@Sun.COM * This is here and not in the PAM-specific file, as there are 8008940SRandy.Fishel@Sun.COM * items specific to sys-suspend, and not generic to PAM. This may 8018940SRandy.Fishel@Sun.COM * become part of a future PM library. The audit handle is passed, 8028940SRandy.Fishel@Sun.COM * as the pm_suspend code actually starts an audit session, so it 8038940SRandy.Fishel@Sun.COM * makes sense to just continue to use it. If it were separated 8048940SRandy.Fishel@Sun.COM * from the pm_suspend code, it will need to open a new session. 8058940SRandy.Fishel@Sun.COM */ 8068940SRandy.Fishel@Sun.COM #define DEF_ATTEMPTS 3 8078940SRandy.Fishel@Sun.COM static void 8088940SRandy.Fishel@Sun.COM pm_do_auth(adt_session_data_t *ah) 8098940SRandy.Fishel@Sun.COM { 8108940SRandy.Fishel@Sun.COM pam_handle_t *pm_pamh; 8118940SRandy.Fishel@Sun.COM int err; 8128940SRandy.Fishel@Sun.COM int pam_flag = 0; 8138940SRandy.Fishel@Sun.COM int chpasswd_tries; 8148940SRandy.Fishel@Sun.COM struct pam_conv pam_conv = {pam_tty_conv, NULL}; 8158940SRandy.Fishel@Sun.COM 8168940SRandy.Fishel@Sun.COM if (user[0] == '\0') 8178940SRandy.Fishel@Sun.COM return; 8188940SRandy.Fishel@Sun.COM 8198940SRandy.Fishel@Sun.COM if ((err = pam_start("sys-suspend", user, &pam_conv, 8208940SRandy.Fishel@Sun.COM &pm_pamh)) != PAM_SUCCESS) 8218940SRandy.Fishel@Sun.COM return; 8228940SRandy.Fishel@Sun.COM 8238940SRandy.Fishel@Sun.COM pam_flag = PAM_DISALLOW_NULL_AUTHTOK; 8248940SRandy.Fishel@Sun.COM 8258940SRandy.Fishel@Sun.COM do { 8268940SRandy.Fishel@Sun.COM err = pam_authenticate(pm_pamh, pam_flag); 8278940SRandy.Fishel@Sun.COM 8288940SRandy.Fishel@Sun.COM if (err == PAM_SUCCESS) { 8298940SRandy.Fishel@Sun.COM err = pam_acct_mgmt(pm_pamh, pam_flag); 8308940SRandy.Fishel@Sun.COM 8318940SRandy.Fishel@Sun.COM if (err == PAM_NEW_AUTHTOK_REQD) { 8328940SRandy.Fishel@Sun.COM chpasswd_tries = 0; 8338940SRandy.Fishel@Sun.COM 8348940SRandy.Fishel@Sun.COM do { 8358940SRandy.Fishel@Sun.COM err = pam_chauthtok(pm_pamh, 8368940SRandy.Fishel@Sun.COM PAM_CHANGE_EXPIRED_AUTHTOK); 8378940SRandy.Fishel@Sun.COM chpasswd_tries++; 8388940SRandy.Fishel@Sun.COM 8398940SRandy.Fishel@Sun.COM } while ((err == PAM_AUTHTOK_ERR || 8408940SRandy.Fishel@Sun.COM err == PAM_TRY_AGAIN) && 8418940SRandy.Fishel@Sun.COM chpasswd_tries < DEF_ATTEMPTS); 8428940SRandy.Fishel@Sun.COM pm_audit_event(ah, ADT_passwd, err); 8438940SRandy.Fishel@Sun.COM } 8448940SRandy.Fishel@Sun.COM err = pam_setcred(pm_pamh, PAM_REFRESH_CRED); 8458940SRandy.Fishel@Sun.COM } 8468940SRandy.Fishel@Sun.COM if (err != PAM_SUCCESS) { 8478940SRandy.Fishel@Sun.COM (void) fprintf(stdout, "%s\n", 8488940SRandy.Fishel@Sun.COM pam_strerror(pm_pamh, err)); 8498940SRandy.Fishel@Sun.COM pm_audit_event(ah, ADT_screenunlock, err); 8508940SRandy.Fishel@Sun.COM } 8518940SRandy.Fishel@Sun.COM } while (err != PAM_SUCCESS); 8528940SRandy.Fishel@Sun.COM pm_audit_event(ah, ADT_passwd, 0); 8538940SRandy.Fishel@Sun.COM 8548940SRandy.Fishel@Sun.COM (void) pam_end(pm_pamh, err); 8558940SRandy.Fishel@Sun.COM } 856