~ubuntu-branches/ubuntu/raring/vlock/raring

« back to all changes in this revision

Viewing changes to src/vlock-main.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Wirt
  • Date: 2008-06-17 17:13:25 UTC
  • mfrom: (1.1.2 upstream) (3.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080617171325-ic8yy6tol0165i96
Tags: 2.2.2-3
* Don't try to chgrp to "vlock" during build time (Closes: #486665)
* Bump standards version (No changes)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vlock-main.c -- main routine for vlock,
 
2
 *                    the VT locking program for linux
 
3
 *
 
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.
 
11
 *
 
12
 */
 
13
 
 
14
#include <stdlib.h>
 
15
#include <string.h>
 
16
#include <stdio.h>
 
17
 
 
18
#include <pwd.h>
 
19
 
 
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>
 
26
 
 
27
#include "prompt.h"
 
28
#include "auth.h"
 
29
#include "console_switch.h"
 
30
#include "util.h"
 
31
 
 
32
#ifdef USE_PLUGINS
 
33
#include "plugins.h"
 
34
#endif
 
35
 
 
36
int vlock_debug = 0;
 
37
 
 
38
#define ensure_atexit(func) \
 
39
  do { \
 
40
    if (atexit(func) != 0) \
 
41
      fatal_perror("vlock: atexit() failed"); \
 
42
  } while (0)
 
43
 
 
44
static char *get_username(void)
 
45
{
 
46
  uid_t uid = getuid();
 
47
  char *username = NULL;
 
48
 
 
49
  /* Get the user name from the environment if started as root. */
 
50
  if (uid == 0)
 
51
    username = getenv("USER");
 
52
 
 
53
  if (username == NULL) {
 
54
    struct passwd *pw;
 
55
 
 
56
    /* Get the password entry. */
 
57
    pw = getpwuid(uid);
 
58
 
 
59
    if (pw == NULL)
 
60
      return NULL;
 
61
 
 
62
    username = pw->pw_name;
 
63
  }
 
64
 
 
65
  return strdup(username);
 
66
}
 
67
 
 
68
static void terminate(int signum)
 
69
{
 
70
  fprintf(stderr, "vlock: Terminated!\n");
 
71
  /* Call exit here to ensure atexit handlers are called. */
 
72
  exit(1);
 
73
}
 
74
 
 
75
static void block_signals(void)
 
76
{
 
77
  struct sigaction sa;
 
78
 
 
79
  /* Ignore some signals. */
 
80
  /* These signals shouldn't be delivered anyway, because terminal signals are
 
81
   * disabled below. */
 
82
  (void) sigemptyset(&(sa.sa_mask));
 
83
  sa.sa_flags = SA_RESTART;
 
84
  sa.sa_handler = SIG_IGN;
 
85
  (void) sigaction(SIGINT, &sa, NULL);
 
86
  (void) sigaction(SIGQUIT, &sa, NULL);
 
87
  (void) sigaction(SIGTSTP, &sa, NULL);
 
88
 
 
89
  /* Install special handler for SIGTERM. */
 
90
  sa.sa_flags = SA_RESETHAND;
 
91
  sa.sa_handler = terminate;
 
92
  (void) sigaction(SIGTERM, &sa, NULL);
 
93
}
 
94
 
 
95
static struct termios term;
 
96
static tcflag_t lflag;
 
97
 
 
98
static void secure_terminal(void)
 
99
{
 
100
  /* Disable terminal echoing and signals. */
 
101
  (void) tcgetattr(STDIN_FILENO, &term);
 
102
  lflag = term.c_lflag;
 
103
  term.c_lflag &= ~(ECHO | ISIG);
 
104
  (void) tcsetattr(STDIN_FILENO, TCSANOW, &term);
 
105
}
 
106
 
 
107
static void restore_terminal(void)
 
108
{
 
109
  /* Restore the terminal. */
 
110
  term.c_lflag = lflag;
 
111
  (void) tcsetattr(STDIN_FILENO, TCSANOW, &term);
 
112
}
 
113
 
 
114
static int auth_tries;
 
115
 
 
116
static void auth_loop(const char *username)
 
117
{
 
118
  struct timespec *prompt_timeout;
 
119
  struct timespec *wait_timeout;
 
120
  char *vlock_message;
 
121
 
 
122
  /* Get the vlock message from the environment. */
 
123
  vlock_message = getenv("VLOCK_MESSAGE");
 
124
 
 
125
  if (vlock_message == NULL) {
 
126
    if (console_switch_locked)
 
127
      vlock_message = getenv("VLOCK_ALL_MESSAGE");
 
128
    else
 
129
      vlock_message = getenv("VLOCK_CURRENT_MESSAGE");
 
130
  }
 
131
 
 
132
  /* Get the timeouts from the environment. */
 
133
  prompt_timeout = parse_seconds(getenv("VLOCK_PROMPT_TIMEOUT"));
 
134
#ifdef USE_PLUGINS
 
135
  wait_timeout = parse_seconds(getenv("VLOCK_TIMEOUT"));
 
136
#else
 
137
  wait_timeout = NULL;
 
138
#endif
 
139
 
 
140
  for (;;) {
 
141
    char c;
 
142
 
 
143
    /* Print vlock message if there is one. */
 
144
    if (vlock_message && *vlock_message) {
 
145
      fputs(vlock_message, stderr);
 
146
      fputc('\n', stderr);
 
147
    }
 
148
 
 
149
    /* Wait for enter or escape to be pressed. */
 
150
    c = wait_for_character("\n\033", wait_timeout);
 
151
 
 
152
    /* Escape was pressed or the timeout occurred. */
 
153
    if (c == '\033' || c == 0) {
 
154
#ifdef USE_PLUGINS
 
155
      plugin_hook("vlock_save");
 
156
      /* Wait for any key to be pressed. */
 
157
      c = wait_for_character(NULL, NULL);
 
158
      plugin_hook("vlock_save_abort");
 
159
 
 
160
      /* Do not require enter to be pressed twice. */
 
161
      if (c != '\n')
 
162
        continue;
 
163
#else
 
164
      continue;
 
165
#endif
 
166
    }
 
167
 
 
168
    /* Try authentication as user. */
 
169
    if (auth(username, prompt_timeout))
 
170
      break;
 
171
    else
 
172
      sleep(1);
 
173
 
 
174
#ifndef NO_ROOT_PASS
 
175
    if (strcmp(username, "root") != 0) {
 
176
      /* Try authentication as root. */
 
177
      if (auth("root", prompt_timeout))
 
178
        break;
 
179
      else
 
180
        sleep(1);
 
181
    }
 
182
#endif
 
183
 
 
184
    auth_tries++;
 
185
  }
 
186
 
 
187
  /* Free timeouts memory. */
 
188
  free(wait_timeout);
 
189
  free(prompt_timeout);
 
190
}
 
191
 
 
192
void display_auth_tries(void)
 
193
{
 
194
  if (auth_tries > 0)
 
195
    fprintf(stderr, "%d failed authentication %s.\n", auth_tries, auth_tries > 1 ? "tries" : "try");
 
196
}
 
197
 
 
198
#ifdef USE_PLUGINS
 
199
static void call_end_hook(void)
 
200
{
 
201
  (void) plugin_hook("vlock_end");
 
202
}
 
203
#endif
 
204
 
 
205
/* Lock the current terminal until proper authentication is received. */
 
206
int main(int argc, char *const argv[])
 
207
{
 
208
  char *username;
 
209
 
 
210
  vlock_debug = (getenv("VLOCK_DEBUG") != NULL);
 
211
 
 
212
  block_signals();
 
213
 
 
214
  username = get_username();
 
215
 
 
216
  if (username == NULL)
 
217
    fatal_perror("vlock: could not get username");
 
218
 
 
219
  ensure_atexit(display_auth_tries);
 
220
 
 
221
#ifdef USE_PLUGINS
 
222
  for (int i = 1; i < argc; i++)
 
223
    if (!load_plugin(argv[i]))
 
224
      fatal_error("vlock: loading plugin '%s' failed: %s", argv[i], STRERROR);
 
225
 
 
226
  ensure_atexit(unload_plugins);
 
227
 
 
228
  if (!resolve_dependencies()) {
 
229
    if (errno == 0)
 
230
      exit(EXIT_FAILURE);
 
231
    else
 
232
      fatal_error("vlock: error resolving plugin dependencies: %s", STRERROR);
 
233
  }
 
234
 
 
235
  plugin_hook("vlock_start");
 
236
  ensure_atexit(call_end_hook);
 
237
#else /* !USE_PLUGINS */
 
238
  /* Emulate pseudo plugin "all". */
 
239
  if (argc == 2 && (strcmp(argv[1], "all") == 0)) {
 
240
    if (!lock_console_switch()) {
 
241
      if (errno)
 
242
        perror("vlock: could not disable console switching");
 
243
 
 
244
      exit(EXIT_FAILURE);
 
245
    }
 
246
 
 
247
    ensure_atexit((void (*)(void))unlock_console_switch);
 
248
  } else if (argc > 1) {
 
249
    fatal_error("vlock: plugin support disabled");
 
250
  }
 
251
#endif
 
252
 
 
253
  if (!isatty(STDIN_FILENO))
 
254
    fatal_error("vlock: stdin is not a terminal");
 
255
 
 
256
  secure_terminal();
 
257
  ensure_atexit(restore_terminal);
 
258
 
 
259
  auth_loop(username);
 
260
 
 
261
  free(username);
 
262
 
 
263
  exit(0);
 
264
}