/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/passprompt.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-02 10:48:24 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080802104824-fx0miwp9o4g9r31e
* plugbasedclient.c (struct process): New fields "eof", "completed",
                                      and "status".
  (handle_sigchld): New function.
  (main): Initialize "dir" to NULL to only closedir() it if necessary.
          Move "process_list" to be a global variable to be accessible
          by "handle_sigchld".  Make "handle_sigchld" handle SIGCHLD.
          Remove redundant check for NULL "dir".  Free "filename" when
          no longer used.  Block SIGCHLD around fork()/exec().
          Restore normal signals in child.  Only loop while running
          processes exist.  Print process buffer when the process is
          done and it has emitted EOF, not when it only emits EOF.
          Remove processes from list which exit non-cleanly.  In
          cleaning up, closedir() if necessary.  Bug fix: set next
          pointer correctly when freeing process list.

* plugins.d/passprompt.c (main): Do not ignore SIGQUIT.

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