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 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 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 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 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 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 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 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 adt_put_event(event, ADT_FAILURE, 0); 370 } 371 } 372 } 373 374 /* 375 * Write the thaw event. 376 */ 377 if (ah != NULL) { 378 if ((event == NULL) && 379 ((event = adt_alloc_event(ah, ADT_uadmin_thaw)) 380 == NULL)) { 381 (void) fprintf(stderr, gettext( 382 "%s: can't allocate thaw audit event\n"), 383 argvl[0]); 384 } else { 385 event->adt_uadmin_thaw.fcn = fcn_id; 386 if (adt_put_event(event, ADT_SUCCESS, 0) != 0) { 387 (void) fprintf(stderr, gettext( 388 "%s: can't put thaw audit event\n"), 389 argvl[0]); 390 } 391 (void) adt_free_event(event); 392 } 393 } 394 } 395 if ((no_tty ? 0 : 1) && !(flags & NO_XLOCK)) { 396 pm_do_auth(ah); 397 } 398 399 (void) adt_end_session(ah); 400 } 401 /* End of "library" functions */ 402 403 /* 404 * Print an appropriate error message and exit. 405 */ 406 407 static void 408 suspend_error(int error) { 409 410 switch (error) { 411 case EBUSY: 412 (void) printf(gettext("suspend: " 413 "Suspend already in progress.\n\n")); 414 exit(1); 415 /*NOTREACHED*/ 416 case ENOMEM: 417 /*FALLTHROUGH*/ 418 case ENOSPC: 419 (void) printf(gettext("suspend: " 420 "Not enough resources to suspend.\n\n")); 421 exit(1); 422 /*NOTREACHED*/ 423 case ENOTSUP: 424 (void) printf(gettext("suspend: " 425 "Suspend is not supported.\n\n")); 426 exit(1); 427 /*NOTREACHED*/ 428 case EPERM: 429 (void) printf(gettext("suspend: " 430 "Not sufficient privileges.\n\n")); 431 exit(1); 432 /*NOTREACHED*/ 433 default: 434 (void) printf(gettext("suspend: " 435 "unknown error.\n\n")); 436 exit(1); 437 } 438 439 } 440 441 /* 442 * refresh_dt() - Refresh screen when 'dtgreet' is running. 443 * This is here for compatibility reasons, and could be removed once 444 * dtgreet is no longer part of the system. 445 */ 446 static int 447 refresh_dt() 448 { 449 int status; 450 struct stat stat_buf; 451 452 /* 453 * If dtgreet exists, HUP it, otherwise just let screenlock 454 * do it's thing. 455 */ 456 if ((stat("/usr/dt/bin/dtgreet", &stat_buf) == 0) && 457 (stat_buf.st_mode & S_IXUSR)) { 458 switch (fork()) { 459 case -1: 460 break; 461 case 0: 462 (void) close(1); 463 (void) execl("/usr/bin/pkill", "pkill", 464 "-HUP", "-u", "0", "-x", "dtgreet", NULL); 465 break; 466 default: 467 (void) wait(&status); 468 } 469 } 470 471 return (0); 472 } 473 474 #define DT_TMP "/var/dt/tmp" 475 476 /* 477 * On enter, the "xauthority" string has the value "XAUTHORITY=". On 478 * return, if a Xauthority file is found, concatenate it to this string, 479 * otherwise, return "xauthority" as it is. 480 */ 481 static char * 482 get_xauthority(char *xauthority) 483 { 484 pid_t uid; 485 char *home_dir; 486 struct passwd *pwd; 487 char filepath[MAXPATHLEN]; 488 struct stat stat_buf; 489 DIR *dirp; 490 struct dirent *dp; 491 char xauth[MAXPATHLEN] = ""; 492 time_t latest = 0; 493 494 uid = getuid(); 495 496 /* 497 * Determine home directory of the user. 498 */ 499 if ((home_dir = getenv("HOME")) == NULL) { 500 if ((pwd = getpwuid(uid)) == NULL) { 501 printf(gettext("Error: unable to get passwd " 502 "entry for user.\n")); 503 exit(1); 504 } 505 home_dir = pwd->pw_dir; 506 } 507 if ((strlen(home_dir) + sizeof ("/.Xauthority")) >= MAXPATHLEN) { 508 printf(gettext("Error: path to home directory is too " 509 "long.\n")); 510 exit(1); 511 } 512 513 /* 514 * If there is a .Xauthority file in home directory, reference it. 515 */ 516 /*LINTED*/ 517 (void) sprintf(filepath, "%s/.Xauthority", home_dir); 518 if (stat(filepath, &stat_buf) == 0) 519 return (strcat(xauthority, filepath)); 520 521 /* 522 * If Xsession can not access user's home directory, it creates the 523 * Xauthority file in "/var/dt/tmp" directory. Since the exact 524 * name of the Xauthority is not known, search the directory and 525 * find the last changed file that starts with ".Xauth" and owned 526 * by the user. Hopefully, that is the valid Xauthority file for 527 * the current X session. 528 */ 529 if ((dirp = opendir(DT_TMP)) == NULL) 530 return (xauthority); 531 532 while ((dp = readdir(dirp)) != NULL) { 533 if (strstr(dp->d_name, ".Xauth") != NULL) { 534 /*LINTED*/ 535 (void) sprintf(filepath, "%s/%s", DT_TMP, dp->d_name); 536 if (stat(filepath, &stat_buf) == -1) 537 continue; 538 if (stat_buf.st_uid != uid) 539 continue; 540 if (stat_buf.st_ctime > latest) { 541 (void) strcpy(xauth, filepath); 542 latest = stat_buf.st_ctime; 543 } 544 } 545 } 546 (void) closedir(dirp); 547 548 return (strcat(xauthority, xauth)); 549 } 550 551 /* 552 * suspend can be called in following ways: 553 * 1. from daemon (powerd) for auto-shutdown. 554 * a. there might be a OW/CDE environment 555 * b. there might not be any windowing environment 556 * 2. by a user entered command. 557 * a. the command can be entered from a cmdtool type OW/CDE tool 558 * b. the command can be entered by a user logged in on a dumb 559 * terminal. 560 * i) there might be a OW/CDE running on console 561 * and we have permission to talk to it. 562 * ii) there is no OW/CDE running on console or we 563 * don't have permission to talk to it or console 564 * itself is the dumb terminal we have logged into. 565 * 566 * In main(), we decide on the correct case and call appropriate functions. 567 */ 568 569 int 570 main(int argc, char **argv) 571 { 572 int c; 573 char display_name[MAXNAMELEN + 9] = "DISPLAY="; 574 char xauthority[MAXPATHLEN + 12] = "XAUTHORITY="; 575 struct passwd *pw; 576 577 (void *) signal(SIGHUP, SIG_IGN); 578 (void *) signal(SIGINT, SIG_IGN); 579 (void *) signal(SIGQUIT, SIG_IGN); 580 (void *) signal(SIGTSTP, SIG_IGN); 581 (void *) signal(SIGTTIN, SIG_IGN); 582 (void *) signal(SIGTTOU, SIG_IGN); 583 584 /* 585 * If suspend is invoked from a daemon (case 1 above), it 586 * will not have a working stdin, stdout and stderr. We need 587 * these to print proper error messages and possibly get user 588 * input. We attach them to console and hope that attachment 589 * works. 590 */ 591 if (ttyname(0) == NULL) { 592 no_tty = 1; 593 dup2(open("/dev/console", O_RDONLY), 0); 594 dup2(open("/dev/console", O_WRONLY), 1); 595 dup2(open("/dev/console", O_WRONLY), 2); 596 } 597 598 while ((c = getopt(argc, argv, "fnxhtd:")) != EOF) { 599 switch (c) { 600 case 'f': 601 /* 602 * Force machine to poweroff if 603 * suspend fails 604 */ 605 flags |= FORCE; 606 break; 607 case 'n': 608 /* No warning popups - Obsolete */ 609 flags |= NO_WARN; 610 break; 611 case 'x': 612 /* Don't try to screenlock */ 613 flags |= NO_XLOCK; 614 break; 615 case 'h': 616 /* Do a shutdown instead of suspend */ 617 flags |= SHUTDOWN; 618 break; 619 case 'd': 620 /* Needswork */ 621 /* Set the DISPLAY value in the environment */ 622 if (strlen(optarg) >= MAXNAMELEN) { 623 (void) printf(gettext("Error: " 624 "display name is too long.\n")); 625 return (1); 626 } 627 (void) strcat(display_name, optarg); 628 if (putenv(display_name) != 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 break; 644 } 645 } 646 647 /* 648 * The action of pressing power key and power button on a MOU-3 machine 649 * causes suspend being invoked with SYSSUSPENDDODEFAULT 650 * enviromental variable set - indicating the default action is machine 651 * dependent: for MOU-3 type machine, "LowPower" mode is the default, 652 * for all the rest, "Suspend" is the default. Existing suspend 653 * flags works the same. 654 */ 655 if (getenv("SYSSUSPENDDODEFAULT")) 656 if (is_mou3()) 657 flags |= LOWPOWER; 658 659 if ((flags & FORCE) && (flags & LOWPOWER)) 660 flags &= ~LOWPOWER; 661 662 /* 663 * Flag "-h" overrides flag "-f". 664 */ 665 if ((flags & SHUTDOWN) && (flags & FORCE)) 666 flags &= ~(FORCE | LOWPOWER); 667 668 if (flags & FORCE) 669 flags |= NO_WARN; 670 671 /* 672 * Check initally if the user has the authorizations to 673 * do either a suspend or shutdown. pm_suspend() will also 674 * make this test, so we could defer till then, but if we 675 * do it now, we at least prevent a lot of unneeded setup. 676 */ 677 pw = getpwuid(getuid()); 678 strncpy(user, pw->pw_name, NMAX); 679 680 if ((flags & (FORCE|SHUTDOWN)) && 681 (chkauthattr(AUTHNAME_SHUTDOWN, pw->pw_name) != 1)) { 682 (void) printf(gettext("User does not have correct " 683 "authorizations to shutdown the machine.\n")); 684 exit(1); 685 } 686 if (!(flags & SHUTDOWN) && 687 (chkauthattr(AUTHNAME_SUSPEND, pw->pw_name) != 1)) { 688 (void) printf(gettext("User does not have correct " 689 "authorizations to suspend.\n")); 690 exit(1); 691 } 692 693 /* 694 * If we are only shutting down, there isn't much to do, just 695 * call pm_poweroff(), and let it do all the work. 696 */ 697 if (flags & SHUTDOWN) { 698 /* 699 * pm_poweroff either powers off or exits, 700 * so there is no return. 701 */ 702 if (flags & TEST) { 703 (void) printf("TEST: This machine would have " 704 "powered off\n"); 705 exit(1); 706 } else { 707 pm_poweroff(); 708 } 709 /* NOTREACHED */ 710 } 711 712 /* 713 * If XAUTHORITY environment variable is not set, try to set 714 * one up. 715 */ 716 if (getenv("XAUTHORITY") == NULL) 717 (void) putenv(get_xauthority(xauthority)); 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 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 749 bringto_lowpower() 750 { 751 int fd; 752 753 if ((fd = open("/dev/pm", O_RDWR)) < 0) { 754 printf(gettext("Can't open /dev/pm\n")); 755 return (-1); 756 } 757 758 if (ioctl(fd, PM_IDLE_DOWN, NULL) < 0) { 759 printf(gettext("Failed to bring system to low power mode.\n")); 760 close(fd); 761 return (-1); 762 } 763 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 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 printf(gettext("Can't read /etc/.cpr_config file.")); 787 } else { 788 found = cf.is_autopm_default; 789 } 790 791 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