/mandos/release

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

« back to all changes in this revision

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

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