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