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