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>
31 #include "console_switch.h"
40 static GList
*atexit_functions
;
42 static void invoke_atexit_functions(void)
44 for (GList
*item
= atexit_functions
;
46 item
= g_list_next(item
)) {
47 (*(void (**)())&item
->data
)();
51 static void ensure_atexit(void (*function
)(void))
53 if (atexit_functions
== NULL
)
54 atexit(invoke_atexit_functions
);
56 atexit_functions
= g_list_prepend(atexit_functions
,
60 static char *get_username(void)
63 char *username
= NULL
;
65 /* Get the user name from the environment if started as root. */
67 username
= getenv("USER");
69 if (username
== NULL
) {
72 /* Get the password entry. */
78 username
= pw
->pw_name
;
81 return strdup(username
);
84 static void terminate(int signum
)
86 fprintf(stderr
, "vlock: Terminated!\n");
87 invoke_atexit_functions();
91 static void block_signals(void)
95 /* Ignore some signals. */
96 /* These signals shouldn't be delivered anyway, because terminal signals are
98 (void) sigemptyset(&(sa
.sa_mask
));
99 sa
.sa_flags
= SA_RESTART
;
100 sa
.sa_handler
= SIG_IGN
;
101 (void) sigaction(SIGINT
, &sa
, NULL
);
102 (void) sigaction(SIGQUIT
, &sa
, NULL
);
103 (void) sigaction(SIGTSTP
, &sa
, NULL
);
105 /* Install special handler for SIGTERM. */
106 sa
.sa_flags
= SA_RESETHAND
;
107 sa
.sa_handler
= terminate
;
108 (void) sigaction(SIGTERM
, &sa
, NULL
);
111 static struct termios term
;
112 static tcflag_t lflag
;
114 static void secure_terminal(void)
116 /* Disable terminal echoing and signals. */
117 (void) tcgetattr(STDIN_FILENO
, &term
);
118 lflag
= term
.c_lflag
;
119 term
.c_lflag
&= ~(ECHO
| ISIG
);
120 (void) tcsetattr(STDIN_FILENO
, TCSANOW
, &term
);
123 static void restore_terminal(void)
125 /* Restore the terminal. */
126 term
.c_lflag
= lflag
;
127 (void) tcsetattr(STDIN_FILENO
, TCSANOW
, &term
);
130 static int auth_tries
;
132 static void auth_loop(const char *username
)
135 struct timespec
*prompt_timeout
;
136 struct timespec
*wait_timeout
;
138 const char *auth_names
[] = { username
, "root", NULL
};
140 /* If NO_ROOT_PASS is defined or the username is "root" ... */
142 if (strcmp(username
, "root") == 0)
144 /* ... do not fall back to "root". */
145 auth_names
[1] = NULL
;
147 /* Get the vlock message from the environment. */
148 vlock_message
= getenv("VLOCK_MESSAGE");
150 if (vlock_message
== NULL
) {
151 if (console_switch_locked
)
152 vlock_message
= getenv("VLOCK_ALL_MESSAGE");
154 vlock_message
= getenv("VLOCK_CURRENT_MESSAGE");
157 /* Get the timeouts from the environment. */
158 prompt_timeout
= parse_seconds(getenv("VLOCK_PROMPT_TIMEOUT"));
160 wait_timeout
= parse_seconds(getenv("VLOCK_TIMEOUT"));
168 /* Print vlock message if there is one. */
169 if (vlock_message
&& *vlock_message
) {
170 fputs(vlock_message
, stderr
);
174 /* Wait for enter or escape to be pressed. */
175 c
= wait_for_character("\n\033", wait_timeout
);
177 /* Escape was pressed or the timeout occurred. */
178 if (c
== '\033' || c
== 0) {
180 plugin_hook("vlock_save");
181 /* Wait for any key to be pressed. */
182 c
= wait_for_character(NULL
, NULL
);
183 plugin_hook("vlock_save_abort");
185 /* Do not require enter to be pressed twice. */
193 for (size_t i
= 0; auth_names
[i
] != NULL
; i
++) {
194 if (auth(auth_names
[i
], prompt_timeout
, &err
))
197 g_assert(err
!= NULL
);
199 if (g_error_matches(err
,
201 VLOCK_PROMPT_ERROR_TIMEOUT
))
202 fprintf(stderr
, "Timeout!\n");
204 fprintf(stderr
, "vlock: %s\n", err
->message
);
214 /* Free timeouts memory. */
216 free(prompt_timeout
);
219 void display_auth_tries(void)
222 fprintf(stderr
, "%d failed authentication %s.\n", auth_tries
, auth_tries
> 1 ? "tries" : "try");
226 static void call_end_hook(void)
228 (void) plugin_hook("vlock_end");
232 /* Lock the current terminal until proper authentication is received. */
233 int main(int argc
, char *const argv
[])
237 vlock_debug
= (getenv("VLOCK_DEBUG") != NULL
);
241 username
= get_username();
243 if (username
== NULL
)
244 fatal_perror("vlock: could not get username");
246 ensure_atexit(display_auth_tries
);
249 for (int i
= 1; i
< argc
; i
++)
250 if (!load_plugin(argv
[i
]))
251 fatal_error("vlock: loading plugin '%s' failed: %s", argv
[i
], STRERROR
);
253 ensure_atexit(unload_plugins
);
255 if (!resolve_dependencies()) {
259 fatal_error("vlock: error resolving plugin dependencies: %s", STRERROR
);
262 plugin_hook("vlock_start");
263 ensure_atexit(call_end_hook
);
264 #else /* !USE_PLUGINS */
265 /* Emulate pseudo plugin "all". */
266 if (argc
== 2 && (strcmp(argv
[1], "all") == 0)) {
267 if (!lock_console_switch()) {
269 perror("vlock: could not disable console switching");
274 ensure_atexit((void (*)(void))unlock_console_switch
);
275 } else if (argc
> 1) {
276 fatal_error("vlock: plugin support disabled");
280 if (!isatty(STDIN_FILENO
))
281 fatal_error("vlock: stdin is not a terminal");
284 ensure_atexit(restore_terminal
);