1*8940SRandy.Fishel@Sun.COM /* 2*8940SRandy.Fishel@Sun.COM * CDDL HEADER START 3*8940SRandy.Fishel@Sun.COM * 4*8940SRandy.Fishel@Sun.COM * The contents of this file are subject to the terms of the 5*8940SRandy.Fishel@Sun.COM * Common Development and Distribution License (the "License"). 6*8940SRandy.Fishel@Sun.COM * You may not use this file except in compliance with the License. 7*8940SRandy.Fishel@Sun.COM * 8*8940SRandy.Fishel@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*8940SRandy.Fishel@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*8940SRandy.Fishel@Sun.COM * See the License for the specific language governing permissions 11*8940SRandy.Fishel@Sun.COM * and limitations under the License. 12*8940SRandy.Fishel@Sun.COM * 13*8940SRandy.Fishel@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*8940SRandy.Fishel@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*8940SRandy.Fishel@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*8940SRandy.Fishel@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*8940SRandy.Fishel@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*8940SRandy.Fishel@Sun.COM * 19*8940SRandy.Fishel@Sun.COM * CDDL HEADER END 20*8940SRandy.Fishel@Sun.COM */ 21*8940SRandy.Fishel@Sun.COM /* 22*8940SRandy.Fishel@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*8940SRandy.Fishel@Sun.COM * Use is subject to license terms. 24*8940SRandy.Fishel@Sun.COM */ 25*8940SRandy.Fishel@Sun.COM 26*8940SRandy.Fishel@Sun.COM /* 27*8940SRandy.Fishel@Sun.COM * This code has a lot in common with the original sys-suspend 28*8940SRandy.Fishel@Sun.COM * code. Windowing facilities have been removed, and it has been 29*8940SRandy.Fishel@Sun.COM * updated to use more recent API's. 30*8940SRandy.Fishel@Sun.COM */ 31*8940SRandy.Fishel@Sun.COM #include <stdio.h> 32*8940SRandy.Fishel@Sun.COM #include <fcntl.h> 33*8940SRandy.Fishel@Sun.COM #include <stdlib.h> 34*8940SRandy.Fishel@Sun.COM #include <string.h> 35*8940SRandy.Fishel@Sun.COM #include <strings.h> 36*8940SRandy.Fishel@Sun.COM #include <unistd.h> 37*8940SRandy.Fishel@Sun.COM #include <libintl.h> 38*8940SRandy.Fishel@Sun.COM #include <locale.h> 39*8940SRandy.Fishel@Sun.COM #include <utility.h> 40*8940SRandy.Fishel@Sun.COM #include <signal.h> 41*8940SRandy.Fishel@Sun.COM #include <errno.h> 42*8940SRandy.Fishel@Sun.COM #include <setjmp.h> 43*8940SRandy.Fishel@Sun.COM #include <pwd.h> 44*8940SRandy.Fishel@Sun.COM #include <syslog.h> 45*8940SRandy.Fishel@Sun.COM #include <sys/types.h> 46*8940SRandy.Fishel@Sun.COM #include <sys/param.h> 47*8940SRandy.Fishel@Sun.COM #include <sys/utsname.h> 48*8940SRandy.Fishel@Sun.COM #include <sys/uadmin.h> 49*8940SRandy.Fishel@Sun.COM #include <auth_attr.h> 50*8940SRandy.Fishel@Sun.COM #include <auth_list.h> 51*8940SRandy.Fishel@Sun.COM #include <secdb.h> 52*8940SRandy.Fishel@Sun.COM #include <security/pam_appl.h> 53*8940SRandy.Fishel@Sun.COM #include <utmpx.h> 54*8940SRandy.Fishel@Sun.COM 55*8940SRandy.Fishel@Sun.COM /* For audit */ 56*8940SRandy.Fishel@Sun.COM #include <bsm/adt.h> 57*8940SRandy.Fishel@Sun.COM #include <bsm/adt_event.h> 58*8940SRandy.Fishel@Sun.COM 59*8940SRandy.Fishel@Sun.COM #include <sys/wait.h> 60*8940SRandy.Fishel@Sun.COM #include <sys/stat.h> 61*8940SRandy.Fishel@Sun.COM #include <sys/pm.h> 62*8940SRandy.Fishel@Sun.COM #include <dirent.h> 63*8940SRandy.Fishel@Sun.COM #include <sys/cpr.h> 64*8940SRandy.Fishel@Sun.COM 65*8940SRandy.Fishel@Sun.COM /* STATICUSED */ 66*8940SRandy.Fishel@Sun.COM struct utmpx utmp; 67*8940SRandy.Fishel@Sun.COM #define NMAX (sizeof (utmp.ut_name)) 68*8940SRandy.Fishel@Sun.COM 69*8940SRandy.Fishel@Sun.COM /* 70*8940SRandy.Fishel@Sun.COM * Authorizations used by Power Management 71*8940SRandy.Fishel@Sun.COM */ 72*8940SRandy.Fishel@Sun.COM #define AUTHNAME_SHUTDOWN "solaris.system.shutdown" 73*8940SRandy.Fishel@Sun.COM #define AUTHNAME_SUSPEND_RAM "solaris.system.power.suspend.ram" 74*8940SRandy.Fishel@Sun.COM #define AUTHNAME_SUSPEND_DISK "solaris.system.power.suspend.disk" 75*8940SRandy.Fishel@Sun.COM 76*8940SRandy.Fishel@Sun.COM /* Platform specific definitions */ 77*8940SRandy.Fishel@Sun.COM #ifdef i386 78*8940SRandy.Fishel@Sun.COM #define AD_CHECK_SUSPEND AD_CHECK_SUSPEND_TO_RAM 79*8940SRandy.Fishel@Sun.COM #define AD_SUSPEND AD_SUSPEND_TO_RAM 80*8940SRandy.Fishel@Sun.COM #define ADT_FCN ADT_UADMIN_FCN_AD_SUSPEND_TO_RAM 81*8940SRandy.Fishel@Sun.COM #define AUTHNAME_SUSPEND AUTHNAME_SUSPEND_RAM 82*8940SRandy.Fishel@Sun.COM #else 83*8940SRandy.Fishel@Sun.COM #define AD_CHECK_SUSPEND AD_CHECK_SUSPEND_TO_DISK 84*8940SRandy.Fishel@Sun.COM #define AD_SUSPEND AD_SUSPEND_TO_DISK 85*8940SRandy.Fishel@Sun.COM #define ADT_FCN ADT_UADMIN_FCN_AD_SUSPEND_TO_DISK 86*8940SRandy.Fishel@Sun.COM #define AUTHNAME_SUSPEND AUTHNAME_SUSPEND_DISK 87*8940SRandy.Fishel@Sun.COM #endif 88*8940SRandy.Fishel@Sun.COM 89*8940SRandy.Fishel@Sun.COM static int flags = 0; 90*8940SRandy.Fishel@Sun.COM static int no_tty = 0; 91*8940SRandy.Fishel@Sun.COM /* 92*8940SRandy.Fishel@Sun.COM * Flag definitions - could go in a header file, but there are just a few 93*8940SRandy.Fishel@Sun.COM */ 94*8940SRandy.Fishel@Sun.COM #define FORCE 0x001 95*8940SRandy.Fishel@Sun.COM #define NO_WARN 0x002 96*8940SRandy.Fishel@Sun.COM #define NO_XLOCK 0x004 97*8940SRandy.Fishel@Sun.COM #define SHUTDOWN 0x008 98*8940SRandy.Fishel@Sun.COM #define LOWPOWER 0x010 99*8940SRandy.Fishel@Sun.COM #define TEST 0x800 100*8940SRandy.Fishel@Sun.COM 101*8940SRandy.Fishel@Sun.COM static sigjmp_buf jmp_stack; 102*8940SRandy.Fishel@Sun.COM static char user[NMAX + 1]; 103*8940SRandy.Fishel@Sun.COM static char **argvl; 104*8940SRandy.Fishel@Sun.COM 105*8940SRandy.Fishel@Sun.COM 106*8940SRandy.Fishel@Sun.COM 107*8940SRandy.Fishel@Sun.COM /* 108*8940SRandy.Fishel@Sun.COM * Forward Declarations. 109*8940SRandy.Fishel@Sun.COM */ 110*8940SRandy.Fishel@Sun.COM static void pm_poweroff(void); 111*8940SRandy.Fishel@Sun.COM static int bringto_lowpower(void); 112*8940SRandy.Fishel@Sun.COM static int is_mou3(void); 113*8940SRandy.Fishel@Sun.COM static void suspend_error(int); 114*8940SRandy.Fishel@Sun.COM static int pm_check_suspend(void); 115*8940SRandy.Fishel@Sun.COM static void pm_suspend(void); 116*8940SRandy.Fishel@Sun.COM static void pm_do_auth(adt_session_data_t *); 117*8940SRandy.Fishel@Sun.COM 118*8940SRandy.Fishel@Sun.COM /* 119*8940SRandy.Fishel@Sun.COM * External Declarations. 120*8940SRandy.Fishel@Sun.COM */ 121*8940SRandy.Fishel@Sun.COM extern int pam_tty_conv(int, struct pam_message **, 122*8940SRandy.Fishel@Sun.COM struct pam_response **, void *); 123*8940SRandy.Fishel@Sun.COM extern char *optarg; 124*8940SRandy.Fishel@Sun.COM 125*8940SRandy.Fishel@Sun.COM /* 126*8940SRandy.Fishel@Sun.COM * Audit related code. I would also think that some of this could be 127*8940SRandy.Fishel@Sun.COM * in external code, as they could be useful of other apps. 128*8940SRandy.Fishel@Sun.COM */ 129*8940SRandy.Fishel@Sun.COM /* 130*8940SRandy.Fishel@Sun.COM * Write audit event. Could be useful in the PM library, so it is 131*8940SRandy.Fishel@Sun.COM * included here. For the most part it is only used by the PAM code. 132*8940SRandy.Fishel@Sun.COM */ 133*8940SRandy.Fishel@Sun.COM static void 134*8940SRandy.Fishel@Sun.COM pm_audit_event(adt_session_data_t *ah, au_event_t event_id, int status) 135*8940SRandy.Fishel@Sun.COM { 136*8940SRandy.Fishel@Sun.COM adt_event_data_t *event; 137*8940SRandy.Fishel@Sun.COM 138*8940SRandy.Fishel@Sun.COM 139*8940SRandy.Fishel@Sun.COM if ((event = adt_alloc_event(ah, event_id)) == NULL) { 140*8940SRandy.Fishel@Sun.COM return; 141*8940SRandy.Fishel@Sun.COM } 142*8940SRandy.Fishel@Sun.COM 143*8940SRandy.Fishel@Sun.COM (void) adt_put_event(event, 144*8940SRandy.Fishel@Sun.COM status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE, 145*8940SRandy.Fishel@Sun.COM status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM + status); 146*8940SRandy.Fishel@Sun.COM 147*8940SRandy.Fishel@Sun.COM adt_free_event(event); 148*8940SRandy.Fishel@Sun.COM } 149*8940SRandy.Fishel@Sun.COM 150*8940SRandy.Fishel@Sun.COM #define RETRY_COUNT 15 151*8940SRandy.Fishel@Sun.COM static int 152*8940SRandy.Fishel@Sun.COM change_audit_file(void) 153*8940SRandy.Fishel@Sun.COM { 154*8940SRandy.Fishel@Sun.COM pid_t pid; 155*8940SRandy.Fishel@Sun.COM 156*8940SRandy.Fishel@Sun.COM if (!adt_audit_state(AUC_AUDITING)) { 157*8940SRandy.Fishel@Sun.COM /* auditd not running, just return */ 158*8940SRandy.Fishel@Sun.COM return (0); 159*8940SRandy.Fishel@Sun.COM } 160*8940SRandy.Fishel@Sun.COM 161*8940SRandy.Fishel@Sun.COM if ((pid = fork()) == 0) { 162*8940SRandy.Fishel@Sun.COM (void) execl("/usr/sbin/audit", "audit", "-n", NULL); 163*8940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext("error changing audit files: " 164*8940SRandy.Fishel@Sun.COM "%s\n"), strerror(errno)); 165*8940SRandy.Fishel@Sun.COM _exit(-1); 166*8940SRandy.Fishel@Sun.COM } else if (pid == -1) { 167*8940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext("error changing audit files: " 168*8940SRandy.Fishel@Sun.COM "%s\n"), strerror(errno)); 169*8940SRandy.Fishel@Sun.COM return (-1); 170*8940SRandy.Fishel@Sun.COM } else { 171*8940SRandy.Fishel@Sun.COM pid_t rc; 172*8940SRandy.Fishel@Sun.COM int retries = RETRY_COUNT; 173*8940SRandy.Fishel@Sun.COM 174*8940SRandy.Fishel@Sun.COM /* 175*8940SRandy.Fishel@Sun.COM * Wait for audit(1M) -n process to complete 176*8940SRandy.Fishel@Sun.COM * 177*8940SRandy.Fishel@Sun.COM */ 178*8940SRandy.Fishel@Sun.COM do { 179*8940SRandy.Fishel@Sun.COM if ((rc = waitpid(pid, NULL, WNOHANG)) == pid) { 180*8940SRandy.Fishel@Sun.COM return (0); 181*8940SRandy.Fishel@Sun.COM } else if (rc == -1) { 182*8940SRandy.Fishel@Sun.COM return (-1); 183*8940SRandy.Fishel@Sun.COM } else { 184*8940SRandy.Fishel@Sun.COM (void) sleep(1); 185*8940SRandy.Fishel@Sun.COM retries--; 186*8940SRandy.Fishel@Sun.COM } 187*8940SRandy.Fishel@Sun.COM 188*8940SRandy.Fishel@Sun.COM } while (retries != 0); 189*8940SRandy.Fishel@Sun.COM } 190*8940SRandy.Fishel@Sun.COM return (-1); 191*8940SRandy.Fishel@Sun.COM } 192*8940SRandy.Fishel@Sun.COM 193*8940SRandy.Fishel@Sun.COM static void 194*8940SRandy.Fishel@Sun.COM wait_for_auqueue() 195*8940SRandy.Fishel@Sun.COM { 196*8940SRandy.Fishel@Sun.COM au_stat_t au_stat; 197*8940SRandy.Fishel@Sun.COM int retries = 10; 198*8940SRandy.Fishel@Sun.COM 199*8940SRandy.Fishel@Sun.COM while (retries-- && auditon(A_GETSTAT, (caddr_t)&au_stat, NULL) == 0) { 200*8940SRandy.Fishel@Sun.COM if (au_stat.as_enqueue == au_stat.as_written) { 201*8940SRandy.Fishel@Sun.COM break; 202*8940SRandy.Fishel@Sun.COM } 203*8940SRandy.Fishel@Sun.COM (void) sleep(1); 204*8940SRandy.Fishel@Sun.COM } 205*8940SRandy.Fishel@Sun.COM } 206*8940SRandy.Fishel@Sun.COM 207*8940SRandy.Fishel@Sun.COM /* End of Audit-related code */ 208*8940SRandy.Fishel@Sun.COM 209*8940SRandy.Fishel@Sun.COM /* ARGSUSED0 */ 210*8940SRandy.Fishel@Sun.COM static void 211*8940SRandy.Fishel@Sun.COM alarm_handler(int sig) 212*8940SRandy.Fishel@Sun.COM { 213*8940SRandy.Fishel@Sun.COM siglongjmp(jmp_stack, 1); 214*8940SRandy.Fishel@Sun.COM } 215*8940SRandy.Fishel@Sun.COM 216*8940SRandy.Fishel@Sun.COM /* 217*8940SRandy.Fishel@Sun.COM * These are functions that would be candidates for moving to a library. 218*8940SRandy.Fishel@Sun.COM */ 219*8940SRandy.Fishel@Sun.COM 220*8940SRandy.Fishel@Sun.COM /* 221*8940SRandy.Fishel@Sun.COM * pm_poweroff - similar to poweroff(1M) 222*8940SRandy.Fishel@Sun.COM * This should do the same auditing as poweroff(1m) would do when it 223*8940SRandy.Fishel@Sun.COM * becomes a libpower function. Till then we use poweroff(1m). 224*8940SRandy.Fishel@Sun.COM */ 225*8940SRandy.Fishel@Sun.COM static void 226*8940SRandy.Fishel@Sun.COM pm_poweroff(void) 227*8940SRandy.Fishel@Sun.COM { 228*8940SRandy.Fishel@Sun.COM if (chkauthattr(AUTHNAME_SHUTDOWN, user) != 1) { 229*8940SRandy.Fishel@Sun.COM (void) printf(gettext("User %s does not have correct " 230*8940SRandy.Fishel@Sun.COM "authorizations to shutdown this machine.\n"), user); 231*8940SRandy.Fishel@Sun.COM exit(1); 232*8940SRandy.Fishel@Sun.COM } 233*8940SRandy.Fishel@Sun.COM openlog("suspend", 0, LOG_DAEMON); 234*8940SRandy.Fishel@Sun.COM syslog(LOG_NOTICE, "System is being shut down."); 235*8940SRandy.Fishel@Sun.COM closelog(); 236*8940SRandy.Fishel@Sun.COM 237*8940SRandy.Fishel@Sun.COM /* 238*8940SRandy.Fishel@Sun.COM * Call poweroff(1m) to shut down the system. 239*8940SRandy.Fishel@Sun.COM */ 240*8940SRandy.Fishel@Sun.COM (void) execl("/usr/sbin/poweroff", "poweroff", NULL); 241*8940SRandy.Fishel@Sun.COM 242*8940SRandy.Fishel@Sun.COM } 243*8940SRandy.Fishel@Sun.COM 244*8940SRandy.Fishel@Sun.COM /* 245*8940SRandy.Fishel@Sun.COM * pm_check_suspend() - Check to see if suspend is supported/enabled 246*8940SRandy.Fishel@Sun.COM * on this machine. 247*8940SRandy.Fishel@Sun.COM * Ultimately, we would prefer to get the "default" suspend type from 248*8940SRandy.Fishel@Sun.COM * a PM property or some other API, but for now, we know that STR is 249*8940SRandy.Fishel@Sun.COM * only available on x86 and STD is only available on Sparc. It does 250*8940SRandy.Fishel@Sun.COM * make this function quite easy, though. 251*8940SRandy.Fishel@Sun.COM */ 252*8940SRandy.Fishel@Sun.COM static int 253*8940SRandy.Fishel@Sun.COM pm_check_suspend(void) { 254*8940SRandy.Fishel@Sun.COM /* 255*8940SRandy.Fishel@Sun.COM * Use the uadmin(2) "CHECK" command to see if suspend is supported 256*8940SRandy.Fishel@Sun.COM */ 257*8940SRandy.Fishel@Sun.COM return (uadmin(A_FREEZE, AD_CHECK_SUSPEND, 0)); 258*8940SRandy.Fishel@Sun.COM } 259*8940SRandy.Fishel@Sun.COM 260*8940SRandy.Fishel@Sun.COM /* 261*8940SRandy.Fishel@Sun.COM * This entry point _should_ be the common entry to suspend. It is in 262*8940SRandy.Fishel@Sun.COM * it's entirety here, but would be best moved to libpower when that 263*8940SRandy.Fishel@Sun.COM * is available. 264*8940SRandy.Fishel@Sun.COM */ 265*8940SRandy.Fishel@Sun.COM static void 266*8940SRandy.Fishel@Sun.COM pm_suspend(void) 267*8940SRandy.Fishel@Sun.COM { 268*8940SRandy.Fishel@Sun.COM int cprarg = AD_SUSPEND; 269*8940SRandy.Fishel@Sun.COM enum adt_uadmin_fcn fcn_id = ADT_FCN; 270*8940SRandy.Fishel@Sun.COM au_event_t event_id = ADT_uadmin_freeze; 271*8940SRandy.Fishel@Sun.COM adt_event_data_t *event = NULL; /* event to be generated */ 272*8940SRandy.Fishel@Sun.COM adt_session_data_t *ah = NULL; /* audit session handle */ 273*8940SRandy.Fishel@Sun.COM 274*8940SRandy.Fishel@Sun.COM /* 275*8940SRandy.Fishel@Sun.COM * Does the user have permission to use this command? 276*8940SRandy.Fishel@Sun.COM */ 277*8940SRandy.Fishel@Sun.COM if (chkauthattr(AUTHNAME_SUSPEND, user) != 1) { 278*8940SRandy.Fishel@Sun.COM (void) printf(gettext("User %s does not have correct " 279*8940SRandy.Fishel@Sun.COM "authorizations to suspend this machine.\n"), user); 280*8940SRandy.Fishel@Sun.COM exit(1); 281*8940SRandy.Fishel@Sun.COM } 282*8940SRandy.Fishel@Sun.COM 283*8940SRandy.Fishel@Sun.COM if (flags & LOWPOWER) { 284*8940SRandy.Fishel@Sun.COM if (bringto_lowpower() == -1) { 285*8940SRandy.Fishel@Sun.COM (void) printf(gettext("LowPower Failed\n")); 286*8940SRandy.Fishel@Sun.COM exit(1); 287*8940SRandy.Fishel@Sun.COM } 288*8940SRandy.Fishel@Sun.COM } else if (flags & TEST) { 289*8940SRandy.Fishel@Sun.COM /* 290*8940SRandy.Fishel@Sun.COM * Test mode, do checks as if a real suspend, but 291*8940SRandy.Fishel@Sun.COM * don't actually do the suspend. 292*8940SRandy.Fishel@Sun.COM */ 293*8940SRandy.Fishel@Sun.COM /* Check if suspend is supported */ 294*8940SRandy.Fishel@Sun.COM if (pm_check_suspend() == -1) { 295*8940SRandy.Fishel@Sun.COM suspend_error(errno); 296*8940SRandy.Fishel@Sun.COM } 297*8940SRandy.Fishel@Sun.COM 298*8940SRandy.Fishel@Sun.COM (void) printf(gettext("TEST: Suspend would have been" 299*8940SRandy.Fishel@Sun.COM " performed\n")); 300*8940SRandy.Fishel@Sun.COM 301*8940SRandy.Fishel@Sun.COM } else { 302*8940SRandy.Fishel@Sun.COM /* Check if suspend is supported */ 303*8940SRandy.Fishel@Sun.COM if (pm_check_suspend() == -1) { 304*8940SRandy.Fishel@Sun.COM suspend_error(errno); 305*8940SRandy.Fishel@Sun.COM } 306*8940SRandy.Fishel@Sun.COM 307*8940SRandy.Fishel@Sun.COM /* 308*8940SRandy.Fishel@Sun.COM * We are about to suspend this machine, try and 309*8940SRandy.Fishel@Sun.COM * lock the screen. We don't really care if this 310*8940SRandy.Fishel@Sun.COM * succeeds or not, but that we actually tried. We 311*8940SRandy.Fishel@Sun.COM * also know that we have sufficient privileges to 312*8940SRandy.Fishel@Sun.COM * be here, so we lock the screen now, even if 313*8940SRandy.Fishel@Sun.COM * suspend actually fails. 314*8940SRandy.Fishel@Sun.COM * Note that garbage is sometimes displayed, and 315*8940SRandy.Fishel@Sun.COM * we don't really care about it, so we toss all 316*8940SRandy.Fishel@Sun.COM * text response. 317*8940SRandy.Fishel@Sun.COM * it would also be good if there were another option 318*8940SRandy.Fishel@Sun.COM * instead of launcing a file, as the disk might be 319*8940SRandy.Fishel@Sun.COM * spun down if we are suspending due to idle. 320*8940SRandy.Fishel@Sun.COM */ 321*8940SRandy.Fishel@Sun.COM if (!(flags & NO_XLOCK)) { 322*8940SRandy.Fishel@Sun.COM (void) system("/usr/bin/xdg-screensaver lock " 323*8940SRandy.Fishel@Sun.COM " >/dev/null 2>&1"); 324*8940SRandy.Fishel@Sun.COM } 325*8940SRandy.Fishel@Sun.COM 326*8940SRandy.Fishel@Sun.COM /* Time to do the actual deed! */ 327*8940SRandy.Fishel@Sun.COM /* 328*8940SRandy.Fishel@Sun.COM * Before we actually suspend, we need to audit and 329*8940SRandy.Fishel@Sun.COM * "suspend" the audit files. 330*8940SRandy.Fishel@Sun.COM */ 331*8940SRandy.Fishel@Sun.COM /* set up audit session and event */ 332*8940SRandy.Fishel@Sun.COM if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) == 0) { 333*8940SRandy.Fishel@Sun.COM if ((event = adt_alloc_event(ah, event_id)) != NULL) { 334*8940SRandy.Fishel@Sun.COM event->adt_uadmin_freeze.fcn = fcn_id; 335*8940SRandy.Fishel@Sun.COM event->adt_uadmin_freeze.mdep = NULL; 336*8940SRandy.Fishel@Sun.COM if (adt_put_event(event, ADT_SUCCESS, 0) != 0) { 337*8940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext( 338*8940SRandy.Fishel@Sun.COM "%s: can't put audit event\n"), 339*8940SRandy.Fishel@Sun.COM argvl[0]); 340*8940SRandy.Fishel@Sun.COM } else { 341*8940SRandy.Fishel@Sun.COM wait_for_auqueue(); 342*8940SRandy.Fishel@Sun.COM } 343*8940SRandy.Fishel@Sun.COM } 344*8940SRandy.Fishel@Sun.COM (void) change_audit_file(); 345*8940SRandy.Fishel@Sun.COM } else { 346*8940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext( 347*8940SRandy.Fishel@Sun.COM "%s: can't start audit session\n"), argvl[0]); 348*8940SRandy.Fishel@Sun.COM } 349*8940SRandy.Fishel@Sun.COM 350*8940SRandy.Fishel@Sun.COM if (uadmin(A_FREEZE, cprarg, 0) != 0) { 351*8940SRandy.Fishel@Sun.COM (void) printf(gettext("Suspend Failed\n")); 352*8940SRandy.Fishel@Sun.COM if (flags & FORCE) { 353*8940SRandy.Fishel@Sun.COM /* 354*8940SRandy.Fishel@Sun.COM * Note, that if we actually poweroff, 355*8940SRandy.Fishel@Sun.COM * that the poweroff function will handle 356*8940SRandy.Fishel@Sun.COM * that audit trail, and the resume 357*8940SRandy.Fishel@Sun.COM * trail is effectively done. 358*8940SRandy.Fishel@Sun.COM */ 359*8940SRandy.Fishel@Sun.COM pm_poweroff(); 360*8940SRandy.Fishel@Sun.COM } else { 361*8940SRandy.Fishel@Sun.COM /* suspend_error() will exit. */ 362*8940SRandy.Fishel@Sun.COM suspend_error(errno); 363*8940SRandy.Fishel@Sun.COM /* 364*8940SRandy.Fishel@Sun.COM * Audit the suspend failure and 365*8940SRandy.Fishel@Sun.COM * reuse the event, but don't create one 366*8940SRandy.Fishel@Sun.COM * if we don't already have one. 367*8940SRandy.Fishel@Sun.COM */ 368*8940SRandy.Fishel@Sun.COM if (event != NULL) { 369*8940SRandy.Fishel@Sun.COM adt_put_event(event, ADT_FAILURE, 0); 370*8940SRandy.Fishel@Sun.COM } 371*8940SRandy.Fishel@Sun.COM } 372*8940SRandy.Fishel@Sun.COM } 373*8940SRandy.Fishel@Sun.COM 374*8940SRandy.Fishel@Sun.COM /* 375*8940SRandy.Fishel@Sun.COM * Write the thaw event. 376*8940SRandy.Fishel@Sun.COM */ 377*8940SRandy.Fishel@Sun.COM if (ah != NULL) { 378*8940SRandy.Fishel@Sun.COM if ((event == NULL) && 379*8940SRandy.Fishel@Sun.COM ((event = adt_alloc_event(ah, ADT_uadmin_thaw)) 380*8940SRandy.Fishel@Sun.COM == NULL)) { 381*8940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext( 382*8940SRandy.Fishel@Sun.COM "%s: can't allocate thaw audit event\n"), 383*8940SRandy.Fishel@Sun.COM argvl[0]); 384*8940SRandy.Fishel@Sun.COM } else { 385*8940SRandy.Fishel@Sun.COM event->adt_uadmin_thaw.fcn = fcn_id; 386*8940SRandy.Fishel@Sun.COM if (adt_put_event(event, ADT_SUCCESS, 0) != 0) { 387*8940SRandy.Fishel@Sun.COM (void) fprintf(stderr, gettext( 388*8940SRandy.Fishel@Sun.COM "%s: can't put thaw audit event\n"), 389*8940SRandy.Fishel@Sun.COM argvl[0]); 390*8940SRandy.Fishel@Sun.COM } 391*8940SRandy.Fishel@Sun.COM (void) adt_free_event(event); 392*8940SRandy.Fishel@Sun.COM } 393*8940SRandy.Fishel@Sun.COM } 394*8940SRandy.Fishel@Sun.COM } 395*8940SRandy.Fishel@Sun.COM if ((no_tty ? 0 : 1) && !(flags & NO_XLOCK)) { 396*8940SRandy.Fishel@Sun.COM pm_do_auth(ah); 397*8940SRandy.Fishel@Sun.COM } 398*8940SRandy.Fishel@Sun.COM 399*8940SRandy.Fishel@Sun.COM (void) adt_end_session(ah); 400*8940SRandy.Fishel@Sun.COM } 401*8940SRandy.Fishel@Sun.COM /* End of "library" functions */ 402*8940SRandy.Fishel@Sun.COM 403*8940SRandy.Fishel@Sun.COM /* 404*8940SRandy.Fishel@Sun.COM * Print an appropriate error message and exit. 405*8940SRandy.Fishel@Sun.COM */ 406*8940SRandy.Fishel@Sun.COM 407*8940SRandy.Fishel@Sun.COM static void 408*8940SRandy.Fishel@Sun.COM suspend_error(int error) { 409*8940SRandy.Fishel@Sun.COM 410*8940SRandy.Fishel@Sun.COM switch (error) { 411*8940SRandy.Fishel@Sun.COM case EBUSY: 412*8940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 413*8940SRandy.Fishel@Sun.COM "Suspend already in progress.\n\n")); 414*8940SRandy.Fishel@Sun.COM exit(1); 415*8940SRandy.Fishel@Sun.COM /*NOTREACHED*/ 416*8940SRandy.Fishel@Sun.COM case ENOMEM: 417*8940SRandy.Fishel@Sun.COM /*FALLTHROUGH*/ 418*8940SRandy.Fishel@Sun.COM case ENOSPC: 419*8940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 420*8940SRandy.Fishel@Sun.COM "Not enough resources to suspend.\n\n")); 421*8940SRandy.Fishel@Sun.COM exit(1); 422*8940SRandy.Fishel@Sun.COM /*NOTREACHED*/ 423*8940SRandy.Fishel@Sun.COM case ENOTSUP: 424*8940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 425*8940SRandy.Fishel@Sun.COM "Suspend is not supported.\n\n")); 426*8940SRandy.Fishel@Sun.COM exit(1); 427*8940SRandy.Fishel@Sun.COM /*NOTREACHED*/ 428*8940SRandy.Fishel@Sun.COM case EPERM: 429*8940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 430*8940SRandy.Fishel@Sun.COM "Not sufficient privileges.\n\n")); 431*8940SRandy.Fishel@Sun.COM exit(1); 432*8940SRandy.Fishel@Sun.COM /*NOTREACHED*/ 433*8940SRandy.Fishel@Sun.COM default: 434*8940SRandy.Fishel@Sun.COM (void) printf(gettext("suspend: " 435*8940SRandy.Fishel@Sun.COM "unknown error.\n\n")); 436*8940SRandy.Fishel@Sun.COM exit(1); 437*8940SRandy.Fishel@Sun.COM } 438*8940SRandy.Fishel@Sun.COM 439*8940SRandy.Fishel@Sun.COM } 440*8940SRandy.Fishel@Sun.COM 441*8940SRandy.Fishel@Sun.COM /* 442*8940SRandy.Fishel@Sun.COM * refresh_dt() - Refresh screen when 'dtgreet' is running. 443*8940SRandy.Fishel@Sun.COM * This is here for compatibility reasons, and could be removed once 444*8940SRandy.Fishel@Sun.COM * dtgreet is no longer part of the system. 445*8940SRandy.Fishel@Sun.COM */ 446*8940SRandy.Fishel@Sun.COM static int 447*8940SRandy.Fishel@Sun.COM refresh_dt() 448*8940SRandy.Fishel@Sun.COM { 449*8940SRandy.Fishel@Sun.COM int status; 450*8940SRandy.Fishel@Sun.COM struct stat stat_buf; 451*8940SRandy.Fishel@Sun.COM 452*8940SRandy.Fishel@Sun.COM /* 453*8940SRandy.Fishel@Sun.COM * If dtgreet exists, HUP it, otherwise just let screenlock 454*8940SRandy.Fishel@Sun.COM * do it's thing. 455*8940SRandy.Fishel@Sun.COM */ 456*8940SRandy.Fishel@Sun.COM if ((stat("/usr/dt/bin/dtgreet", &stat_buf) == 0) && 457*8940SRandy.Fishel@Sun.COM (stat_buf.st_mode & S_IXUSR)) { 458*8940SRandy.Fishel@Sun.COM switch (fork()) { 459*8940SRandy.Fishel@Sun.COM case -1: 460*8940SRandy.Fishel@Sun.COM break; 461*8940SRandy.Fishel@Sun.COM case 0: 462*8940SRandy.Fishel@Sun.COM (void) close(1); 463*8940SRandy.Fishel@Sun.COM (void) execl("/usr/bin/pkill", "pkill", 464*8940SRandy.Fishel@Sun.COM "-HUP", "-u", "0", "-x", "dtgreet", NULL); 465*8940SRandy.Fishel@Sun.COM break; 466*8940SRandy.Fishel@Sun.COM default: 467*8940SRandy.Fishel@Sun.COM (void) wait(&status); 468*8940SRandy.Fishel@Sun.COM } 469*8940SRandy.Fishel@Sun.COM } 470*8940SRandy.Fishel@Sun.COM 471*8940SRandy.Fishel@Sun.COM return (0); 472*8940SRandy.Fishel@Sun.COM } 473*8940SRandy.Fishel@Sun.COM 474*8940SRandy.Fishel@Sun.COM #define DT_TMP "/var/dt/tmp" 475*8940SRandy.Fishel@Sun.COM 476*8940SRandy.Fishel@Sun.COM /* 477*8940SRandy.Fishel@Sun.COM * On enter, the "xauthority" string has the value "XAUTHORITY=". On 478*8940SRandy.Fishel@Sun.COM * return, if a Xauthority file is found, concatenate it to this string, 479*8940SRandy.Fishel@Sun.COM * otherwise, return "xauthority" as it is. 480*8940SRandy.Fishel@Sun.COM */ 481*8940SRandy.Fishel@Sun.COM static char * 482*8940SRandy.Fishel@Sun.COM get_xauthority(char *xauthority) 483*8940SRandy.Fishel@Sun.COM { 484*8940SRandy.Fishel@Sun.COM pid_t uid; 485*8940SRandy.Fishel@Sun.COM char *home_dir; 486*8940SRandy.Fishel@Sun.COM struct passwd *pwd; 487*8940SRandy.Fishel@Sun.COM char filepath[MAXPATHLEN]; 488*8940SRandy.Fishel@Sun.COM struct stat stat_buf; 489*8940SRandy.Fishel@Sun.COM DIR *dirp; 490*8940SRandy.Fishel@Sun.COM struct dirent *dp; 491*8940SRandy.Fishel@Sun.COM char xauth[MAXPATHLEN] = ""; 492*8940SRandy.Fishel@Sun.COM time_t latest = 0; 493*8940SRandy.Fishel@Sun.COM 494*8940SRandy.Fishel@Sun.COM uid = getuid(); 495*8940SRandy.Fishel@Sun.COM 496*8940SRandy.Fishel@Sun.COM /* 497*8940SRandy.Fishel@Sun.COM * Determine home directory of the user. 498*8940SRandy.Fishel@Sun.COM */ 499*8940SRandy.Fishel@Sun.COM if ((home_dir = getenv("HOME")) == NULL) { 500*8940SRandy.Fishel@Sun.COM if ((pwd = getpwuid(uid)) == NULL) { 501*8940SRandy.Fishel@Sun.COM printf(gettext("Error: unable to get passwd " 502*8940SRandy.Fishel@Sun.COM "entry for user.\n")); 503*8940SRandy.Fishel@Sun.COM exit(1); 504*8940SRandy.Fishel@Sun.COM } 505*8940SRandy.Fishel@Sun.COM home_dir = pwd->pw_dir; 506*8940SRandy.Fishel@Sun.COM } 507*8940SRandy.Fishel@Sun.COM if ((strlen(home_dir) + sizeof ("/.Xauthority")) >= MAXPATHLEN) { 508*8940SRandy.Fishel@Sun.COM printf(gettext("Error: path to home directory is too " 509*8940SRandy.Fishel@Sun.COM "long.\n")); 510*8940SRandy.Fishel@Sun.COM exit(1); 511*8940SRandy.Fishel@Sun.COM } 512*8940SRandy.Fishel@Sun.COM 513*8940SRandy.Fishel@Sun.COM /* 514*8940SRandy.Fishel@Sun.COM * If there is a .Xauthority file in home directory, reference it. 515*8940SRandy.Fishel@Sun.COM */ 516*8940SRandy.Fishel@Sun.COM /*LINTED*/ 517*8940SRandy.Fishel@Sun.COM (void) sprintf(filepath, "%s/.Xauthority", home_dir); 518*8940SRandy.Fishel@Sun.COM if (stat(filepath, &stat_buf) == 0) 519*8940SRandy.Fishel@Sun.COM return (strcat(xauthority, filepath)); 520*8940SRandy.Fishel@Sun.COM 521*8940SRandy.Fishel@Sun.COM /* 522*8940SRandy.Fishel@Sun.COM * If Xsession can not access user's home directory, it creates the 523*8940SRandy.Fishel@Sun.COM * Xauthority file in "/var/dt/tmp" directory. Since the exact 524*8940SRandy.Fishel@Sun.COM * name of the Xauthority is not known, search the directory and 525*8940SRandy.Fishel@Sun.COM * find the last changed file that starts with ".Xauth" and owned 526*8940SRandy.Fishel@Sun.COM * by the user. Hopefully, that is the valid Xauthority file for 527*8940SRandy.Fishel@Sun.COM * the current X session. 528*8940SRandy.Fishel@Sun.COM */ 529*8940SRandy.Fishel@Sun.COM if ((dirp = opendir(DT_TMP)) == NULL) 530*8940SRandy.Fishel@Sun.COM return (xauthority); 531*8940SRandy.Fishel@Sun.COM 532*8940SRandy.Fishel@Sun.COM while ((dp = readdir(dirp)) != NULL) { 533*8940SRandy.Fishel@Sun.COM if (strstr(dp->d_name, ".Xauth") != NULL) { 534*8940SRandy.Fishel@Sun.COM /*LINTED*/ 535*8940SRandy.Fishel@Sun.COM (void) sprintf(filepath, "%s/%s", DT_TMP, dp->d_name); 536*8940SRandy.Fishel@Sun.COM if (stat(filepath, &stat_buf) == -1) 537*8940SRandy.Fishel@Sun.COM continue; 538*8940SRandy.Fishel@Sun.COM if (stat_buf.st_uid != uid) 539*8940SRandy.Fishel@Sun.COM continue; 540*8940SRandy.Fishel@Sun.COM if (stat_buf.st_ctime > latest) { 541*8940SRandy.Fishel@Sun.COM (void) strcpy(xauth, filepath); 542*8940SRandy.Fishel@Sun.COM latest = stat_buf.st_ctime; 543*8940SRandy.Fishel@Sun.COM } 544*8940SRandy.Fishel@Sun.COM } 545*8940SRandy.Fishel@Sun.COM } 546*8940SRandy.Fishel@Sun.COM (void) closedir(dirp); 547*8940SRandy.Fishel@Sun.COM 548*8940SRandy.Fishel@Sun.COM return (strcat(xauthority, xauth)); 549*8940SRandy.Fishel@Sun.COM } 550*8940SRandy.Fishel@Sun.COM 551*8940SRandy.Fishel@Sun.COM /* 552*8940SRandy.Fishel@Sun.COM * suspend can be called in following ways: 553*8940SRandy.Fishel@Sun.COM * 1. from daemon (powerd) for auto-shutdown. 554*8940SRandy.Fishel@Sun.COM * a. there might be a OW/CDE environment 555*8940SRandy.Fishel@Sun.COM * b. there might not be any windowing environment 556*8940SRandy.Fishel@Sun.COM * 2. by a user entered command. 557*8940SRandy.Fishel@Sun.COM * a. the command can be entered from a cmdtool type OW/CDE tool 558*8940SRandy.Fishel@Sun.COM * b. the command can be entered by a user logged in on a dumb 559*8940SRandy.Fishel@Sun.COM * terminal. 560*8940SRandy.Fishel@Sun.COM * i) there might be a OW/CDE running on console 561*8940SRandy.Fishel@Sun.COM * and we have permission to talk to it. 562*8940SRandy.Fishel@Sun.COM * ii) there is no OW/CDE running on console or we 563*8940SRandy.Fishel@Sun.COM * don't have permission to talk to it or console 564*8940SRandy.Fishel@Sun.COM * itself is the dumb terminal we have logged into. 565*8940SRandy.Fishel@Sun.COM * 566*8940SRandy.Fishel@Sun.COM * In main(), we decide on the correct case and call appropriate functions. 567*8940SRandy.Fishel@Sun.COM */ 568*8940SRandy.Fishel@Sun.COM 569*8940SRandy.Fishel@Sun.COM int 570*8940SRandy.Fishel@Sun.COM main(int argc, char **argv) 571*8940SRandy.Fishel@Sun.COM { 572*8940SRandy.Fishel@Sun.COM int c; 573*8940SRandy.Fishel@Sun.COM char display_name[MAXNAMELEN + 9] = "DISPLAY="; 574*8940SRandy.Fishel@Sun.COM char xauthority[MAXPATHLEN + 12] = "XAUTHORITY="; 575*8940SRandy.Fishel@Sun.COM struct passwd *pw; 576*8940SRandy.Fishel@Sun.COM 577*8940SRandy.Fishel@Sun.COM (void *) signal(SIGHUP, SIG_IGN); 578*8940SRandy.Fishel@Sun.COM (void *) signal(SIGINT, SIG_IGN); 579*8940SRandy.Fishel@Sun.COM (void *) signal(SIGQUIT, SIG_IGN); 580*8940SRandy.Fishel@Sun.COM (void *) signal(SIGTSTP, SIG_IGN); 581*8940SRandy.Fishel@Sun.COM (void *) signal(SIGTTIN, SIG_IGN); 582*8940SRandy.Fishel@Sun.COM (void *) signal(SIGTTOU, SIG_IGN); 583*8940SRandy.Fishel@Sun.COM 584*8940SRandy.Fishel@Sun.COM /* 585*8940SRandy.Fishel@Sun.COM * If suspend is invoked from a daemon (case 1 above), it 586*8940SRandy.Fishel@Sun.COM * will not have a working stdin, stdout and stderr. We need 587*8940SRandy.Fishel@Sun.COM * these to print proper error messages and possibly get user 588*8940SRandy.Fishel@Sun.COM * input. We attach them to console and hope that attachment 589*8940SRandy.Fishel@Sun.COM * works. 590*8940SRandy.Fishel@Sun.COM */ 591*8940SRandy.Fishel@Sun.COM if (ttyname(0) == NULL) { 592*8940SRandy.Fishel@Sun.COM no_tty = 1; 593*8940SRandy.Fishel@Sun.COM dup2(open("/dev/console", O_RDONLY), 0); 594*8940SRandy.Fishel@Sun.COM dup2(open("/dev/console", O_WRONLY), 1); 595*8940SRandy.Fishel@Sun.COM dup2(open("/dev/console", O_WRONLY), 2); 596*8940SRandy.Fishel@Sun.COM } 597*8940SRandy.Fishel@Sun.COM 598*8940SRandy.Fishel@Sun.COM while ((c = getopt(argc, argv, "fnxhtd:")) != EOF) { 599*8940SRandy.Fishel@Sun.COM switch (c) { 600*8940SRandy.Fishel@Sun.COM case 'f': 601*8940SRandy.Fishel@Sun.COM /* 602*8940SRandy.Fishel@Sun.COM * Force machine to poweroff if 603*8940SRandy.Fishel@Sun.COM * suspend fails 604*8940SRandy.Fishel@Sun.COM */ 605*8940SRandy.Fishel@Sun.COM flags |= FORCE; 606*8940SRandy.Fishel@Sun.COM break; 607*8940SRandy.Fishel@Sun.COM case 'n': 608*8940SRandy.Fishel@Sun.COM /* No warning popups - Obsolete */ 609*8940SRandy.Fishel@Sun.COM flags |= NO_WARN; 610*8940SRandy.Fishel@Sun.COM break; 611*8940SRandy.Fishel@Sun.COM case 'x': 612*8940SRandy.Fishel@Sun.COM /* Don't try to screenlock */ 613*8940SRandy.Fishel@Sun.COM flags |= NO_XLOCK; 614*8940SRandy.Fishel@Sun.COM break; 615*8940SRandy.Fishel@Sun.COM case 'h': 616*8940SRandy.Fishel@Sun.COM /* Do a shutdown instead of suspend */ 617*8940SRandy.Fishel@Sun.COM flags |= SHUTDOWN; 618*8940SRandy.Fishel@Sun.COM break; 619*8940SRandy.Fishel@Sun.COM case 'd': 620*8940SRandy.Fishel@Sun.COM /* Needswork */ 621*8940SRandy.Fishel@Sun.COM /* Set the DISPLAY value in the environment */ 622*8940SRandy.Fishel@Sun.COM if (strlen(optarg) >= MAXNAMELEN) { 623*8940SRandy.Fishel@Sun.COM (void) printf(gettext("Error: " 624*8940SRandy.Fishel@Sun.COM "display name is too long.\n")); 625*8940SRandy.Fishel@Sun.COM return (1); 626*8940SRandy.Fishel@Sun.COM } 627*8940SRandy.Fishel@Sun.COM (void) strcat(display_name, optarg); 628*8940SRandy.Fishel@Sun.COM if (putenv(display_name) != 0) { 629*8940SRandy.Fishel@Sun.COM (void) printf(gettext("Error: " 630*8940SRandy.Fishel@Sun.COM "unable to set DISPLAY " 631*8940SRandy.Fishel@Sun.COM "environment variable.\n")); 632*8940SRandy.Fishel@Sun.COM return (1); 633*8940SRandy.Fishel@Sun.COM } 634*8940SRandy.Fishel@Sun.COM break; 635*8940SRandy.Fishel@Sun.COM case 't': 636*8940SRandy.Fishel@Sun.COM /* Test, don't actually do any operation */ 637*8940SRandy.Fishel@Sun.COM flags |= TEST; 638*8940SRandy.Fishel@Sun.COM break; 639*8940SRandy.Fishel@Sun.COM default: 640*8940SRandy.Fishel@Sun.COM (void) printf(gettext("USAGE: suspend " 641*8940SRandy.Fishel@Sun.COM "[-fnxh] [-d <display>]\n")); 642*8940SRandy.Fishel@Sun.COM return (1); 643*8940SRandy.Fishel@Sun.COM break; 644*8940SRandy.Fishel@Sun.COM } 645*8940SRandy.Fishel@Sun.COM } 646*8940SRandy.Fishel@Sun.COM 647*8940SRandy.Fishel@Sun.COM /* 648*8940SRandy.Fishel@Sun.COM * The action of pressing power key and power button on a MOU-3 machine 649*8940SRandy.Fishel@Sun.COM * causes suspend being invoked with SYSSUSPENDDODEFAULT 650*8940SRandy.Fishel@Sun.COM * enviromental variable set - indicating the default action is machine 651*8940SRandy.Fishel@Sun.COM * dependent: for MOU-3 type machine, "LowPower" mode is the default, 652*8940SRandy.Fishel@Sun.COM * for all the rest, "Suspend" is the default. Existing suspend 653*8940SRandy.Fishel@Sun.COM * flags works the same. 654*8940SRandy.Fishel@Sun.COM */ 655*8940SRandy.Fishel@Sun.COM if (getenv("SYSSUSPENDDODEFAULT")) 656*8940SRandy.Fishel@Sun.COM if (is_mou3()) 657*8940SRandy.Fishel@Sun.COM flags |= LOWPOWER; 658*8940SRandy.Fishel@Sun.COM 659*8940SRandy.Fishel@Sun.COM if ((flags & FORCE) && (flags & LOWPOWER)) 660*8940SRandy.Fishel@Sun.COM flags &= ~LOWPOWER; 661*8940SRandy.Fishel@Sun.COM 662*8940SRandy.Fishel@Sun.COM /* 663*8940SRandy.Fishel@Sun.COM * Flag "-h" overrides flag "-f". 664*8940SRandy.Fishel@Sun.COM */ 665*8940SRandy.Fishel@Sun.COM if ((flags & SHUTDOWN) && (flags & FORCE)) 666*8940SRandy.Fishel@Sun.COM flags &= ~(FORCE | LOWPOWER); 667*8940SRandy.Fishel@Sun.COM 668*8940SRandy.Fishel@Sun.COM if (flags & FORCE) 669*8940SRandy.Fishel@Sun.COM flags |= NO_WARN; 670*8940SRandy.Fishel@Sun.COM 671*8940SRandy.Fishel@Sun.COM /* 672*8940SRandy.Fishel@Sun.COM * Check initally if the user has the authorizations to 673*8940SRandy.Fishel@Sun.COM * do either a suspend or shutdown. pm_suspend() will also 674*8940SRandy.Fishel@Sun.COM * make this test, so we could defer till then, but if we 675*8940SRandy.Fishel@Sun.COM * do it now, we at least prevent a lot of unneeded setup. 676*8940SRandy.Fishel@Sun.COM */ 677*8940SRandy.Fishel@Sun.COM pw = getpwuid(getuid()); 678*8940SRandy.Fishel@Sun.COM strncpy(user, pw->pw_name, NMAX); 679*8940SRandy.Fishel@Sun.COM 680*8940SRandy.Fishel@Sun.COM if ((flags & (FORCE|SHUTDOWN)) && 681*8940SRandy.Fishel@Sun.COM (chkauthattr(AUTHNAME_SHUTDOWN, pw->pw_name) != 1)) { 682*8940SRandy.Fishel@Sun.COM (void) printf(gettext("User does not have correct " 683*8940SRandy.Fishel@Sun.COM "authorizations to shutdown the machine.\n")); 684*8940SRandy.Fishel@Sun.COM exit(1); 685*8940SRandy.Fishel@Sun.COM } 686*8940SRandy.Fishel@Sun.COM if (!(flags & SHUTDOWN) && 687*8940SRandy.Fishel@Sun.COM (chkauthattr(AUTHNAME_SUSPEND, pw->pw_name) != 1)) { 688*8940SRandy.Fishel@Sun.COM (void) printf(gettext("User does not have correct " 689*8940SRandy.Fishel@Sun.COM "authorizations to suspend.\n")); 690*8940SRandy.Fishel@Sun.COM exit(1); 691*8940SRandy.Fishel@Sun.COM } 692*8940SRandy.Fishel@Sun.COM 693*8940SRandy.Fishel@Sun.COM /* 694*8940SRandy.Fishel@Sun.COM * If we are only shutting down, there isn't much to do, just 695*8940SRandy.Fishel@Sun.COM * call pm_poweroff(), and let it do all the work. 696*8940SRandy.Fishel@Sun.COM */ 697*8940SRandy.Fishel@Sun.COM if (flags & SHUTDOWN) { 698*8940SRandy.Fishel@Sun.COM /* 699*8940SRandy.Fishel@Sun.COM * pm_poweroff either powers off or exits, 700*8940SRandy.Fishel@Sun.COM * so there is no return. 701*8940SRandy.Fishel@Sun.COM */ 702*8940SRandy.Fishel@Sun.COM if (flags & TEST) { 703*8940SRandy.Fishel@Sun.COM (void) printf("TEST: This machine would have " 704*8940SRandy.Fishel@Sun.COM "powered off\n"); 705*8940SRandy.Fishel@Sun.COM exit(1); 706*8940SRandy.Fishel@Sun.COM } else { 707*8940SRandy.Fishel@Sun.COM pm_poweroff(); 708*8940SRandy.Fishel@Sun.COM } 709*8940SRandy.Fishel@Sun.COM /* NOTREACHED */ 710*8940SRandy.Fishel@Sun.COM } 711*8940SRandy.Fishel@Sun.COM 712*8940SRandy.Fishel@Sun.COM /* 713*8940SRandy.Fishel@Sun.COM * If XAUTHORITY environment variable is not set, try to set 714*8940SRandy.Fishel@Sun.COM * one up. 715*8940SRandy.Fishel@Sun.COM */ 716*8940SRandy.Fishel@Sun.COM if (getenv("XAUTHORITY") == NULL) 717*8940SRandy.Fishel@Sun.COM (void) putenv(get_xauthority(xauthority)); 718*8940SRandy.Fishel@Sun.COM 719*8940SRandy.Fishel@Sun.COM /* 720*8940SRandy.Fishel@Sun.COM * In case of "suspend" being called from daemon "powerd", 721*8940SRandy.Fishel@Sun.COM * signal SIGALRM is blocked so use "sigset()" instead of "signal()". 722*8940SRandy.Fishel@Sun.COM */ 723*8940SRandy.Fishel@Sun.COM (void *) sigset(SIGALRM, alarm_handler); 724*8940SRandy.Fishel@Sun.COM 725*8940SRandy.Fishel@Sun.COM /* Call the "suspend" function to do the last of the work */ 726*8940SRandy.Fishel@Sun.COM pm_suspend(); 727*8940SRandy.Fishel@Sun.COM 728*8940SRandy.Fishel@Sun.COM if (refresh_dt() == -1) { 729*8940SRandy.Fishel@Sun.COM printf("%s: Failed to refresh screen.\n", argv[0]); 730*8940SRandy.Fishel@Sun.COM return (1); 731*8940SRandy.Fishel@Sun.COM } 732*8940SRandy.Fishel@Sun.COM return (0); 733*8940SRandy.Fishel@Sun.COM } 734*8940SRandy.Fishel@Sun.COM 735*8940SRandy.Fishel@Sun.COM #include <sys/pm.h> 736*8940SRandy.Fishel@Sun.COM 737*8940SRandy.Fishel@Sun.COM /* 738*8940SRandy.Fishel@Sun.COM * Note that some of these functions are more relevant to Sparc platforms, 739*8940SRandy.Fishel@Sun.COM * but they do function properly on other platforms, they just don't do 740*8940SRandy.Fishel@Sun.COM * as much. 741*8940SRandy.Fishel@Sun.COM */ 742*8940SRandy.Fishel@Sun.COM /* 743*8940SRandy.Fishel@Sun.COM * bringto_lowpower() 744*8940SRandy.Fishel@Sun.COM * This tells the PM framework to put the devices it controls in an idle 745*8940SRandy.Fishel@Sun.COM * state. The framework only complains if a device that *must* be idle 746*8940SRandy.Fishel@Sun.COM * doesn't succeed in getting there. 747*8940SRandy.Fishel@Sun.COM */ 748*8940SRandy.Fishel@Sun.COM static int 749*8940SRandy.Fishel@Sun.COM bringto_lowpower() 750*8940SRandy.Fishel@Sun.COM { 751*8940SRandy.Fishel@Sun.COM int fd; 752*8940SRandy.Fishel@Sun.COM 753*8940SRandy.Fishel@Sun.COM if ((fd = open("/dev/pm", O_RDWR)) < 0) { 754*8940SRandy.Fishel@Sun.COM printf(gettext("Can't open /dev/pm\n")); 755*8940SRandy.Fishel@Sun.COM return (-1); 756*8940SRandy.Fishel@Sun.COM } 757*8940SRandy.Fishel@Sun.COM 758*8940SRandy.Fishel@Sun.COM if (ioctl(fd, PM_IDLE_DOWN, NULL) < 0) { 759*8940SRandy.Fishel@Sun.COM printf(gettext("Failed to bring system to low power mode.\n")); 760*8940SRandy.Fishel@Sun.COM close(fd); 761*8940SRandy.Fishel@Sun.COM return (-1); 762*8940SRandy.Fishel@Sun.COM } 763*8940SRandy.Fishel@Sun.COM close(fd); 764*8940SRandy.Fishel@Sun.COM return (0); 765*8940SRandy.Fishel@Sun.COM } 766*8940SRandy.Fishel@Sun.COM 767*8940SRandy.Fishel@Sun.COM #include <sys/cpr.h> 768*8940SRandy.Fishel@Sun.COM 769*8940SRandy.Fishel@Sun.COM /* 770*8940SRandy.Fishel@Sun.COM * Though this test is predominantly used on Sparc, it will run on other 771*8940SRandy.Fishel@Sun.COM * platforms, and might be usefull one day on those. 772*8940SRandy.Fishel@Sun.COM */ 773*8940SRandy.Fishel@Sun.COM static int 774*8940SRandy.Fishel@Sun.COM is_mou3() 775*8940SRandy.Fishel@Sun.COM { 776*8940SRandy.Fishel@Sun.COM struct cprconfig cf; 777*8940SRandy.Fishel@Sun.COM int fd; 778*8940SRandy.Fishel@Sun.COM int found = 0; 779*8940SRandy.Fishel@Sun.COM 780*8940SRandy.Fishel@Sun.COM if ((fd = open(CPR_CONFIG, O_RDONLY)) < 0) { 781*8940SRandy.Fishel@Sun.COM printf(gettext("Can't open /etc/.cpr_config file.")); 782*8940SRandy.Fishel@Sun.COM return (found); 783*8940SRandy.Fishel@Sun.COM } 784*8940SRandy.Fishel@Sun.COM 785*8940SRandy.Fishel@Sun.COM if (read(fd, (void *) &cf, sizeof (cf)) != sizeof (cf)) { 786*8940SRandy.Fishel@Sun.COM printf(gettext("Can't read /etc/.cpr_config file.")); 787*8940SRandy.Fishel@Sun.COM } else { 788*8940SRandy.Fishel@Sun.COM found = cf.is_autopm_default; 789*8940SRandy.Fishel@Sun.COM } 790*8940SRandy.Fishel@Sun.COM 791*8940SRandy.Fishel@Sun.COM close(fd); 792*8940SRandy.Fishel@Sun.COM return (found); 793*8940SRandy.Fishel@Sun.COM } 794*8940SRandy.Fishel@Sun.COM 795*8940SRandy.Fishel@Sun.COM /* 796*8940SRandy.Fishel@Sun.COM * Reauthenticate the user on return from suspend. 797*8940SRandy.Fishel@Sun.COM * This is here and not in the PAM-specific file, as there are 798*8940SRandy.Fishel@Sun.COM * items specific to sys-suspend, and not generic to PAM. This may 799*8940SRandy.Fishel@Sun.COM * become part of a future PM library. The audit handle is passed, 800*8940SRandy.Fishel@Sun.COM * as the pm_suspend code actually starts an audit session, so it 801*8940SRandy.Fishel@Sun.COM * makes sense to just continue to use it. If it were separated 802*8940SRandy.Fishel@Sun.COM * from the pm_suspend code, it will need to open a new session. 803*8940SRandy.Fishel@Sun.COM */ 804*8940SRandy.Fishel@Sun.COM #define DEF_ATTEMPTS 3 805*8940SRandy.Fishel@Sun.COM static void 806*8940SRandy.Fishel@Sun.COM pm_do_auth(adt_session_data_t *ah) 807*8940SRandy.Fishel@Sun.COM { 808*8940SRandy.Fishel@Sun.COM pam_handle_t *pm_pamh; 809*8940SRandy.Fishel@Sun.COM int err; 810*8940SRandy.Fishel@Sun.COM int pam_flag = 0; 811*8940SRandy.Fishel@Sun.COM int chpasswd_tries; 812*8940SRandy.Fishel@Sun.COM struct pam_conv pam_conv = {pam_tty_conv, NULL}; 813*8940SRandy.Fishel@Sun.COM 814*8940SRandy.Fishel@Sun.COM if (user[0] == '\0') 815*8940SRandy.Fishel@Sun.COM return; 816*8940SRandy.Fishel@Sun.COM 817*8940SRandy.Fishel@Sun.COM if ((err = pam_start("sys-suspend", user, &pam_conv, 818*8940SRandy.Fishel@Sun.COM &pm_pamh)) != PAM_SUCCESS) 819*8940SRandy.Fishel@Sun.COM return; 820*8940SRandy.Fishel@Sun.COM 821*8940SRandy.Fishel@Sun.COM pam_flag = PAM_DISALLOW_NULL_AUTHTOK; 822*8940SRandy.Fishel@Sun.COM 823*8940SRandy.Fishel@Sun.COM do { 824*8940SRandy.Fishel@Sun.COM err = pam_authenticate(pm_pamh, pam_flag); 825*8940SRandy.Fishel@Sun.COM 826*8940SRandy.Fishel@Sun.COM if (err == PAM_SUCCESS) { 827*8940SRandy.Fishel@Sun.COM err = pam_acct_mgmt(pm_pamh, pam_flag); 828*8940SRandy.Fishel@Sun.COM 829*8940SRandy.Fishel@Sun.COM if (err == PAM_NEW_AUTHTOK_REQD) { 830*8940SRandy.Fishel@Sun.COM chpasswd_tries = 0; 831*8940SRandy.Fishel@Sun.COM 832*8940SRandy.Fishel@Sun.COM do { 833*8940SRandy.Fishel@Sun.COM err = pam_chauthtok(pm_pamh, 834*8940SRandy.Fishel@Sun.COM PAM_CHANGE_EXPIRED_AUTHTOK); 835*8940SRandy.Fishel@Sun.COM chpasswd_tries++; 836*8940SRandy.Fishel@Sun.COM 837*8940SRandy.Fishel@Sun.COM } while ((err == PAM_AUTHTOK_ERR || 838*8940SRandy.Fishel@Sun.COM err == PAM_TRY_AGAIN) && 839*8940SRandy.Fishel@Sun.COM chpasswd_tries < DEF_ATTEMPTS); 840*8940SRandy.Fishel@Sun.COM pm_audit_event(ah, ADT_passwd, err); 841*8940SRandy.Fishel@Sun.COM } 842*8940SRandy.Fishel@Sun.COM err = pam_setcred(pm_pamh, PAM_REFRESH_CRED); 843*8940SRandy.Fishel@Sun.COM } 844*8940SRandy.Fishel@Sun.COM if (err != PAM_SUCCESS) { 845*8940SRandy.Fishel@Sun.COM (void) fprintf(stdout, "%s\n", 846*8940SRandy.Fishel@Sun.COM pam_strerror(pm_pamh, err)); 847*8940SRandy.Fishel@Sun.COM pm_audit_event(ah, ADT_screenunlock, err); 848*8940SRandy.Fishel@Sun.COM } 849*8940SRandy.Fishel@Sun.COM } while (err != PAM_SUCCESS); 850*8940SRandy.Fishel@Sun.COM pm_audit_event(ah, ADT_passwd, 0); 851*8940SRandy.Fishel@Sun.COM 852*8940SRandy.Fishel@Sun.COM (void) pam_end(pm_pamh, err); 853*8940SRandy.Fishel@Sun.COM } 854