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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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