xref: /illumos-gate/usr/src/cmd/power/sys-suspend.c (revision cbea7aca3fd7787405cbdbd93752998f03dfc25f)
1623ec8b0SRandy Fishel /*
2623ec8b0SRandy Fishel  * CDDL HEADER START
3623ec8b0SRandy Fishel  *
4623ec8b0SRandy Fishel  * The contents of this file are subject to the terms of the
5623ec8b0SRandy Fishel  * Common Development and Distribution License (the "License").
6623ec8b0SRandy Fishel  * You may not use this file except in compliance with the License.
7623ec8b0SRandy Fishel  *
8623ec8b0SRandy Fishel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9623ec8b0SRandy Fishel  * or http://www.opensolaris.org/os/licensing.
10623ec8b0SRandy Fishel  * See the License for the specific language governing permissions
11623ec8b0SRandy Fishel  * and limitations under the License.
12623ec8b0SRandy Fishel  *
13623ec8b0SRandy Fishel  * When distributing Covered Code, include this CDDL HEADER in each
14623ec8b0SRandy Fishel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15623ec8b0SRandy Fishel  * If applicable, add the following below this CDDL HEADER, with the
16623ec8b0SRandy Fishel  * fields enclosed by brackets "[]" replaced with your own identifying
17623ec8b0SRandy Fishel  * information: Portions Copyright [yyyy] [name of copyright owner]
18623ec8b0SRandy Fishel  *
19623ec8b0SRandy Fishel  * CDDL HEADER END
20623ec8b0SRandy Fishel  */
21623ec8b0SRandy Fishel /*
22623ec8b0SRandy Fishel  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23623ec8b0SRandy Fishel  * Use is subject to license terms.
2433f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
25*cbea7acaSDominik Hassler  * Copyright 2023 OmniOS Community Edition (OmniOSce) Association.
26623ec8b0SRandy Fishel  */
27623ec8b0SRandy Fishel 
28623ec8b0SRandy Fishel /*
29623ec8b0SRandy Fishel  * This code has a lot in common with the original sys-suspend
30623ec8b0SRandy Fishel  * code.  Windowing facilities have been removed, and it has been
31623ec8b0SRandy Fishel  * updated to use more recent API's.
32623ec8b0SRandy Fishel  */
33623ec8b0SRandy Fishel #include <stdio.h>
34623ec8b0SRandy Fishel #include <fcntl.h>
35623ec8b0SRandy Fishel #include <stdlib.h>
36623ec8b0SRandy Fishel #include <string.h>
37623ec8b0SRandy Fishel #include <strings.h>
38623ec8b0SRandy Fishel #include <unistd.h>
39623ec8b0SRandy Fishel #include <libintl.h>
40623ec8b0SRandy Fishel #include <locale.h>
41623ec8b0SRandy Fishel #include <utility.h>
42623ec8b0SRandy Fishel #include <signal.h>
43623ec8b0SRandy Fishel #include <errno.h>
44623ec8b0SRandy Fishel #include <setjmp.h>
45623ec8b0SRandy Fishel #include <pwd.h>
46623ec8b0SRandy Fishel #include <syslog.h>
47623ec8b0SRandy Fishel #include <sys/types.h>
48623ec8b0SRandy Fishel #include <sys/param.h>
49623ec8b0SRandy Fishel #include <sys/utsname.h>
50623ec8b0SRandy Fishel #include <sys/uadmin.h>
51623ec8b0SRandy Fishel #include <auth_attr.h>
52623ec8b0SRandy Fishel #include <auth_list.h>
53623ec8b0SRandy Fishel #include <secdb.h>
54623ec8b0SRandy Fishel #include <security/pam_appl.h>
55623ec8b0SRandy Fishel #include <utmpx.h>
56623ec8b0SRandy Fishel 
57623ec8b0SRandy Fishel /* For audit */
58623ec8b0SRandy Fishel #include <bsm/adt.h>
59623ec8b0SRandy Fishel #include <bsm/adt_event.h>
60623ec8b0SRandy Fishel 
61623ec8b0SRandy Fishel #include <sys/wait.h>
62623ec8b0SRandy Fishel #include <sys/stat.h>
63623ec8b0SRandy Fishel #include <sys/pm.h>
64623ec8b0SRandy Fishel #include <dirent.h>
65623ec8b0SRandy Fishel #include <sys/cpr.h>
66623ec8b0SRandy Fishel 
67623ec8b0SRandy Fishel /* STATICUSED */
68623ec8b0SRandy Fishel struct utmpx	utmp;
69623ec8b0SRandy Fishel #define	NMAX		(sizeof (utmp.ut_name))
70623ec8b0SRandy Fishel 
71623ec8b0SRandy Fishel /*
72623ec8b0SRandy Fishel  * Authorizations used by Power Management
73623ec8b0SRandy Fishel  */
74623ec8b0SRandy Fishel #define	AUTHNAME_SHUTDOWN	"solaris.system.shutdown"
75623ec8b0SRandy Fishel #define	AUTHNAME_SUSPEND_RAM	"solaris.system.power.suspend.ram"
76623ec8b0SRandy Fishel #define	AUTHNAME_SUSPEND_DISK	"solaris.system.power.suspend.disk"
77623ec8b0SRandy Fishel 
78623ec8b0SRandy Fishel /* Platform specific definitions */
79623ec8b0SRandy Fishel #ifdef i386
80623ec8b0SRandy Fishel #define	AD_CHECK_SUSPEND	AD_CHECK_SUSPEND_TO_RAM
81623ec8b0SRandy Fishel #define	AD_SUSPEND		AD_SUSPEND_TO_RAM
82623ec8b0SRandy Fishel #define	ADT_FCN			ADT_UADMIN_FCN_AD_SUSPEND_TO_RAM
83623ec8b0SRandy Fishel #define	AUTHNAME_SUSPEND	AUTHNAME_SUSPEND_RAM
84623ec8b0SRandy Fishel #else
85623ec8b0SRandy Fishel #define	AD_CHECK_SUSPEND	AD_CHECK_SUSPEND_TO_DISK
86623ec8b0SRandy Fishel #define	AD_SUSPEND		AD_SUSPEND_TO_DISK
87623ec8b0SRandy Fishel #define	ADT_FCN			ADT_UADMIN_FCN_AD_SUSPEND_TO_DISK
88623ec8b0SRandy Fishel #define	AUTHNAME_SUSPEND	AUTHNAME_SUSPEND_DISK
89623ec8b0SRandy Fishel #endif
90623ec8b0SRandy Fishel 
91623ec8b0SRandy Fishel static	int		flags = 0;
92623ec8b0SRandy Fishel static	int		no_tty = 0;
93623ec8b0SRandy Fishel /*
94623ec8b0SRandy Fishel  * Flag definitions - could go in a header file, but there are just a few
95623ec8b0SRandy Fishel  */
96623ec8b0SRandy Fishel #define	FORCE		0x001
97623ec8b0SRandy Fishel #define	NO_WARN		0x002
98623ec8b0SRandy Fishel #define	NO_XLOCK	0x004
99623ec8b0SRandy Fishel #define	SHUTDOWN	0x008
100623ec8b0SRandy Fishel #define	LOWPOWER	0x010
101623ec8b0SRandy Fishel #define	TEST		0x800
102623ec8b0SRandy Fishel 
103623ec8b0SRandy Fishel static	sigjmp_buf	jmp_stack;
104623ec8b0SRandy Fishel static	char	user[NMAX + 1];
105623ec8b0SRandy Fishel static	char	**argvl;
106623ec8b0SRandy Fishel 
107623ec8b0SRandy Fishel 
108623ec8b0SRandy Fishel 
109623ec8b0SRandy Fishel /*
110623ec8b0SRandy Fishel  *  Forward Declarations.
111623ec8b0SRandy Fishel  */
112623ec8b0SRandy Fishel static	void	pm_poweroff(void);
113623ec8b0SRandy Fishel static	int	bringto_lowpower(void);
114623ec8b0SRandy Fishel static	int	is_mou3(void);
115623ec8b0SRandy Fishel static	void	suspend_error(int);
116623ec8b0SRandy Fishel static	int	pm_check_suspend(void);
117623ec8b0SRandy Fishel static	void	pm_suspend(void);
118623ec8b0SRandy Fishel static	void	pm_do_auth(adt_session_data_t *);
119623ec8b0SRandy Fishel 
120623ec8b0SRandy Fishel /*
121623ec8b0SRandy Fishel  *  External Declarations.
122623ec8b0SRandy Fishel  */
123*cbea7acaSDominik Hassler extern	int	pam_tty_conv(int, const struct pam_message **,
124623ec8b0SRandy Fishel     struct pam_response **, void *);
125623ec8b0SRandy Fishel extern	char	*optarg;
126623ec8b0SRandy Fishel 
127623ec8b0SRandy Fishel /*
128623ec8b0SRandy Fishel  * Audit related code.  I would also think that some of this could be
129623ec8b0SRandy Fishel  * in external code, as they could be useful of other apps.
130623ec8b0SRandy Fishel  */
131623ec8b0SRandy Fishel /*
132623ec8b0SRandy Fishel  * Write audit event.  Could be useful in the PM library, so it is
133623ec8b0SRandy Fishel  * included here.  For the most part it is only used by the PAM code.
134623ec8b0SRandy Fishel  */
135623ec8b0SRandy Fishel static void
pm_audit_event(adt_session_data_t * ah,au_event_t event_id,int status)136623ec8b0SRandy Fishel pm_audit_event(adt_session_data_t *ah, au_event_t event_id, int status)
137623ec8b0SRandy Fishel {
138623ec8b0SRandy Fishel 	adt_event_data_t	*event;
139623ec8b0SRandy Fishel 
140623ec8b0SRandy Fishel 
141623ec8b0SRandy Fishel 	if ((event = adt_alloc_event(ah, event_id)) == NULL) {
142623ec8b0SRandy Fishel 		return;
143623ec8b0SRandy Fishel 	}
144623ec8b0SRandy Fishel 
145623ec8b0SRandy Fishel 	(void) adt_put_event(event,
146623ec8b0SRandy Fishel 	    status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
147623ec8b0SRandy Fishel 	    status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM + status);
148623ec8b0SRandy Fishel 
149623ec8b0SRandy Fishel 	adt_free_event(event);
150623ec8b0SRandy Fishel }
151623ec8b0SRandy Fishel 
152623ec8b0SRandy Fishel #define	RETRY_COUNT 15
153623ec8b0SRandy Fishel static int
change_audit_file(void)154623ec8b0SRandy Fishel change_audit_file(void)
155623ec8b0SRandy Fishel {
156623ec8b0SRandy Fishel 	pid_t	pid;
157623ec8b0SRandy Fishel 
158623ec8b0SRandy Fishel 	if (!adt_audit_state(AUC_AUDITING)) {
159623ec8b0SRandy Fishel 		/* auditd not running, just return */
160623ec8b0SRandy Fishel 		return (0);
161623ec8b0SRandy Fishel 	}
162623ec8b0SRandy Fishel 
163623ec8b0SRandy Fishel 	if ((pid = fork()) == 0) {
164623ec8b0SRandy Fishel 		(void) execl("/usr/sbin/audit", "audit", "-n", NULL);
165623ec8b0SRandy Fishel 		(void) fprintf(stderr, gettext("error changing audit files: "
166623ec8b0SRandy Fishel 		    "%s\n"), strerror(errno));
167623ec8b0SRandy Fishel 		_exit(-1);
168623ec8b0SRandy Fishel 	} else if (pid == -1) {
169623ec8b0SRandy Fishel 		(void) fprintf(stderr, gettext("error changing audit files: "
170623ec8b0SRandy Fishel 		    "%s\n"), strerror(errno));
171623ec8b0SRandy Fishel 		return (-1);
172623ec8b0SRandy Fishel 	} else {
173623ec8b0SRandy Fishel 		pid_t	rc;
174623ec8b0SRandy Fishel 		int	retries = RETRY_COUNT;
175623ec8b0SRandy Fishel 
176623ec8b0SRandy Fishel 		/*
177bbf21555SRichard Lowe 		 * Wait for audit(8) -n process to complete
178623ec8b0SRandy Fishel 		 *
179623ec8b0SRandy Fishel 		 */
180623ec8b0SRandy Fishel 		do {
181623ec8b0SRandy Fishel 			if ((rc = waitpid(pid, NULL, WNOHANG)) == pid) {
182623ec8b0SRandy Fishel 				return (0);
183623ec8b0SRandy Fishel 			} else if (rc == -1) {
184623ec8b0SRandy Fishel 				return (-1);
185623ec8b0SRandy Fishel 			} else {
186623ec8b0SRandy Fishel 				(void) sleep(1);
187623ec8b0SRandy Fishel 				retries--;
188623ec8b0SRandy Fishel 			}
189623ec8b0SRandy Fishel 
190623ec8b0SRandy Fishel 		} while (retries != 0);
191623ec8b0SRandy Fishel 	}
192623ec8b0SRandy Fishel 	return (-1);
193623ec8b0SRandy Fishel }
194623ec8b0SRandy Fishel 
195623ec8b0SRandy Fishel static void
wait_for_auqueue()196623ec8b0SRandy Fishel wait_for_auqueue()
197623ec8b0SRandy Fishel {
198623ec8b0SRandy Fishel 	au_stat_t	au_stat;
199623ec8b0SRandy Fishel 	int		retries = 10;
200623ec8b0SRandy Fishel 
2013f77e798SToomas Soome 	while (retries-- && auditon(A_GETSTAT, (caddr_t)&au_stat, 0) == 0) {
202623ec8b0SRandy Fishel 		if (au_stat.as_enqueue == au_stat.as_written) {
203623ec8b0SRandy Fishel 			break;
204623ec8b0SRandy Fishel 		}
205623ec8b0SRandy Fishel 		(void) sleep(1);
206623ec8b0SRandy Fishel 	}
207623ec8b0SRandy Fishel }
208623ec8b0SRandy Fishel 
209623ec8b0SRandy Fishel /* End of Audit-related code */
210623ec8b0SRandy Fishel 
211623ec8b0SRandy Fishel /* ARGSUSED0 */
212623ec8b0SRandy Fishel static void
alarm_handler(int sig)213623ec8b0SRandy Fishel alarm_handler(int sig)
214623ec8b0SRandy Fishel {
215623ec8b0SRandy Fishel 	siglongjmp(jmp_stack, 1);
216623ec8b0SRandy Fishel }
217623ec8b0SRandy Fishel 
218623ec8b0SRandy Fishel /*
219623ec8b0SRandy Fishel  * These are functions that would be candidates for moving to a library.
220623ec8b0SRandy Fishel  */
221623ec8b0SRandy Fishel 
222623ec8b0SRandy Fishel /*
223bbf21555SRichard Lowe  * pm_poweroff - similar to poweroff(8)
224bbf21555SRichard Lowe  * This should do the same auditing as poweroff(8) would do when it
225bbf21555SRichard Lowe  * becomes a libpower function.  Till then we use poweroff(8).
226623ec8b0SRandy Fishel  */
227623ec8b0SRandy Fishel static void
pm_poweroff(void)228623ec8b0SRandy Fishel pm_poweroff(void)
229623ec8b0SRandy Fishel {
230623ec8b0SRandy Fishel 	if (chkauthattr(AUTHNAME_SHUTDOWN, user) != 1) {
231623ec8b0SRandy Fishel 		(void) printf(gettext("User %s does not have correct "
232623ec8b0SRandy Fishel 		    "authorizations to shutdown this machine.\n"), user);
233623ec8b0SRandy Fishel 		exit(1);
234623ec8b0SRandy Fishel 	}
235623ec8b0SRandy Fishel 	openlog("suspend", 0, LOG_DAEMON);
236623ec8b0SRandy Fishel 	syslog(LOG_NOTICE, "System is being shut down.");
237623ec8b0SRandy Fishel 	closelog();
238623ec8b0SRandy Fishel 
239623ec8b0SRandy Fishel 	/*
240bbf21555SRichard Lowe 	 * Call poweroff(8) to shut down the system.
241623ec8b0SRandy Fishel 	 */
242623ec8b0SRandy Fishel 	(void) execl("/usr/sbin/poweroff", "poweroff", NULL);
243623ec8b0SRandy Fishel 
244623ec8b0SRandy Fishel }
245623ec8b0SRandy Fishel 
246623ec8b0SRandy Fishel /*
247623ec8b0SRandy Fishel  * pm_check_suspend() - Check to see if suspend is supported/enabled
248623ec8b0SRandy Fishel  * on this machine.
249623ec8b0SRandy Fishel  * Ultimately, we would prefer to get the "default" suspend type from
250623ec8b0SRandy Fishel  * a PM property or some other API, but for now, we know that STR is
251623ec8b0SRandy Fishel  * only available on x86 and STD is only available on Sparc.  It does
252623ec8b0SRandy Fishel  * make this function quite easy, though.
253623ec8b0SRandy Fishel  */
254623ec8b0SRandy Fishel static int
pm_check_suspend(void)2551e655ac4SRichard Lowe pm_check_suspend(void)
2561e655ac4SRichard Lowe {
257623ec8b0SRandy Fishel 	/*
258623ec8b0SRandy Fishel 	 * Use the uadmin(2) "CHECK" command to see if suspend is supported
259623ec8b0SRandy Fishel 	 */
260623ec8b0SRandy Fishel 	return (uadmin(A_FREEZE, AD_CHECK_SUSPEND, 0));
261623ec8b0SRandy Fishel }
262623ec8b0SRandy Fishel 
263623ec8b0SRandy Fishel /*
264623ec8b0SRandy Fishel  * This entry point _should_ be the common entry to suspend.  It is in
265623ec8b0SRandy Fishel  * it's entirety here, but would be best moved to libpower when that
266623ec8b0SRandy Fishel  * is available.
267623ec8b0SRandy Fishel  */
268623ec8b0SRandy Fishel static void
pm_suspend(void)269623ec8b0SRandy Fishel pm_suspend(void)
270623ec8b0SRandy Fishel {
271623ec8b0SRandy Fishel 	int			cprarg = AD_SUSPEND;
272623ec8b0SRandy Fishel 	enum adt_uadmin_fcn	fcn_id = ADT_FCN;
273623ec8b0SRandy Fishel 	au_event_t		event_id = ADT_uadmin_freeze;
274623ec8b0SRandy Fishel 	adt_event_data_t	*event = NULL; /* event to be generated */
275623ec8b0SRandy Fishel 	adt_session_data_t	*ah = NULL;  /* audit session handle */
276623ec8b0SRandy Fishel 
277623ec8b0SRandy Fishel 	/*
278623ec8b0SRandy Fishel 	 * Does the user have permission to use this command?
279623ec8b0SRandy Fishel 	 */
280623ec8b0SRandy Fishel 	if (chkauthattr(AUTHNAME_SUSPEND, user) != 1) {
281623ec8b0SRandy Fishel 		(void) printf(gettext("User %s does not have correct "
282623ec8b0SRandy Fishel 		    "authorizations to suspend this machine.\n"), user);
283623ec8b0SRandy Fishel 		exit(1);
284623ec8b0SRandy Fishel 	}
285623ec8b0SRandy Fishel 
286623ec8b0SRandy Fishel 	if (flags & LOWPOWER) {
287623ec8b0SRandy Fishel 		if (bringto_lowpower() == -1) {
288623ec8b0SRandy Fishel 			(void) printf(gettext("LowPower Failed\n"));
289623ec8b0SRandy Fishel 			exit(1);
290623ec8b0SRandy Fishel 		}
291623ec8b0SRandy Fishel 	} else if (flags & TEST) {
292623ec8b0SRandy Fishel 		/*
293623ec8b0SRandy Fishel 		 * Test mode, do checks as if a real suspend, but
294623ec8b0SRandy Fishel 		 * don't actually do the suspend.
295623ec8b0SRandy Fishel 		 */
296623ec8b0SRandy Fishel 		/* Check if suspend is supported */
297623ec8b0SRandy Fishel 		if (pm_check_suspend() == -1) {
298623ec8b0SRandy Fishel 			suspend_error(errno);
299623ec8b0SRandy Fishel 		}
300623ec8b0SRandy Fishel 
301623ec8b0SRandy Fishel 		(void) printf(gettext("TEST: Suspend would have been"
302623ec8b0SRandy Fishel 		    " performed\n"));
303623ec8b0SRandy Fishel 
304623ec8b0SRandy Fishel 	} else {
305623ec8b0SRandy Fishel 		/* Check if suspend is supported */
306623ec8b0SRandy Fishel 		if (pm_check_suspend() == -1) {
307623ec8b0SRandy Fishel 			suspend_error(errno);
308623ec8b0SRandy Fishel 		}
309623ec8b0SRandy Fishel 
310623ec8b0SRandy Fishel 		/*
311623ec8b0SRandy Fishel 		 * We are about to suspend this machine, try and
312623ec8b0SRandy Fishel 		 * lock the screen.  We don't really care if this
313623ec8b0SRandy Fishel 		 * succeeds or not, but that we actually tried. We
314623ec8b0SRandy Fishel 		 * also know that we have sufficient privileges to
315623ec8b0SRandy Fishel 		 * be here, so we lock the screen now, even if
316623ec8b0SRandy Fishel 		 * suspend actually fails.
317623ec8b0SRandy Fishel 		 * Note that garbage is sometimes displayed, and
318623ec8b0SRandy Fishel 		 * we don't really care about it, so we toss all
319623ec8b0SRandy Fishel 		 * text response.
320623ec8b0SRandy Fishel 		 * it would also be good if there were another option
321623ec8b0SRandy Fishel 		 * instead of launcing a file, as the disk might be
322623ec8b0SRandy Fishel 		 * spun down if we are suspending due to idle.
323623ec8b0SRandy Fishel 		 */
324623ec8b0SRandy Fishel 		if (!(flags & NO_XLOCK)) {
325623ec8b0SRandy Fishel 			(void) system("/usr/bin/xdg-screensaver lock "
326623ec8b0SRandy Fishel 			    " >/dev/null 2>&1");
327623ec8b0SRandy Fishel 		}
328623ec8b0SRandy Fishel 
329623ec8b0SRandy Fishel 		/* Time to do the actual deed!  */
330623ec8b0SRandy Fishel 		/*
331623ec8b0SRandy Fishel 		 * Before we actually suspend, we need to audit and
332623ec8b0SRandy Fishel 		 * "suspend" the audit files.
333623ec8b0SRandy Fishel 		 */
334623ec8b0SRandy Fishel 		/* set up audit session and event */
335623ec8b0SRandy Fishel 		if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) == 0) {
336623ec8b0SRandy Fishel 			if ((event = adt_alloc_event(ah, event_id)) != NULL) {
337623ec8b0SRandy Fishel 				event->adt_uadmin_freeze.fcn = fcn_id;
338623ec8b0SRandy Fishel 				event->adt_uadmin_freeze.mdep = NULL;
339623ec8b0SRandy Fishel 				if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
340623ec8b0SRandy Fishel 					(void) fprintf(stderr, gettext(
341623ec8b0SRandy Fishel 					    "%s: can't put audit event\n"),
342623ec8b0SRandy Fishel 					    argvl[0]);
343623ec8b0SRandy Fishel 				} else {
344623ec8b0SRandy Fishel 					wait_for_auqueue();
345623ec8b0SRandy Fishel 				}
346623ec8b0SRandy Fishel 			}
347623ec8b0SRandy Fishel 			(void) change_audit_file();
348623ec8b0SRandy Fishel 		} else {
349623ec8b0SRandy Fishel 			(void) fprintf(stderr, gettext(
350623ec8b0SRandy Fishel 			    "%s: can't start audit session\n"), argvl[0]);
351623ec8b0SRandy Fishel 		}
352623ec8b0SRandy Fishel 
353623ec8b0SRandy Fishel 		if (uadmin(A_FREEZE, cprarg, 0) != 0) {
354623ec8b0SRandy Fishel 			(void) printf(gettext("Suspend Failed\n"));
355623ec8b0SRandy Fishel 			if (flags & FORCE) {
356623ec8b0SRandy Fishel 				/*
357623ec8b0SRandy Fishel 				 * Note, that if we actually poweroff,
358623ec8b0SRandy Fishel 				 * that the poweroff function will handle
359623ec8b0SRandy Fishel 				 * that audit trail, and the resume
360623ec8b0SRandy Fishel 				 * trail is effectively done.
361623ec8b0SRandy Fishel 				 */
362623ec8b0SRandy Fishel 				pm_poweroff();
363623ec8b0SRandy Fishel 			} else {
364623ec8b0SRandy Fishel 				/* suspend_error() will exit. */
365623ec8b0SRandy Fishel 				suspend_error(errno);
366623ec8b0SRandy Fishel 				/*
367623ec8b0SRandy Fishel 				 * Audit the suspend failure and
368623ec8b0SRandy Fishel 				 * reuse the event, but don't create one
369623ec8b0SRandy Fishel 				 * if we don't already have one.
370623ec8b0SRandy Fishel 				 */
371623ec8b0SRandy Fishel 				if (event != NULL) {
37280148899SSurya Prakki 					(void) adt_put_event(event,
37380148899SSurya Prakki 					    ADT_FAILURE, 0);
374623ec8b0SRandy Fishel 				}
375623ec8b0SRandy Fishel 			}
376623ec8b0SRandy Fishel 		}
377623ec8b0SRandy Fishel 
378623ec8b0SRandy Fishel 		/*
379623ec8b0SRandy Fishel 		 * Write the thaw event.
380623ec8b0SRandy Fishel 		 */
381623ec8b0SRandy Fishel 		if (ah != NULL) {
382623ec8b0SRandy Fishel 			if ((event == NULL) &&
383623ec8b0SRandy Fishel 			    ((event = adt_alloc_event(ah, ADT_uadmin_thaw))
384623ec8b0SRandy Fishel 			    == NULL)) {
385623ec8b0SRandy Fishel 				(void) fprintf(stderr, gettext(
386623ec8b0SRandy Fishel 				    "%s: can't allocate thaw audit event\n"),
387623ec8b0SRandy Fishel 				    argvl[0]);
388623ec8b0SRandy Fishel 			} else {
389623ec8b0SRandy Fishel 				event->adt_uadmin_thaw.fcn = fcn_id;
390623ec8b0SRandy Fishel 				if (adt_put_event(event, ADT_SUCCESS, 0) != 0) {
391623ec8b0SRandy Fishel 					(void) fprintf(stderr, gettext(
392623ec8b0SRandy Fishel 					    "%s: can't put thaw audit event\n"),
393623ec8b0SRandy Fishel 					    argvl[0]);
394623ec8b0SRandy Fishel 				}
395623ec8b0SRandy Fishel 				(void) adt_free_event(event);
396623ec8b0SRandy Fishel 			}
397623ec8b0SRandy Fishel 		}
398623ec8b0SRandy Fishel 	}
399623ec8b0SRandy Fishel 	if ((no_tty ? 0 : 1) && !(flags & NO_XLOCK)) {
400623ec8b0SRandy Fishel 		pm_do_auth(ah);
401623ec8b0SRandy Fishel 	}
402623ec8b0SRandy Fishel 
403623ec8b0SRandy Fishel 	(void) adt_end_session(ah);
404623ec8b0SRandy Fishel }
405623ec8b0SRandy Fishel /* End of "library" functions */
406623ec8b0SRandy Fishel 
407623ec8b0SRandy Fishel /*
408623ec8b0SRandy Fishel  * Print an appropriate error message and exit.
409623ec8b0SRandy Fishel  */
410623ec8b0SRandy Fishel 
411623ec8b0SRandy Fishel static void
suspend_error(int error)4121e655ac4SRichard Lowe suspend_error(int error)
4131e655ac4SRichard Lowe {
414623ec8b0SRandy Fishel 	switch (error) {
415623ec8b0SRandy Fishel 	case EBUSY:
416623ec8b0SRandy Fishel 		(void) printf(gettext("suspend: "
417623ec8b0SRandy Fishel 		    "Suspend already in progress.\n\n"));
418623ec8b0SRandy Fishel 		exit(1);
419623ec8b0SRandy Fishel 		/*NOTREACHED*/
420623ec8b0SRandy Fishel 	case ENOMEM:
421623ec8b0SRandy Fishel 		/*FALLTHROUGH*/
422623ec8b0SRandy Fishel 	case ENOSPC:
423623ec8b0SRandy Fishel 		(void) printf(gettext("suspend: "
424623ec8b0SRandy Fishel 		    "Not enough resources to suspend.\n\n"));
425623ec8b0SRandy Fishel 		exit(1);
426623ec8b0SRandy Fishel 		/*NOTREACHED*/
427623ec8b0SRandy Fishel 	case ENOTSUP:
428623ec8b0SRandy Fishel 		(void) printf(gettext("suspend: "
429623ec8b0SRandy Fishel 		    "Suspend is not supported.\n\n"));
430623ec8b0SRandy Fishel 		exit(1);
431623ec8b0SRandy Fishel 		/*NOTREACHED*/
432623ec8b0SRandy Fishel 	case EPERM:
433623ec8b0SRandy Fishel 		(void) printf(gettext("suspend: "
434623ec8b0SRandy Fishel 		    "Not sufficient privileges.\n\n"));
435623ec8b0SRandy Fishel 		exit(1);
436623ec8b0SRandy Fishel 		/*NOTREACHED*/
437623ec8b0SRandy Fishel 	default:
438623ec8b0SRandy Fishel 		(void) printf(gettext("suspend: "
439623ec8b0SRandy Fishel 		    "unknown error.\n\n"));
440623ec8b0SRandy Fishel 		exit(1);
441623ec8b0SRandy Fishel 	}
442623ec8b0SRandy Fishel 
443623ec8b0SRandy Fishel }
444623ec8b0SRandy Fishel 
445623ec8b0SRandy Fishel /*
446623ec8b0SRandy Fishel  * refresh_dt() - Refresh screen when 'dtgreet' is running.
447623ec8b0SRandy Fishel  * This is here for compatibility reasons, and could be removed once
448623ec8b0SRandy Fishel  * dtgreet is no longer part of the system.
449623ec8b0SRandy Fishel  */
450623ec8b0SRandy Fishel static int
refresh_dt()451623ec8b0SRandy Fishel refresh_dt()
452623ec8b0SRandy Fishel {
453623ec8b0SRandy Fishel 	int	status;
454623ec8b0SRandy Fishel 	struct stat	stat_buf;
455623ec8b0SRandy Fishel 
456623ec8b0SRandy Fishel 	/*
457623ec8b0SRandy Fishel 	 * If dtgreet exists, HUP it, otherwise just let screenlock
458623ec8b0SRandy Fishel 	 * do it's thing.
459623ec8b0SRandy Fishel 	 */
460623ec8b0SRandy Fishel 	if ((stat("/usr/dt/bin/dtgreet", &stat_buf) == 0) &&
461623ec8b0SRandy Fishel 	    (stat_buf.st_mode & S_IXUSR)) {
462623ec8b0SRandy Fishel 		switch (fork()) {
463623ec8b0SRandy Fishel 		case -1:
464623ec8b0SRandy Fishel 			break;
465623ec8b0SRandy Fishel 		case 0:
466623ec8b0SRandy Fishel 			(void) close(1);
467623ec8b0SRandy Fishel 			(void) execl("/usr/bin/pkill", "pkill",
468623ec8b0SRandy Fishel 			    "-HUP", "-u", "0", "-x", "dtgreet", NULL);
469623ec8b0SRandy Fishel 			break;
470623ec8b0SRandy Fishel 		default:
471623ec8b0SRandy Fishel 			(void) wait(&status);
472623ec8b0SRandy Fishel 		}
473623ec8b0SRandy Fishel 	}
474623ec8b0SRandy Fishel 
475623ec8b0SRandy Fishel 	return (0);
476623ec8b0SRandy Fishel }
477623ec8b0SRandy Fishel 
478623ec8b0SRandy Fishel #define	DT_TMP	"/var/dt/tmp"
479623ec8b0SRandy Fishel 
480623ec8b0SRandy Fishel /*
481623ec8b0SRandy Fishel  * On enter, the "xauthority" string has the value "XAUTHORITY=".  On
482623ec8b0SRandy Fishel  * return, if a Xauthority file is found, concatenate it to this string,
483623ec8b0SRandy Fishel  * otherwise, return "xauthority" as it is.
484623ec8b0SRandy Fishel  */
485623ec8b0SRandy Fishel static char *
get_xauthority(char * xauthority,size_t buflen)4861e655ac4SRichard Lowe get_xauthority(char *xauthority, size_t buflen)
487623ec8b0SRandy Fishel {
488623ec8b0SRandy Fishel 	pid_t uid;
489623ec8b0SRandy Fishel 	char *home_dir;
490623ec8b0SRandy Fishel 	struct passwd *pwd;
491623ec8b0SRandy Fishel 	char filepath[MAXPATHLEN];
492623ec8b0SRandy Fishel 	struct stat stat_buf;
493623ec8b0SRandy Fishel 	DIR *dirp;
494623ec8b0SRandy Fishel 	struct dirent *dp;
495623ec8b0SRandy Fishel 	char xauth[MAXPATHLEN] = "";
496623ec8b0SRandy Fishel 	time_t latest = 0;
497623ec8b0SRandy Fishel 
498623ec8b0SRandy Fishel 	uid = getuid();
499623ec8b0SRandy Fishel 
500623ec8b0SRandy Fishel 	/*
501623ec8b0SRandy Fishel 	 * Determine home directory of the user.
502623ec8b0SRandy Fishel 	 */
503623ec8b0SRandy Fishel 	if ((home_dir = getenv("HOME")) == NULL) {
504623ec8b0SRandy Fishel 		if ((pwd = getpwuid(uid)) == NULL) {
50580148899SSurya Prakki 			(void) printf(gettext("Error: unable to get passwd "
506623ec8b0SRandy Fishel 			    "entry for user.\n"));
507623ec8b0SRandy Fishel 			exit(1);
508623ec8b0SRandy Fishel 		}
509623ec8b0SRandy Fishel 		home_dir = pwd->pw_dir;
510623ec8b0SRandy Fishel 	}
511623ec8b0SRandy Fishel 	if ((strlen(home_dir) + sizeof ("/.Xauthority")) >= MAXPATHLEN) {
51280148899SSurya Prakki 		(void) printf(gettext("Error: path to home directory is too "
513623ec8b0SRandy Fishel 		    "long.\n"));
514623ec8b0SRandy Fishel 		exit(1);
515623ec8b0SRandy Fishel 	}
516623ec8b0SRandy Fishel 
517623ec8b0SRandy Fishel 	/*
518623ec8b0SRandy Fishel 	 * If there is a .Xauthority file in home directory, reference it.
519623ec8b0SRandy Fishel 	 */
5201e655ac4SRichard Lowe 	(void) snprintf(filepath, sizeof (filepath),
5211e655ac4SRichard Lowe 	    "%s/.Xauthority", home_dir);
5221e655ac4SRichard Lowe 	if (stat(filepath, &stat_buf) == 0) {
5231e655ac4SRichard Lowe 		(void) strlcpy(xauthority, filepath, buflen);
5241e655ac4SRichard Lowe 		return (xauthority);
5251e655ac4SRichard Lowe 	}
526623ec8b0SRandy Fishel 
527623ec8b0SRandy Fishel 	/*
528623ec8b0SRandy Fishel 	 * If Xsession can not access user's home directory, it creates the
529623ec8b0SRandy Fishel 	 * Xauthority file in "/var/dt/tmp" directory.  Since the exact
530623ec8b0SRandy Fishel 	 * name of the Xauthority is not known, search the directory and
531623ec8b0SRandy Fishel 	 * find the last changed file that starts with ".Xauth" and owned
532623ec8b0SRandy Fishel 	 * by the user.  Hopefully, that is the valid Xauthority file for
533623ec8b0SRandy Fishel 	 * the current X session.
534623ec8b0SRandy Fishel 	 */
535623ec8b0SRandy Fishel 	if ((dirp = opendir(DT_TMP)) == NULL)
536623ec8b0SRandy Fishel 		return (xauthority);
537623ec8b0SRandy Fishel 
538623ec8b0SRandy Fishel 	while ((dp = readdir(dirp)) != NULL) {
539623ec8b0SRandy Fishel 		if (strstr(dp->d_name, ".Xauth") != NULL) {
5401e655ac4SRichard Lowe 			(void) snprintf(filepath, sizeof (filepath),
5411e655ac4SRichard Lowe 			    "%s/%s", DT_TMP, dp->d_name);
542623ec8b0SRandy Fishel 			if (stat(filepath, &stat_buf) == -1)
543623ec8b0SRandy Fishel 				continue;
544623ec8b0SRandy Fishel 			if (stat_buf.st_uid != uid)
545623ec8b0SRandy Fishel 				continue;
546623ec8b0SRandy Fishel 			if (stat_buf.st_ctime > latest) {
5471e655ac4SRichard Lowe 				(void) strlcpy(xauth, filepath,
5481e655ac4SRichard Lowe 				    sizeof (xauth));
549623ec8b0SRandy Fishel 				latest = stat_buf.st_ctime;
550623ec8b0SRandy Fishel 			}
551623ec8b0SRandy Fishel 		}
552623ec8b0SRandy Fishel 	}
553623ec8b0SRandy Fishel 	(void) closedir(dirp);
554623ec8b0SRandy Fishel 
5551e655ac4SRichard Lowe 	(void) strlcpy(xauthority, xauth, buflen);
5561e655ac4SRichard Lowe 	return (xauthority);
557623ec8b0SRandy Fishel }
558623ec8b0SRandy Fishel 
559623ec8b0SRandy Fishel /*
560623ec8b0SRandy Fishel  * suspend can be called in following ways:
561623ec8b0SRandy Fishel  *	1. from daemon (powerd) for auto-shutdown.
562623ec8b0SRandy Fishel  *		a. there might be a OW/CDE environment
563623ec8b0SRandy Fishel  *		b. there might not be any windowing environment
564623ec8b0SRandy Fishel  *      2. by a user entered command.
565623ec8b0SRandy Fishel  *		a. the command can be entered from a cmdtool type OW/CDE tool
566623ec8b0SRandy Fishel  *		b. the command can be entered by a user logged in on a dumb
567623ec8b0SRandy Fishel  *		   terminal.
568623ec8b0SRandy Fishel  *			i) there might be a OW/CDE running on console
569623ec8b0SRandy Fishel  *			   and we have permission to talk to it.
570623ec8b0SRandy Fishel  *			ii) there is no OW/CDE running on console or we
571623ec8b0SRandy Fishel  *			   don't have permission to talk to it or console
572623ec8b0SRandy Fishel  *			   itself is the dumb terminal we have logged into.
573623ec8b0SRandy Fishel  *
574623ec8b0SRandy Fishel  * In main(), we decide on the correct case and call appropriate functions.
575623ec8b0SRandy Fishel  */
576623ec8b0SRandy Fishel 
577623ec8b0SRandy Fishel int
main(int argc,char ** argv)578623ec8b0SRandy Fishel main(int argc, char **argv)
579623ec8b0SRandy Fishel {
580623ec8b0SRandy Fishel 	int		c;
5811e655ac4SRichard Lowe 	char		xauthority[MAXPATHLEN];
582623ec8b0SRandy Fishel 	struct passwd	*pw;
583623ec8b0SRandy Fishel 
5845009f788SIgor Kozhukhov 	(void) signal(SIGHUP, SIG_IGN);
5855009f788SIgor Kozhukhov 	(void) signal(SIGINT, SIG_IGN);
5865009f788SIgor Kozhukhov 	(void) signal(SIGQUIT, SIG_IGN);
5875009f788SIgor Kozhukhov 	(void) signal(SIGTSTP, SIG_IGN);
5885009f788SIgor Kozhukhov 	(void) signal(SIGTTIN, SIG_IGN);
5895009f788SIgor Kozhukhov 	(void) signal(SIGTTOU, SIG_IGN);
590623ec8b0SRandy Fishel 
591623ec8b0SRandy Fishel 	/*
592623ec8b0SRandy Fishel 	 * If suspend is invoked from a daemon (case 1 above), it
593623ec8b0SRandy Fishel 	 * will not have a working stdin, stdout and stderr. We need
594623ec8b0SRandy Fishel 	 * these to print proper error messages and possibly get user
595623ec8b0SRandy Fishel 	 * input. We attach them to console and hope that attachment
596623ec8b0SRandy Fishel 	 * works.
597623ec8b0SRandy Fishel 	 */
598623ec8b0SRandy Fishel 	if (ttyname(0) == NULL) {
599623ec8b0SRandy Fishel 		no_tty = 1;
60080148899SSurya Prakki 		(void) dup2(open("/dev/console", O_RDONLY), 0);
60180148899SSurya Prakki 		(void) dup2(open("/dev/console", O_WRONLY), 1);
60280148899SSurya Prakki 		(void) dup2(open("/dev/console", O_WRONLY), 2);
603623ec8b0SRandy Fishel 	}
604623ec8b0SRandy Fishel 
605623ec8b0SRandy Fishel 	while ((c = getopt(argc, argv, "fnxhtd:")) != EOF) {
606623ec8b0SRandy Fishel 		switch (c) {
607623ec8b0SRandy Fishel 			case 'f':
608623ec8b0SRandy Fishel 				/*
609623ec8b0SRandy Fishel 				 * Force machine to poweroff if
610623ec8b0SRandy Fishel 				 * suspend fails
611623ec8b0SRandy Fishel 				 */
612623ec8b0SRandy Fishel 				flags |= FORCE;
613623ec8b0SRandy Fishel 				break;
614623ec8b0SRandy Fishel 			case 'n':
615623ec8b0SRandy Fishel 				/* No warning popups - Obsolete */
616623ec8b0SRandy Fishel 				flags |= NO_WARN;
617623ec8b0SRandy Fishel 				break;
618623ec8b0SRandy Fishel 			case 'x':
619623ec8b0SRandy Fishel 				/* Don't try to screenlock */
620623ec8b0SRandy Fishel 				flags |= NO_XLOCK;
621623ec8b0SRandy Fishel 				break;
622623ec8b0SRandy Fishel 			case 'h':
623623ec8b0SRandy Fishel 				/* Do a shutdown instead of suspend */
624623ec8b0SRandy Fishel 				flags |= SHUTDOWN;
625623ec8b0SRandy Fishel 				break;
626623ec8b0SRandy Fishel 			case 'd':
627623ec8b0SRandy Fishel 				/* Set the DISPLAY value in the environment */
6281e655ac4SRichard Lowe 				if (setenv("DISPLAY", optarg, 1) != 0) {
629623ec8b0SRandy Fishel 					(void) printf(gettext("Error: "
630623ec8b0SRandy Fishel 					    "unable to set DISPLAY "
631623ec8b0SRandy Fishel 					    "environment variable.\n"));
632623ec8b0SRandy Fishel 					return (1);
633623ec8b0SRandy Fishel 				}
634623ec8b0SRandy Fishel 				break;
635623ec8b0SRandy Fishel 			case 't':
636623ec8b0SRandy Fishel 				/* Test, don't actually do any operation */
637623ec8b0SRandy Fishel 				flags |= TEST;
638623ec8b0SRandy Fishel 				break;
639623ec8b0SRandy Fishel 			default:
640623ec8b0SRandy Fishel 				(void) printf(gettext("USAGE: suspend "
641623ec8b0SRandy Fishel 				    "[-fnxh] [-d <display>]\n"));
642623ec8b0SRandy Fishel 				return (1);
643623ec8b0SRandy Fishel 		}
644623ec8b0SRandy Fishel 	}
645623ec8b0SRandy Fishel 
646623ec8b0SRandy Fishel 	/*
647623ec8b0SRandy Fishel 	 * The action of pressing power key and power button on a MOU-3 machine
648623ec8b0SRandy Fishel 	 * causes suspend being invoked with SYSSUSPENDDODEFAULT
649623ec8b0SRandy Fishel 	 * enviromental variable set - indicating the default action is machine
650623ec8b0SRandy Fishel 	 * dependent: for MOU-3 type machine, "LowPower" mode is the default,
651623ec8b0SRandy Fishel 	 * for all the rest, "Suspend" is the default.  Existing suspend
652623ec8b0SRandy Fishel 	 * flags works the same.
653623ec8b0SRandy Fishel 	 */
654623ec8b0SRandy Fishel 	if (getenv("SYSSUSPENDDODEFAULT"))
655623ec8b0SRandy Fishel 		if (is_mou3())
656623ec8b0SRandy Fishel 			flags |= LOWPOWER;
657623ec8b0SRandy Fishel 
658623ec8b0SRandy Fishel 	if ((flags & FORCE) && (flags & LOWPOWER))
659623ec8b0SRandy Fishel 		flags &= ~LOWPOWER;
660623ec8b0SRandy Fishel 
661623ec8b0SRandy Fishel 	/*
662623ec8b0SRandy Fishel 	 * Flag "-h" overrides flag "-f".
663623ec8b0SRandy Fishel 	 */
664623ec8b0SRandy Fishel 	if ((flags & SHUTDOWN) && (flags & FORCE))
665623ec8b0SRandy Fishel 		flags &= ~(FORCE | LOWPOWER);
666623ec8b0SRandy Fishel 
667623ec8b0SRandy Fishel 	if (flags & FORCE)
668623ec8b0SRandy Fishel 		flags |= NO_WARN;
669623ec8b0SRandy Fishel 
670623ec8b0SRandy Fishel 	/*
671623ec8b0SRandy Fishel 	 * Check initally if the user has the authorizations to
672623ec8b0SRandy Fishel 	 * do either a suspend or shutdown.  pm_suspend() will also
673623ec8b0SRandy Fishel 	 * make this test, so we could defer till then, but if we
674623ec8b0SRandy Fishel 	 * do it now, we at least prevent a lot of unneeded setup.
675623ec8b0SRandy Fishel 	 */
676623ec8b0SRandy Fishel 	pw = getpwuid(getuid());
67780148899SSurya Prakki 	(void) strncpy(user, pw->pw_name, NMAX);
678623ec8b0SRandy Fishel 
679623ec8b0SRandy Fishel 	if ((flags & (FORCE|SHUTDOWN)) &&
680623ec8b0SRandy Fishel 	    (chkauthattr(AUTHNAME_SHUTDOWN, pw->pw_name) != 1)) {
681623ec8b0SRandy Fishel 		(void) printf(gettext("User does not have correct "
682623ec8b0SRandy Fishel 		    "authorizations to shutdown the machine.\n"));
683623ec8b0SRandy Fishel 		exit(1);
684623ec8b0SRandy Fishel 	}
685623ec8b0SRandy Fishel 	if (!(flags & SHUTDOWN) &&
686623ec8b0SRandy Fishel 	    (chkauthattr(AUTHNAME_SUSPEND, pw->pw_name) != 1)) {
687623ec8b0SRandy Fishel 		(void) printf(gettext("User does not have correct "
688623ec8b0SRandy Fishel 		    "authorizations to suspend.\n"));
689623ec8b0SRandy Fishel 		exit(1);
690623ec8b0SRandy Fishel 	}
691623ec8b0SRandy Fishel 
692623ec8b0SRandy Fishel 	/*
693623ec8b0SRandy Fishel 	 * If we are only shutting down, there isn't much to do, just
694623ec8b0SRandy Fishel 	 * call pm_poweroff(), and let it do all the work.
695623ec8b0SRandy Fishel 	 */
696623ec8b0SRandy Fishel 	if (flags & SHUTDOWN) {
697623ec8b0SRandy Fishel 		/*
698623ec8b0SRandy Fishel 		 * pm_poweroff either powers off or exits,
699623ec8b0SRandy Fishel 		 * so there is no return.
700623ec8b0SRandy Fishel 		 */
701623ec8b0SRandy Fishel 		if (flags & TEST) {
702623ec8b0SRandy Fishel 			(void) printf("TEST: This machine would have "
703623ec8b0SRandy Fishel 			    "powered off\n");
704623ec8b0SRandy Fishel 			exit(1);
705623ec8b0SRandy Fishel 		} else {
706623ec8b0SRandy Fishel 			pm_poweroff();
707623ec8b0SRandy Fishel 		}
708623ec8b0SRandy Fishel 		/* NOTREACHED */
709623ec8b0SRandy Fishel 	}
710623ec8b0SRandy Fishel 
711623ec8b0SRandy Fishel 	/*
712623ec8b0SRandy Fishel 	 * If XAUTHORITY environment variable is not set, try to set
713623ec8b0SRandy Fishel 	 * one up.
714623ec8b0SRandy Fishel 	 */
715623ec8b0SRandy Fishel 	if (getenv("XAUTHORITY") == NULL)
7161e655ac4SRichard Lowe 		(void) setenv("XAUTHORITY",
7171e655ac4SRichard Lowe 		    get_xauthority(xauthority, MAXPATHLEN), 1);
718623ec8b0SRandy Fishel 
719623ec8b0SRandy Fishel 	/*
720623ec8b0SRandy Fishel 	 * In case of "suspend" being called from daemon "powerd",
721623ec8b0SRandy Fishel 	 * signal SIGALRM is blocked so use "sigset()" instead of "signal()".
722623ec8b0SRandy Fishel 	 */
7235009f788SIgor Kozhukhov 	(void) sigset(SIGALRM, alarm_handler);
724623ec8b0SRandy Fishel 
725623ec8b0SRandy Fishel 	/* Call the "suspend" function to do the last of the work */
726623ec8b0SRandy Fishel 	pm_suspend();
727623ec8b0SRandy Fishel 
728623ec8b0SRandy Fishel 	if (refresh_dt() == -1) {
72980148899SSurya Prakki 		(void) printf("%s: Failed to refresh screen.\n", argv[0]);
730623ec8b0SRandy Fishel 		return (1);
731623ec8b0SRandy Fishel 	}
732623ec8b0SRandy Fishel 	return (0);
733623ec8b0SRandy Fishel }
734623ec8b0SRandy Fishel 
735623ec8b0SRandy Fishel #include <sys/pm.h>
736623ec8b0SRandy Fishel 
737623ec8b0SRandy Fishel /*
738623ec8b0SRandy Fishel  * Note that some of these functions are more relevant to Sparc platforms,
739623ec8b0SRandy Fishel  * but they do function properly on other platforms, they just don't do
740623ec8b0SRandy Fishel  * as much.
741623ec8b0SRandy Fishel  */
742623ec8b0SRandy Fishel /*
743623ec8b0SRandy Fishel  * bringto_lowpower()
744623ec8b0SRandy Fishel  * This tells the PM framework to put the devices it controls in an idle
745623ec8b0SRandy Fishel  * state.  The framework only complains if a device that *must* be idle
746623ec8b0SRandy Fishel  * doesn't succeed in getting there.
747623ec8b0SRandy Fishel  */
748623ec8b0SRandy Fishel static int
bringto_lowpower()749623ec8b0SRandy Fishel bringto_lowpower()
750623ec8b0SRandy Fishel {
751623ec8b0SRandy Fishel 	int	fd;
752623ec8b0SRandy Fishel 
753623ec8b0SRandy Fishel 	if ((fd = open("/dev/pm", O_RDWR)) < 0) {
75480148899SSurya Prakki 		(void) printf(gettext("Can't open /dev/pm\n"));
755623ec8b0SRandy Fishel 		return (-1);
756623ec8b0SRandy Fishel 	}
757623ec8b0SRandy Fishel 
758623ec8b0SRandy Fishel 	if (ioctl(fd, PM_IDLE_DOWN, NULL) < 0) {
75980148899SSurya Prakki 		(void) printf(gettext("Failed to bring system "
76080148899SSurya Prakki 		    "to low power mode.\n"));
76180148899SSurya Prakki 		(void) close(fd);
762623ec8b0SRandy Fishel 		return (-1);
763623ec8b0SRandy Fishel 	}
76480148899SSurya Prakki 	(void) close(fd);
765623ec8b0SRandy Fishel 	return (0);
766623ec8b0SRandy Fishel }
767623ec8b0SRandy Fishel 
768623ec8b0SRandy Fishel #include <sys/cpr.h>
769623ec8b0SRandy Fishel 
770623ec8b0SRandy Fishel /*
771623ec8b0SRandy Fishel  * Though this test is predominantly used on Sparc, it will run on other
772623ec8b0SRandy Fishel  * platforms, and might be usefull one day on those.
773623ec8b0SRandy Fishel  */
774623ec8b0SRandy Fishel static int
is_mou3()775623ec8b0SRandy Fishel is_mou3()
776623ec8b0SRandy Fishel {
777623ec8b0SRandy Fishel 	struct cprconfig	cf;
778623ec8b0SRandy Fishel 	int			fd;
779623ec8b0SRandy Fishel 	int			found = 0;
780623ec8b0SRandy Fishel 
781623ec8b0SRandy Fishel 	if ((fd = open(CPR_CONFIG, O_RDONLY)) < 0) {
78280148899SSurya Prakki 		(void) printf(gettext("Can't open /etc/.cpr_config file."));
783623ec8b0SRandy Fishel 		return (found);
784623ec8b0SRandy Fishel 	}
785623ec8b0SRandy Fishel 
786623ec8b0SRandy Fishel 	if (read(fd, (void *) &cf, sizeof (cf)) != sizeof (cf)) {
78780148899SSurya Prakki 		(void) printf(gettext("Can't read /etc/.cpr_config file."));
788623ec8b0SRandy Fishel 	} else {
789623ec8b0SRandy Fishel 		found = cf.is_autopm_default;
790623ec8b0SRandy Fishel 	}
791623ec8b0SRandy Fishel 
79280148899SSurya Prakki 	(void) close(fd);
793623ec8b0SRandy Fishel 	return (found);
794623ec8b0SRandy Fishel }
795623ec8b0SRandy Fishel 
796623ec8b0SRandy Fishel /*
797623ec8b0SRandy Fishel  * Reauthenticate the user on return from suspend.
798623ec8b0SRandy Fishel  * This is here and not in the PAM-specific file, as there are
799623ec8b0SRandy Fishel  * items specific to sys-suspend, and not generic to PAM.  This may
800623ec8b0SRandy Fishel  * become part of a future PM library.  The audit handle is passed,
801623ec8b0SRandy Fishel  * as the pm_suspend code actually starts an audit session, so it
802623ec8b0SRandy Fishel  * makes sense to just continue to use it.  If it were separated
803623ec8b0SRandy Fishel  * from the pm_suspend code, it will need to open a new session.
804623ec8b0SRandy Fishel  */
805623ec8b0SRandy Fishel #define	DEF_ATTEMPTS	3
806623ec8b0SRandy Fishel static void
pm_do_auth(adt_session_data_t * ah)807623ec8b0SRandy Fishel pm_do_auth(adt_session_data_t *ah)
808623ec8b0SRandy Fishel {
809623ec8b0SRandy Fishel 	pam_handle_t	*pm_pamh;
810623ec8b0SRandy Fishel 	int		err;
811623ec8b0SRandy Fishel 	int		pam_flag = 0;
812623ec8b0SRandy Fishel 	int		chpasswd_tries;
813623ec8b0SRandy Fishel 	struct pam_conv pam_conv = {pam_tty_conv, NULL};
814623ec8b0SRandy Fishel 
815623ec8b0SRandy Fishel 	if (user[0] == '\0')
816623ec8b0SRandy Fishel 		return;
817623ec8b0SRandy Fishel 
818623ec8b0SRandy Fishel 	if ((err = pam_start("sys-suspend", user, &pam_conv,
819623ec8b0SRandy Fishel 	    &pm_pamh)) != PAM_SUCCESS)
820623ec8b0SRandy Fishel 		return;
821623ec8b0SRandy Fishel 
822623ec8b0SRandy Fishel 	pam_flag = PAM_DISALLOW_NULL_AUTHTOK;
823623ec8b0SRandy Fishel 
824623ec8b0SRandy Fishel 	do {
825623ec8b0SRandy Fishel 		err = pam_authenticate(pm_pamh, pam_flag);
826623ec8b0SRandy Fishel 
827623ec8b0SRandy Fishel 		if (err == PAM_SUCCESS) {
828623ec8b0SRandy Fishel 			err = pam_acct_mgmt(pm_pamh, pam_flag);
829623ec8b0SRandy Fishel 
830623ec8b0SRandy Fishel 			if (err == PAM_NEW_AUTHTOK_REQD) {
831623ec8b0SRandy Fishel 				chpasswd_tries = 0;
832623ec8b0SRandy Fishel 
833623ec8b0SRandy Fishel 				do {
834623ec8b0SRandy Fishel 					err = pam_chauthtok(pm_pamh,
835623ec8b0SRandy Fishel 					    PAM_CHANGE_EXPIRED_AUTHTOK);
836623ec8b0SRandy Fishel 					chpasswd_tries++;
837623ec8b0SRandy Fishel 
838623ec8b0SRandy Fishel 				} while ((err == PAM_AUTHTOK_ERR ||
839623ec8b0SRandy Fishel 				    err == PAM_TRY_AGAIN) &&
840623ec8b0SRandy Fishel 				    chpasswd_tries < DEF_ATTEMPTS);
841623ec8b0SRandy Fishel 				pm_audit_event(ah, ADT_passwd, err);
842623ec8b0SRandy Fishel 			}
843623ec8b0SRandy Fishel 			err = pam_setcred(pm_pamh, PAM_REFRESH_CRED);
844623ec8b0SRandy Fishel 		}
845623ec8b0SRandy Fishel 		if (err != PAM_SUCCESS) {
846623ec8b0SRandy Fishel 			(void) fprintf(stdout, "%s\n",
847623ec8b0SRandy Fishel 			    pam_strerror(pm_pamh, err));
848623ec8b0SRandy Fishel 			pm_audit_event(ah, ADT_screenunlock, err);
849623ec8b0SRandy Fishel 		}
850623ec8b0SRandy Fishel 	} while (err != PAM_SUCCESS);
851623ec8b0SRandy Fishel 	pm_audit_event(ah, ADT_passwd, 0);
852623ec8b0SRandy Fishel 
853623ec8b0SRandy Fishel 	(void) pam_end(pm_pamh, err);
854623ec8b0SRandy Fishel }
855