correct fork error handling
[vlock.git] / input.c
blob7536fa008fbf7824625900512012de0428164471
1 /* input.c -- password getting module for vlock
3 * This program is copyright (C) 1994 Michael K. Johnson, and is free
4 * software which is freely distributable under the terms of the
5 * GNU General Public License version 2, included as the file COPYING in this
6 * distribution. It is NOT public domain software, and any
7 * redistribution not permitted by the GNU General Public License is
8 * expressly forbidden without prior written permission from
9 * the author.
13 /* Marek hacked the code a bit:
14 - use /dev/tty instead of /dev/console (permissions on the latter
15 shouldn't allow all users to open it)
16 - get encrypted password once at startup, drop privileges as soon
17 as possible (we have to be setuid root for shadow passwords)
18 * This may not be a good idea, because it makes vlock a way for
19 the user to get at root's encrypted password (if user can
20 ptrace process after setuid(getuid()); -- check this)
21 * (probably) can't give up id with PAM anyway, at least with
22 shadow
23 - error message instead of core dump if getpwuid() returns NULL
24 - added check if encrypted password is valid (>=13 characters)
25 - terminal modes should be properly restored (don't leave echo off)
26 if getpass() fails.
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <sys/types.h>
35 #include <pwd.h>
37 #include <security/pam_appl.h>
38 #include <security/pam_misc.h>
40 static struct pam_conv PAM_conversation = {
41 &misc_conv,
42 NULL
45 #include "vlock.h"
48 static char prompt[100]; /* password prompt ("user's password: ") */
49 static char username[40]; /* current user's name */
52 static int
53 correct_password(void)
55 pam_handle_t *pamh;
56 int pam_error;
58 /* Now use PAM to do authentication.
60 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
61 pam_end(pamh, 0); \
62 /* fix signals that may have been disordered by pam */ \
63 set_signal_mask(0); \
64 return 0; \
66 pam_error = pam_start("vlock", username, &PAM_conversation, &pamh);
67 PAM_BAIL;
68 printf("%s's ", username); fflush(stdout);
69 pam_error = pam_set_item(pamh, PAM_USER_PROMPT, strdup(prompt));
70 PAM_BAIL;
71 pam_error = pam_authenticate(pamh, 0);
72 /* fix signals that may have been disordered by pam */
73 set_signal_mask(0);
74 #ifdef NO_ROOT_PASS
75 PAM_BAIL;
76 #else
77 if (pam_error != PAM_SUCCESS) {
78 /* Try as root; bail if no success there either */
79 printf("root's "); fflush(stdout);
80 pam_error = pam_set_item(pamh, PAM_USER_PROMPT, strdup(prompt));
81 PAM_BAIL;
82 pam_error = pam_set_item(pamh, PAM_USER, "root");
83 PAM_BAIL;
84 pam_error = pam_authenticate(pamh, 0);
85 /* fix signals that may have been disordered by pam */
86 set_signal_mask(0);
87 PAM_BAIL;
89 #endif /* !NO_ROOT_PASS */
90 pam_end(pamh, PAM_SUCCESS);
91 /* If this point is reached, the user has been authenticated. */
92 return 1;
98 void
99 get_password(void)
101 set_terminal(0);
102 do {
103 if (o_lock_all) {
104 /* To do: allow logging the user out safely without shutting down
105 the whole machine... */
106 printf("The entire console display is now completely locked.\n"
107 "You will not be able to switch to another virtual console.\n");
109 } else {
110 printf("This TTY is now locked.\n");
111 if (is_vt)
112 printf("Use Alt-function keys to switch to other virtual consoles.\n");
114 printf("Please enter the password to unlock.\n");
115 fflush(stdout);
117 /* correct_password() sets the terminal status as necessary */
118 if (correct_password()) {
119 restore_signals();
120 restore_terminal();
121 return;
124 /* correct_password() may have failed to return success because the */
125 /* terminal is closed. In this case, it would not be appropriate to */
126 /* try again... */
127 if (isatty(STDIN_FILENO) == 0) {
128 perror("isatty");
129 restore_terminal();
130 exit(1);
134 /* Need to slow down people who are trying to break in by brute force */
135 /* Note that it is technically possible to break this, but I can't */
136 /* make it happen, even knowing the code and knowing how to try. */
137 /* If you manage to kill vlock from the terminal while in this code, */
138 /* please tell me how you did it. */
139 printf(" *** That password is incorrect; please try again. *** \n");
140 printf("\n");
142 } while (1);
145 /* Get the user's and root passwords once at startup and store them
146 for use later. This has several advantages:
147 - to support shadow passwords, we have to be installed setuid
148 root, but we can completely drop privileges very early
149 - we avoid problems with unlocking when using NIS, after the
150 NIS server goes down
151 - before locking, we can check if any real password has a chance
152 to match the encrypted password (should be >=13 chars)
153 - this is the same way xlockmore does it.
154 Warning: this code runs as root - be careful if you modify it.
156 With PAM, applications never see encrypted passwords, so we can't
157 get the encrypted password ahead of time. We just have to hope
158 things work later on, just like we do with PAMified xlockmore.
161 static struct passwd *
162 my_getpwuid(uid_t uid)
164 struct passwd *pw;
166 pw = getpwuid(uid);
167 if (!pw) {
168 fprintf(stderr, "vlock: getpwuid(%d) failed: %s\n", uid, strerror(errno));
169 exit(1);
171 return pw;
174 void
175 init_passwords(void)
177 struct passwd *pw;
179 /* Get the password entry for this user (never returns NULL). */
180 pw = my_getpwuid(getuid());
182 /* Save the results where they will not get overwritten. */
183 strncpy(username, pw->pw_name, sizeof(username) - 1);
184 username[sizeof(username) - 1] = '\0';