src/vlock-main.c: slightly change failed authentication report message
[vlock.git] / src / vlock-main.c
blob450adf2c2c63f658b387efd4f926be5815e64dfd
1 /* vlock-main.c -- main routine for vlock,
2 * the VT locking program for linux
4 * This program is copyright (C) 2007 Frank Benkstein, and is free
5 * software which is freely distributable under the terms of the
6 * GNU General Public License version 2, included as the file COPYING in this
7 * distribution. It is NOT public domain software, and any
8 * redistribution not permitted by the GNU General Public License is
9 * expressly forbidden without prior written permission from
10 * the author.
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdio.h>
18 #include <pwd.h>
20 #include <termios.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <signal.h>
24 #include <errno.h>
25 #include <time.h>
27 #include "prompt.h"
28 #include "auth.h"
29 #include "console_switch.h"
30 #include "util.h"
32 #ifdef USE_PLUGINS
33 #include "plugins.h"
34 #endif
36 int vlock_debug = 0;
38 #define ensure_atexit(func) \
39 do { \
40 if (atexit(func) != 0) \
41 fatal_perror("vlock: atexit() failed"); \
42 } while (0)
44 static char *get_username(void)
46 uid_t uid = getuid();
47 char *username = NULL;
49 /* Get the user name from the environment if started as root. */
50 if (uid == 0)
51 username = getenv("USER");
53 if (username == NULL) {
54 struct passwd *pw;
56 /* Get the password entry. */
57 pw = getpwuid(uid);
59 if (pw == NULL)
60 return NULL;
62 username = pw->pw_name;
65 return strdup(username);
68 static void terminate(int signum)
70 fprintf(stderr, "vlock: Terminated!\n");
71 raise(signum);
74 static void block_signals(void)
76 struct sigaction sa;
78 /* Ignore some signals. */
79 /* These signals shouldn't be delivered anyway, because terminal signals are
80 * disabled below. */
81 (void) sigemptyset(&(sa.sa_mask));
82 sa.sa_flags = SA_RESTART;
83 sa.sa_handler = SIG_IGN;
84 (void) sigaction(SIGINT, &sa, NULL);
85 (void) sigaction(SIGQUIT, &sa, NULL);
86 (void) sigaction(SIGTSTP, &sa, NULL);
88 /* Install special handler for SIGTERM. */
89 sa.sa_flags = SA_RESETHAND;
90 sa.sa_handler = terminate;
91 (void) sigaction(SIGTERM, &sa, NULL);
94 static struct termios term;
95 static tcflag_t lflag;
97 static void secure_terminal(void)
99 /* Disable terminal echoing and signals. */
100 (void) tcgetattr(STDIN_FILENO, &term);
101 lflag = term.c_lflag;
102 term.c_lflag &= ~(ECHO | ISIG);
103 (void) tcsetattr(STDIN_FILENO, TCSANOW, &term);
106 static void restore_terminal(void)
108 /* Restore the terminal. */
109 term.c_lflag = lflag;
110 (void) tcsetattr(STDIN_FILENO, TCSANOW, &term);
113 static int auth_tries;
115 static void auth_loop(const char *username)
117 struct timespec *prompt_timeout;
118 struct timespec *wait_timeout;
119 char *vlock_message;
121 /* Get the vlock message from the environment. */
122 vlock_message = getenv("VLOCK_MESSAGE");
124 if (vlock_message == NULL) {
125 if (console_switch_locked)
126 vlock_message = getenv("VLOCK_ALL_MESSAGE");
127 else
128 vlock_message = getenv("VLOCK_CURRENT_MESSAGE");
131 /* Get the timeouts from the environment. */
132 prompt_timeout = parse_seconds(getenv("VLOCK_PROMPT_TIMEOUT"));
133 #ifdef USE_PLUGINS
134 wait_timeout = parse_seconds(getenv("VLOCK_TIMEOUT"));
135 #else
136 wait_timeout = NULL;
137 #endif
139 for (;;) {
140 char c;
142 /* Print vlock message if there is one. */
143 if (vlock_message && *vlock_message) {
144 fputs(vlock_message, stderr);
145 fputc('\n', stderr);
148 /* Wait for enter or escape to be pressed. */
149 c = wait_for_character("\n\033", wait_timeout);
151 /* Escape was pressed or the timeout occurred. */
152 if (c == '\033' || c == 0) {
153 #ifdef USE_PLUGINS
154 plugin_hook("vlock_save");
155 /* Wait for any key to be pressed. */
156 c = wait_for_character(NULL, NULL);
157 plugin_hook("vlock_save_abort");
159 /* Do not require enter to be pressed twice. */
160 if (c != '\n')
161 continue;
162 #else
163 continue;
164 #endif
167 /* Try authentication as user. */
168 if (auth(username, prompt_timeout))
169 break;
170 else
171 sleep(1);
173 #ifndef NO_ROOT_PASS
174 if (strcmp(username, "root") != 0) {
175 /* Try authentication as root. */
176 if (auth("root", prompt_timeout))
177 break;
178 else
179 sleep(1);
181 #endif
183 auth_tries++;
186 /* Free timeouts memory. */
187 free(wait_timeout);
188 free(prompt_timeout);
191 void display_auth_tries(void)
193 if (auth_tries > 0)
194 fprintf(stderr, "%d failed authentication %s.\n", auth_tries, auth_tries > 1 ? "tries" : "try");
197 #ifdef USE_PLUGINS
198 static void call_end_hook(void)
200 (void) plugin_hook("vlock_end");
202 #endif
204 /* Lock the current terminal until proper authentication is received. */
205 int main(int argc, char *const argv[])
207 char *username;
209 vlock_debug = (getenv("VLOCK_DEBUG") != NULL);
211 block_signals();
213 username = get_username();
215 if (username == NULL)
216 fatal_perror("vlock: could not get username");
218 ensure_atexit(display_auth_tries);
220 #ifdef USE_PLUGINS
221 for (int i = 1; i < argc; i++)
222 if (!load_plugin(argv[i]))
223 fatal_error("vlock: loading plugin '%s' failed: %s", argv[i], STRERROR);
225 ensure_atexit(unload_plugins);
227 if (!resolve_dependencies()) {
228 if (errno == 0)
229 exit(EXIT_FAILURE);
230 else
231 fatal_error("vlock: error resolving plugin dependencies: %s", STRERROR);
234 plugin_hook("vlock_start");
235 ensure_atexit(call_end_hook);
236 #else /* !USE_PLUGINS */
237 /* Emulate pseudo plugin "all". */
238 if (argc == 2 && (strcmp(argv[1], "all") == 0)) {
239 if (!lock_console_switch()) {
240 if (errno)
241 perror("vlock: could not disable console switching");
243 exit(EXIT_FAILURE);
246 ensure_atexit((void (*)(void))unlock_console_switch);
247 } else if (argc > 1) {
248 fatal_error("vlock: plugin support disabled");
250 #endif
252 if (!isatty(STDIN_FILENO))
253 fatal_error("vlock: stdin is not a terminal");
255 secure_terminal();
256 ensure_atexit(restore_terminal);
258 auth_loop(username);
260 free(username);
262 exit(0);