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
22 #include <sys/types.h>
27 #include <glib/gprintf.h>
31 #include "console_switch.h"
41 static GList
*atexit_functions
;
43 void invoke_atexit_functions(void)
45 while (atexit_functions
!= NULL
) {
46 (*(void (**)())&atexit_functions
->data
)();
47 atexit_functions
= g_list_delete_link(atexit_functions
,
52 static void ensure_atexit(void (*function
)(void))
54 if (atexit_functions
== NULL
)
55 atexit(invoke_atexit_functions
);
57 atexit_functions
= g_list_prepend(atexit_functions
,
61 static int auth_tries
;
63 static void auth_loop(const char *username
)
66 struct timespec
*prompt_timeout
;
67 struct timespec
*wait_timeout
;
69 const char *auth_names
[] = { username
, "root", NULL
};
71 /* If NO_ROOT_PASS is defined or the username is "root" ... */
73 if (strcmp(username
, "root") == 0)
75 /* ... do not fall back to "root". */
78 /* Get the vlock message from the environment. */
79 vlock_message
= getenv("VLOCK_MESSAGE");
81 if (vlock_message
== NULL
) {
82 if (console_switch_locked
)
83 vlock_message
= getenv("VLOCK_ALL_MESSAGE");
85 vlock_message
= getenv("VLOCK_CURRENT_MESSAGE");
88 /* Get the timeouts from the environment. */
89 prompt_timeout
= parse_seconds(getenv("VLOCK_PROMPT_TIMEOUT"));
91 wait_timeout
= parse_seconds(getenv("VLOCK_TIMEOUT"));
99 /* Print vlock message if there is one. */
100 if (vlock_message
&& *vlock_message
) {
101 fputs(vlock_message
, stderr
);
105 /* Wait for enter or escape to be pressed. */
106 c
= wait_for_character("\n\033", wait_timeout
);
108 /* Escape was pressed or the timeout occurred. */
109 if (c
== '\033' || c
== 0) {
111 plugin_hook("vlock_save");
112 /* Wait for any key to be pressed. */
113 c
= wait_for_character(NULL
, NULL
);
114 plugin_hook("vlock_save_abort");
116 /* Do not require enter to be pressed twice. */
124 for (size_t i
= 0; auth_names
[i
] != NULL
; i
++) {
125 if (auth(auth_names
[i
], prompt_timeout
, &err
))
128 g_assert(err
!= NULL
);
130 if (g_error_matches(err
,
132 VLOCK_PROMPT_ERROR_TIMEOUT
)) {
133 fprintf(stderr
, "Timeout!\n");
135 fprintf(stderr
, "vlock: %s\n", err
->message
);
137 if (g_error_matches(err
,
139 VLOCK_AUTH_ERROR_FAILED
)) {
141 fprintf(stderr
, "******************************************************************\n");
142 fprintf(stderr
, "*** You may not be able to able to unlock your terminal now. ***\n");
143 fprintf(stderr
, "*** ***\n");
144 fprintf(stderr
, "*** Log into another terminal and kill the vlock-main process. ***\n");
145 fprintf(stderr
, "******************************************************************\n");
159 /* Free timeouts memory. */
161 free(prompt_timeout
);
164 void display_auth_tries(void)
167 fprintf(stderr
, "%d failed authentication %s.\n", auth_tries
, auth_tries
> 1 ? "tries" : "try");
171 static void call_end_hook(void)
173 (void) plugin_hook("vlock_end");
177 __attribute__((noreturn
))
178 static void display_error_and_exit(GError
*error
)
180 g_fprintf(stderr
, "vlock: %s\n", error
->message
);
184 __attribute__((noreturn
, format(printf
, 1, 2)))
185 static void printf_and_exit(const char *format
, ...)
187 char *error_message
= NULL
;
189 va_start(ap
, format
);
190 g_vasprintf(&error_message
, format
, ap
);
192 g_fprintf(stderr
, "vlock: %s\n", error_message
);
196 /* Lock the current terminal until proper authentication is received. */
197 int main(int argc
, char *const argv
[])
199 const char *username
= NULL
;
201 /* Initialize GLib. */
202 g_set_prgname(argv
[0]);
204 /* Initialize logging. */
205 vlock_initialize_logging();
207 install_signal_handlers();
209 /* Get the user name from the environment if started as root. */
211 username
= g_getenv("USER");
213 if (username
== NULL
)
214 username
= g_get_user_name();
216 ensure_atexit(display_auth_tries
);
219 for (int i
= 1; i
< argc
; i
++)
220 if (!load_plugin(argv
[i
]))
221 printf_and_exit("loading plugin '%s' failed: %s", argv
[i
], STRERROR
);
223 ensure_atexit(unload_plugins
);
225 if (!resolve_dependencies()) {
229 printf_and_exit("error resolving plugin dependencies: %s", STRERROR
);
232 plugin_hook("vlock_start");
233 ensure_atexit(call_end_hook
);
234 #else /* !USE_PLUGINS */
235 /* Emulate pseudo plugin "all". */
236 if (argc
== 2 && (strcmp(argv
[1], "all") == 0)) {
237 if (!lock_console_switch()) {
239 perror("vlock: could not disable console switching");
244 ensure_atexit((void (*)(void))unlock_console_switch
);
245 } else if (argc
> 1) {
246 printf_and_exit("plugin support disabled");
250 if (!isatty(STDIN_FILENO
))
251 printf_and_exit("stdin is not a terminal");
253 /* Delay securing the terminal until here because one of the plugins might
254 * have changed the active terminal. */
256 ensure_atexit(restore_terminal
);