src/vlock-main.c: move authentication failure blurb into own variable
[vlock.git] / src / vlock-main.c
blob975a43020c3d6323a8700d3bae49a08c0a787ad8
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 #define _GNU_SOURCE
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdio.h>
19 #include <pwd.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <errno.h>
24 #include <time.h>
26 #include <glib.h>
27 #include <glib/gprintf.h>
28 #include <glib-object.h>
30 #include "prompt.h"
31 #include "auth.h"
32 #include "console_switch.h"
33 #include "signals.h"
34 #include "terminal.h"
35 #include "util.h"
36 #include "logging.h"
38 #ifdef USE_PLUGINS
39 #include "plugins.h"
40 #include "plugin.h"
41 #endif
43 static const char *auth_failure_blurb =
44 "******************************************************************\n"
45 "*** You may not be able to able to unlock your terminal now. ***\n"
46 "*** ***\n"
47 "*** Log into another terminal and kill the vlock-main process. ***\n"
48 "******************************************************************\n"
51 static int auth_tries;
53 static void auth_loop(const char *username)
55 GError *err = NULL;
56 struct timespec *prompt_timeout;
57 struct timespec *wait_timeout;
58 char *vlock_message;
59 const char *auth_names[] = { username, "root", NULL };
61 /* If NO_ROOT_PASS is defined or the username is "root" ... */
62 #ifndef NO_ROOT_PASS
63 if (strcmp(username, "root") == 0)
64 #endif
65 /* ... do not fall back to "root". */
66 auth_names[1] = NULL;
68 /* Get the vlock message from the environment. */
69 vlock_message = getenv("VLOCK_MESSAGE");
71 if (vlock_message == NULL) {
72 if (console_switch_locked)
73 vlock_message = getenv("VLOCK_ALL_MESSAGE");
74 else
75 vlock_message = getenv("VLOCK_CURRENT_MESSAGE");
78 /* Get the timeouts from the environment. */
79 prompt_timeout = parse_seconds(getenv("VLOCK_PROMPT_TIMEOUT"));
80 #ifdef USE_PLUGINS
81 wait_timeout = parse_seconds(getenv("VLOCK_TIMEOUT"));
82 #else
83 wait_timeout = NULL;
84 #endif
86 for (;;) {
87 char c;
89 /* Print vlock message if there is one. */
90 if (vlock_message && *vlock_message) {
91 fputs(vlock_message, stderr);
92 fputc('\n', stderr);
95 /* Wait for enter or escape to be pressed. */
96 c = wait_for_character("\n\033", wait_timeout);
98 /* Escape was pressed or the timeout occurred. */
99 if (c == '\033' || c == 0) {
100 #ifdef USE_PLUGINS
101 plugin_hook("vlock_save");
102 /* Wait for any key to be pressed. */
103 c = wait_for_character(NULL, NULL);
104 plugin_hook("vlock_save_abort");
106 /* Do not require enter to be pressed twice. */
107 if (c != '\n')
108 continue;
109 #else
110 continue;
111 #endif
114 for (size_t i = 0; auth_names[i] != NULL; i++) {
115 if (auth(auth_names[i], prompt_timeout, &err))
116 goto auth_success;
118 g_assert(err != NULL);
120 if (g_error_matches(err,
121 VLOCK_PROMPT_ERROR,
122 VLOCK_PROMPT_ERROR_TIMEOUT))
123 fprintf(stderr, "Timeout!\n");
124 else {
125 fprintf(stderr, "vlock: %s\n", err->message);
127 if (g_error_matches(err,
128 VLOCK_AUTH_ERROR,
129 VLOCK_AUTH_ERROR_FAILED)) {
130 fputc('\n', stderr);
131 fputs(auth_failure_blurb, stderr);
132 fputc('\n', stderr);
133 sleep(3);
137 g_clear_error(&err);
138 sleep(1);
141 auth_tries++;
144 auth_success:
145 /* Free timeouts memory. */
146 free(wait_timeout);
147 free(prompt_timeout);
150 void display_auth_tries(void)
152 if (auth_tries > 0)
153 fprintf(stderr,
154 "%d failed authentication %s.\n",
155 auth_tries,
156 auth_tries > 1 ? "tries" : "try");
159 #ifdef USE_PLUGINS
160 static void call_end_hook(void)
162 (void) plugin_hook("vlock_end");
165 #endif
167 /* Lock the current terminal until proper authentication is received. */
168 int main(int argc, char *const argv[])
170 const char *username = NULL;
172 /* Initialize GLib. */
173 g_set_prgname(argv[0]);
174 g_type_init();
176 /* Initialize logging. */
177 vlock_initialize_logging();
179 install_signal_handlers();
181 /* Get the user name from the environment if started as root. */
182 if (getuid() == 0)
183 username = g_getenv("USER");
185 if (username == NULL)
186 username = g_get_user_name();
188 vlock_atexit(display_auth_tries);
190 #ifdef USE_PLUGINS
191 GError *tmp_error = NULL;
193 for (int i = 1; i < argc; i++) {
194 if (!load_plugin(argv[i], &tmp_error)) {
195 g_assert(tmp_error != NULL);
197 if (g_error_matches(tmp_error,
198 VLOCK_PLUGIN_ERROR,
199 VLOCK_PLUGIN_ERROR_NOT_FOUND))
200 g_fprintf(stderr, "vlock: no such plugin '%s'\n", argv[i]);
201 else
202 g_fprintf(stderr,
203 "vlock: loading plugin '%s' failed: %s\n",
204 argv[i],
205 tmp_error->message);
207 g_clear_error(&tmp_error);
208 exit(EXIT_FAILURE);
212 vlock_atexit(unload_plugins);
214 if (!resolve_dependencies(&tmp_error)) {
215 g_assert(tmp_error != NULL);
216 g_fprintf(stderr,
217 "vlock: error resolving plugin dependencies: %s\n",
218 tmp_error->message);
219 g_clear_error(&tmp_error);
220 exit(EXIT_FAILURE);
223 plugin_hook("vlock_start");
224 vlock_atexit(call_end_hook);
225 #else /* !USE_PLUGINS */
226 /* Emulate pseudo plugin "all". */
227 if (argc == 2 && (strcmp(argv[1], "all") == 0)) {
228 if (!lock_console_switch()) {
229 if (errno)
230 g_fprintf(stderr,
231 "vlock: could not disable console switching: %s\n",
232 g_strerror(errno));
234 exit(EXIT_FAILURE);
237 ensure_atexit((void (*) (void))unlock_console_switch);
238 } else if (argc > 1) {
239 g_fprintf(stderr, "vlock: plugin support disabled\n");
240 exit(EXIT_FAILURE);
242 #endif
244 if (!isatty(STDIN_FILENO)) {
245 g_fprintf(stderr, "vlock: stdin is not a terminal\n");
246 exit(EXIT_FAILURE);
249 /* Delay securing the terminal until here because one of the plugins might
250 * have changed the active terminal. */
251 secure_terminal();
252 vlock_atexit(restore_terminal);
254 auth_loop(username);
256 exit(EXIT_SUCCESS);