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