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