/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to plugins.d/password-prompt.c

  • Committer: Teddy Hogeborn
  • Date: 2008-12-10 01:26:02 UTC
  • mfrom: (237.1.2 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20081210012602-vhz3h75xkj24t340
First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8; mode: c; mode: orgtbl -*- */
 
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Password-prompt - Read a password from the terminal and print it
 
3
 * Passprompt - Read a password from the terminal and print it
4
4
 * 
5
 
 * Copyright © 2008,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 Björn Påhlsson
 
5
 * Copyright © 2008 Teddy Hogeborn
 
6
 * Copyright © 2008 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
19
19
 * along with this program.  If not, see
20
20
 * <http://www.gnu.org/licenses/>.
21
21
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
22
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
23
 * <https://www.fukt.bsnet.se/~teddy/>.
23
24
 */
24
25
 
25
26
#define _GNU_SOURCE             /* getline() */
32
33
#include <signal.h>             /* sig_atomic_t, raise(), struct
33
34
                                   sigaction, sigemptyset(),
34
35
                                   sigaction(), sigaddset(), SIGINT,
35
 
                                   SIGQUIT, SIGHUP, SIGTERM,
36
 
                                   raise() */
 
36
                                   SIGQUIT, SIGHUP, SIGTERM */
37
37
#include <stddef.h>             /* NULL, size_t, ssize_t */
38
38
#include <sys/types.h>          /* ssize_t */
39
39
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
40
 
                                   getenv() */
 
40
                                   getopt_long, getenv() */
41
41
#include <stdio.h>              /* fprintf(), stderr, getline(),
42
 
                                   stdin, feof(), perror(), fputc()
43
 
                                */
44
 
#include <errno.h>              /* errno, EBADF, ENOTTY, EINVAL,
45
 
                                   EFAULT, EFBIG, EIO, ENOSPC, EINTR
46
 
                                */
 
42
                                   stdin, feof(), perror(), fputc(),
 
43
                                   stdout, getopt_long */
 
44
#include <errno.h>              /* errno, EINVAL */
47
45
#include <iso646.h>             /* or, not */
48
46
#include <stdbool.h>            /* bool, false, true */
49
47
#include <string.h>             /* strlen, rindex, strncmp, strcmp */
52
50
                                   argp_parse(), error_t,
53
51
                                   ARGP_KEY_ARG, ARGP_KEY_END,
54
52
                                   ARGP_ERR_UNKNOWN */
55
 
#include <sysexits.h>           /* EX_SOFTWARE, EX_OSERR,
56
 
                                   EX_UNAVAILABLE, EX_IOERR, EX_OK */
57
53
 
58
 
volatile sig_atomic_t quit_now = 0;
59
 
int signal_received;
 
54
volatile bool quit_now = false;
60
55
bool debug = false;
61
56
const char *argp_program_version = "password-prompt " VERSION;
62
57
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
63
58
 
64
 
static void termination_handler(int signum){
65
 
  if(quit_now){
66
 
    return;
67
 
  }
68
 
  quit_now = 1;
69
 
  signal_received = signum;
 
59
static void termination_handler(__attribute__((unused))int signum){
 
60
  quit_now = true;
70
61
}
71
62
 
72
63
int main(int argc, char **argv){
86
77
        .doc = "Prefix shown before the prompt", .group = 2 },
87
78
      { .name = "debug", .key = 128,
88
79
        .doc = "Debug mode", .group = 3 },
89
 
      /*
90
 
       * These reproduce what we would get without ARGP_NO_HELP
91
 
       */
92
 
      { .name = "help", .key = '?',
93
 
        .doc = "Give this help list", .group = -1 },
94
 
      { .name = "usage", .key = -3,
95
 
        .doc = "Give a short usage message", .group = -1 },
96
 
      { .name = "version", .key = 'V',
97
 
        .doc = "Print program version", .group = -1 },
98
80
      { .name = NULL }
99
81
    };
100
 
    
101
 
    error_t parse_opt (int key, char *arg, struct argp_state *state){
102
 
      errno = 0;
103
 
      switch (key){
 
82
  
 
83
    error_t parse_opt (int key, char *arg, struct argp_state *state) {
 
84
      /* Get the INPUT argument from `argp_parse', which we know is a
 
85
         pointer to our plugin list pointer. */
 
86
      switch (key) {
104
87
      case 'p':
105
88
        prefix = arg;
106
89
        break;
107
90
      case 128:
108
91
        debug = true;
109
92
        break;
110
 
        /*
111
 
         * These reproduce what we would get without ARGP_NO_HELP
112
 
         */
113
 
      case '?':                 /* --help */
114
 
        argp_state_help(state, state->out_stream,
115
 
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
116
 
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
117
 
      case -3:                  /* --usage */
118
 
        argp_state_help(state, state->out_stream,
119
 
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
120
 
      case 'V':                 /* --version */
121
 
        fprintf(state->out_stream, "%s\n", argp_program_version);
122
 
        exit(argp_err_exit_status);
 
93
      case ARGP_KEY_ARG:
 
94
        argp_usage (state);
 
95
        break;
 
96
      case ARGP_KEY_END:
123
97
        break;
124
98
      default:
125
99
        return ARGP_ERR_UNKNOWN;
126
100
      }
127
 
      return errno;
 
101
      return 0;
128
102
    }
129
 
    
 
103
  
130
104
    struct argp argp = { .options = options, .parser = parse_opt,
131
105
                         .args_doc = "",
132
106
                         .doc = "Mandos password-prompt -- Read and"
133
107
                         " output a password" };
134
 
    ret = argp_parse(&argp, argc, argv,
135
 
                     ARGP_IN_ORDER | ARGP_NO_HELP, NULL, NULL);
136
 
    switch(ret){
137
 
    case 0:
138
 
      break;
139
 
    case ENOMEM:
140
 
    default:
141
 
      errno = ret;
142
 
      perror("argp_parse");
143
 
      return EX_OSERR;
144
 
    case EINVAL:
145
 
      return EX_USAGE;
 
108
    ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
109
    if (ret == ARGP_ERR_UNKNOWN){
 
110
      fprintf(stderr, "Unknown error while parsing arguments\n");
 
111
      return EXIT_FAILURE;
146
112
    }
147
113
  }
148
 
  
149
 
  if(debug){
 
114
    
 
115
  if (debug){
150
116
    fprintf(stderr, "Starting %s\n", argv[0]);
151
117
  }
152
 
  if(debug){
 
118
  if (debug){
153
119
    fprintf(stderr, "Storing current terminal attributes\n");
154
120
  }
155
121
  
156
 
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
157
 
    int e = errno;
 
122
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
158
123
    perror("tcgetattr");
159
 
    switch(e){
160
 
    case EBADF:
161
 
    case ENOTTY:
162
 
      return EX_UNAVAILABLE;
163
 
    default:
164
 
      return EX_OSERR;
165
 
    }
 
124
    return EXIT_FAILURE;
166
125
  }
167
126
  
168
127
  sigemptyset(&new_action.sa_mask);
169
 
  ret = sigaddset(&new_action.sa_mask, SIGINT);
170
 
  if(ret == -1){
171
 
    perror("sigaddset");
172
 
    return EX_OSERR;
173
 
  }
174
 
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
175
 
  if(ret == -1){
176
 
    perror("sigaddset");
177
 
    return EX_OSERR;
178
 
  }
179
 
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
180
 
  if(ret == -1){
181
 
    perror("sigaddset");
182
 
    return EX_OSERR;
183
 
  }
184
 
  /* Need to check if the handler is SIG_IGN before handling:
185
 
     | [[info:libc:Initial Signal Actions]] |
186
 
     | [[info:libc:Basic Signal Handling]]  |
187
 
  */
 
128
  sigaddset(&new_action.sa_mask, SIGINT);
 
129
  sigaddset(&new_action.sa_mask, SIGHUP);
 
130
  sigaddset(&new_action.sa_mask, SIGTERM);
188
131
  ret = sigaction(SIGINT, NULL, &old_action);
189
132
  if(ret == -1){
190
133
    perror("sigaction");
191
 
    return EX_OSERR;
 
134
    return EXIT_FAILURE;
192
135
  }
193
 
  if(old_action.sa_handler != SIG_IGN){
 
136
  if (old_action.sa_handler != SIG_IGN){
194
137
    ret = sigaction(SIGINT, &new_action, NULL);
195
138
    if(ret == -1){
196
139
      perror("sigaction");
197
 
      return EX_OSERR;
 
140
      return EXIT_FAILURE;
198
141
    }
199
142
  }
200
143
  ret = sigaction(SIGHUP, NULL, &old_action);
201
144
  if(ret == -1){
202
145
    perror("sigaction");
203
 
    return EX_OSERR;
 
146
    return EXIT_FAILURE;
204
147
  }
205
 
  if(old_action.sa_handler != SIG_IGN){
 
148
  if (old_action.sa_handler != SIG_IGN){
206
149
    ret = sigaction(SIGHUP, &new_action, NULL);
207
150
    if(ret == -1){
208
151
      perror("sigaction");
209
 
      return EX_OSERR;
 
152
      return EXIT_FAILURE;
210
153
    }
211
154
  }
212
155
  ret = sigaction(SIGTERM, NULL, &old_action);
213
156
  if(ret == -1){
214
157
    perror("sigaction");
215
 
    return EX_OSERR;
 
158
    return EXIT_FAILURE;
216
159
  }
217
 
  if(old_action.sa_handler != SIG_IGN){
 
160
  if (old_action.sa_handler != SIG_IGN){
218
161
    ret = sigaction(SIGTERM, &new_action, NULL);
219
162
    if(ret == -1){
220
163
      perror("sigaction");
221
 
      return EX_OSERR;
 
164
      return EXIT_FAILURE;
222
165
    }
223
166
  }
224
167
  
225
168
  
226
 
  if(debug){
 
169
  if (debug){
227
170
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
228
171
  }
229
172
  
230
173
  t_new = t_old;
231
 
  t_new.c_lflag &= ~(tcflag_t)ECHO;
232
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
233
 
    int e = errno;
 
174
  t_new.c_lflag &= ~ECHO;
 
175
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
234
176
    perror("tcsetattr-echo");
235
 
    switch(e){
236
 
    case EBADF:
237
 
    case ENOTTY:
238
 
      return EX_UNAVAILABLE;
239
 
    case EINVAL:
240
 
    default:
241
 
      return EX_OSERR;
242
 
    }
 
177
    return EXIT_FAILURE;
243
178
  }
244
 
  
245
 
  if(debug){
 
179
 
 
180
  if (debug){
246
181
    fprintf(stderr, "Waiting for input from stdin \n");
247
182
  }
248
183
  while(true){
249
 
    if(quit_now){
 
184
    if (quit_now){
250
185
      if(debug){
251
186
        fprintf(stderr, "Interrupted by signal, exiting.\n");
252
187
      }
258
193
      fprintf(stderr, "%s ", prefix);
259
194
    }
260
195
    {
261
 
      const char *cryptsource = getenv("CRYPTTAB_SOURCE");
262
 
      const char *crypttarget = getenv("CRYPTTAB_NAME");
263
 
      /* Before cryptsetup 1.1.0~rc2 */
264
 
      if(cryptsource == NULL){
265
 
        cryptsource = getenv("cryptsource");
266
 
      }
267
 
      if(crypttarget == NULL){
268
 
        crypttarget = getenv("crypttarget");
269
 
      }
270
 
      const char *const prompt1 = "Unlocking the disk";
271
 
      const char *const prompt2 = "Enter passphrase";
 
196
      const char *cryptsource = getenv("cryptsource");
 
197
      const char *crypttarget = getenv("crypttarget");
 
198
      const char *const prompt
 
199
        = "Enter passphrase to unlock the disk";
272
200
      if(cryptsource == NULL){
273
201
        if(crypttarget == NULL){
274
 
          fprintf(stderr, "%s to unlock the disk: ", prompt2);
 
202
          fprintf(stderr, "%s: ", prompt);
275
203
        } else {
276
 
          fprintf(stderr, "%s (%s)\n%s: ", prompt1, crypttarget,
277
 
                  prompt2);
 
204
          fprintf(stderr, "%s (%s): ", prompt, crypttarget);
278
205
        }
279
206
      } else {
280
207
        if(crypttarget == NULL){
281
 
          fprintf(stderr, "%s %s\n%s: ", prompt1, cryptsource,
282
 
                  prompt2);
 
208
          fprintf(stderr, "%s %s: ", prompt, cryptsource);
283
209
        } else {
284
 
          fprintf(stderr, "%s %s (%s)\n%s: ", prompt1, cryptsource,
285
 
                  crypttarget, prompt2);
 
210
          fprintf(stderr, "%s %s (%s): ", prompt, cryptsource,
 
211
                  crypttarget);
286
212
        }
287
213
      }
288
214
    }
289
215
    ret = getline(&buffer, &n, stdin);
290
 
    if(ret > 0){
 
216
    if (ret > 0){
291
217
      status = EXIT_SUCCESS;
292
218
      /* Make n = data size instead of allocated buffer size */
293
219
      n = (size_t)ret;
294
220
      /* Strip final newline */
295
 
      if(n > 0 and buffer[n-1] == '\n'){
 
221
      if(n>0 and buffer[n-1] == '\n'){
296
222
        buffer[n-1] = '\0';     /* not strictly necessary */
297
223
        n--;
298
224
      }
300
226
      while(written < n){
301
227
        ret = write(STDOUT_FILENO, buffer + written, n - written);
302
228
        if(ret < 0){
303
 
          int e = errno;
304
229
          perror("write");
305
 
          switch(e){
306
 
          case EBADF:
307
 
          case EFAULT:
308
 
          case EINVAL:
309
 
          case EFBIG:
310
 
          case EIO:
311
 
          case ENOSPC:
312
 
          default:
313
 
            status = EX_IOERR;
314
 
            break;
315
 
          case EINTR:
316
 
            status = EXIT_FAILURE;
317
 
            break;
318
 
          }
 
230
          status = EXIT_FAILURE;
319
231
          break;
320
232
        }
321
233
        written += (size_t)ret;
322
234
      }
323
 
      ret = close(STDOUT_FILENO);
324
 
      if(ret == -1){
325
 
        int e = errno;
326
 
        perror("close");
327
 
        switch(e){
328
 
        case EBADF:
329
 
          status = EX_OSFILE;
330
 
          break;
331
 
        case EIO:
332
 
        default:
333
 
          status = EX_IOERR;
334
 
          break;
335
 
        }
336
 
      }
337
235
      break;
338
236
    }
339
 
    if(ret < 0){
340
 
      int e = errno;
341
 
      if(errno != EINTR and not feof(stdin)){
 
237
    if (ret < 0){
 
238
      if (errno != EINTR and not feof(stdin)){
342
239
        perror("getline");
343
 
        switch(e){
344
 
        case EBADF:
345
 
          status = EX_UNAVAILABLE;
346
 
        case EIO:
347
 
        case EINVAL:
348
 
        default:
349
 
          status = EX_IOERR;
350
 
          break;
351
 
        }
 
240
        status = EXIT_FAILURE;
352
241
        break;
353
242
      }
354
243
    }
356
245
       read from stdin */
357
246
    fputc('\n', stderr);
358
247
    if(debug and not quit_now){
359
 
      /* If quit_now is nonzero, we were interrupted by a signal, and
 
248
      /* If quit_now is true, we were interrupted by a signal, and
360
249
         will print that later, so no need to show this too. */
361
250
      fprintf(stderr, "getline() returned 0, retrying.\n");
362
251
    }
363
252
  }
364
 
  
 
253
 
365
254
  free(buffer);
366
255
  
367
 
  if(debug){
 
256
  if (debug){
368
257
    fprintf(stderr, "Restoring terminal attributes\n");
369
258
  }
370
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
259
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
371
260
    perror("tcsetattr+echo");
372
261
  }
373
262
  
374
 
  if(quit_now){
375
 
    sigemptyset(&old_action.sa_mask);
376
 
    old_action.sa_handler = SIG_DFL;
377
 
    ret = sigaction(signal_received, &old_action, NULL);
378
 
    if(ret == -1){
379
 
      perror("sigaction");
380
 
    }
381
 
    raise(signal_received);
382
 
  }
383
 
  
384
 
  if(debug){
 
263
  if (debug){
385
264
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
386
265
            status);
387
266
  }
388
 
  if(status == EXIT_SUCCESS or status == EX_OK){
 
267
  if(status == EXIT_SUCCESS){
389
268
    fputc('\n', stderr);
390
269
  }
391
270