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
23 #include <sys/types.h>
32 #include "console_switch.h"
41 static GList
*atexit_functions
;
43 static void invoke_atexit_functions(void)
45 while (atexit_functions
!= NULL
) {
46 (*(void (**)())&atexit_functions
->data
)();
47 atexit_functions
= g_list_remove_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 char *get_username(void)
64 char *username
= NULL
;
66 /* Get the user name from the environment if started as root. */
68 username
= getenv("USER");
70 if (username
== NULL
) {
73 /* Get the password entry. */
79 username
= pw
->pw_name
;
82 return strdup(username
);
85 static void terminate(int signum
)
87 invoke_atexit_functions();
88 fprintf(stderr
, "vlock: Killed by signal %d (%s)!\n", signum
, strsignal(signum
));
92 static void install_signal_handlers(void)
96 /* Ignore some signals. */
97 (void) sigemptyset(&(sa
.sa_mask
));
98 sa
.sa_flags
= SA_RESTART
;
99 sa
.sa_handler
= SIG_IGN
;
100 (void) sigaction(SIGTSTP
, &sa
, NULL
);
102 /* Handle termination signals. None of these should be delivered in a normal
103 * run of the program because terminal signals (INT, QUIT) are disabled
105 sa
.sa_flags
= SA_RESETHAND
;
106 sa
.sa_handler
= terminate
;
107 (void) sigaction(SIGINT
, &sa
, NULL
);
108 (void) sigaction(SIGQUIT
, &sa
, NULL
);
109 (void) sigaction(SIGTERM
, &sa
, NULL
);
110 (void) sigaction(SIGHUP
, &sa
, NULL
);
111 (void) sigaction(SIGABRT
, &sa
, NULL
);
112 (void) sigaction(SIGSEGV
, &sa
, NULL
);
115 static struct termios term
;
116 static tcflag_t lflag
;
118 static void secure_terminal(void)
120 /* Disable terminal echoing and signals. */
121 (void) tcgetattr(STDIN_FILENO
, &term
);
122 lflag
= term
.c_lflag
;
123 term
.c_lflag
&= ~(ECHO
| ISIG
);
124 (void) tcsetattr(STDIN_FILENO
, TCSANOW
, &term
);
127 static void restore_terminal(void)
129 /* Restore the terminal. */
130 term
.c_lflag
= lflag
;
131 (void) tcsetattr(STDIN_FILENO
, TCSANOW
, &term
);
134 static int auth_tries
;
136 static void auth_loop(const char *username
)
139 struct timespec
*prompt_timeout
;
140 struct timespec
*wait_timeout
;
142 const char *auth_names
[] = { username
, "root", NULL
};
144 /* If NO_ROOT_PASS is defined or the username is "root" ... */
146 if (strcmp(username
, "root") == 0)
148 /* ... do not fall back to "root". */
149 auth_names
[1] = NULL
;
151 /* Get the vlock message from the environment. */
152 vlock_message
= getenv("VLOCK_MESSAGE");
154 if (vlock_message
== NULL
) {
155 if (console_switch_locked
)
156 vlock_message
= getenv("VLOCK_ALL_MESSAGE");
158 vlock_message
= getenv("VLOCK_CURRENT_MESSAGE");
161 /* Get the timeouts from the environment. */
162 prompt_timeout
= parse_seconds(getenv("VLOCK_PROMPT_TIMEOUT"));
164 wait_timeout
= parse_seconds(getenv("VLOCK_TIMEOUT"));
172 /* Print vlock message if there is one. */
173 if (vlock_message
&& *vlock_message
) {
174 fputs(vlock_message
, stderr
);
178 /* Wait for enter or escape to be pressed. */
179 c
= wait_for_character("\n\033", wait_timeout
);
181 /* Escape was pressed or the timeout occurred. */
182 if (c
== '\033' || c
== 0) {
184 plugin_hook("vlock_save");
185 /* Wait for any key to be pressed. */
186 c
= wait_for_character(NULL
, NULL
);
187 plugin_hook("vlock_save_abort");
189 /* Do not require enter to be pressed twice. */
197 for (size_t i
= 0; auth_names
[i
] != NULL
; i
++) {
198 if (auth(auth_names
[i
], prompt_timeout
, &err
))
201 g_assert(err
!= NULL
);
203 if (g_error_matches(err
,
205 VLOCK_PROMPT_ERROR_TIMEOUT
)) {
206 fprintf(stderr
, "Timeout!\n");
208 fprintf(stderr
, "vlock: %s\n", err
->message
);
210 if (g_error_matches(err
,
212 VLOCK_AUTH_ERROR_FAILED
)) {
214 fprintf(stderr
, "******************************************************************\n");
215 fprintf(stderr
, "*** You may not be able to able to unlock your terminal now. ***\n");
216 fprintf(stderr
, "*** ***\n");
217 fprintf(stderr
, "*** Log into another terminal and kill the vlock-main process. ***\n");
218 fprintf(stderr
, "******************************************************************\n");
232 /* Free timeouts memory. */
234 free(prompt_timeout
);
237 void display_auth_tries(void)
240 fprintf(stderr
, "%d failed authentication %s.\n", auth_tries
, auth_tries
> 1 ? "tries" : "try");
244 static void call_end_hook(void)
246 (void) plugin_hook("vlock_end");
250 /* Lock the current terminal until proper authentication is received. */
251 int main(int argc
, char *const argv
[])
255 vlock_debug
= (getenv("VLOCK_DEBUG") != NULL
);
257 install_signal_handlers();
259 username
= get_username();
261 if (username
== NULL
)
262 fatal_perror("vlock: could not get username");
264 ensure_atexit(display_auth_tries
);
267 for (int i
= 1; i
< argc
; i
++)
268 if (!load_plugin(argv
[i
]))
269 fatal_error("vlock: loading plugin '%s' failed: %s", argv
[i
], STRERROR
);
271 ensure_atexit(unload_plugins
);
273 if (!resolve_dependencies()) {
277 fatal_error("vlock: error resolving plugin dependencies: %s", STRERROR
);
280 plugin_hook("vlock_start");
281 ensure_atexit(call_end_hook
);
282 #else /* !USE_PLUGINS */
283 /* Emulate pseudo plugin "all". */
284 if (argc
== 2 && (strcmp(argv
[1], "all") == 0)) {
285 if (!lock_console_switch()) {
287 perror("vlock: could not disable console switching");
292 ensure_atexit((void (*)(void))unlock_console_switch
);
293 } else if (argc
> 1) {
294 fatal_error("vlock: plugin support disabled");
298 if (!isatty(STDIN_FILENO
))
299 fatal_error("vlock: stdin is not a terminal");
302 ensure_atexit(restore_terminal
);