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