/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-2019, 2021-2022 Teddy Hogeborn
6
 
 * Copyright © 2008-2019, 2021-2022 Björn Påhlsson
7
 
 * 
8
 
 * This file is part of Mandos.
9
 
 * 
10
 
 * Mandos is free software: you can redistribute it and/or modify it
11
 
 * under the terms of the GNU General Public License as published by
12
 
 * the Free Software Foundation, either version 3 of the License, or
13
 
 * (at your option) any later version.
14
 
 * 
15
 
 * Mandos is distributed in the hope that it will be useful, but
 
3
 * Passprompt - Read a password from the terminal and print it
 
4
 *
 
5
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
6
 * 
 
7
 * This program is free software: you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License as
 
9
 * published by the Free Software Foundation, either version 3 of the
 
10
 * License, or (at your option) any later version.
 
11
 * 
 
12
 * This program is distributed in the hope that it will be useful, but
16
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
17
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
15
 * General Public License for more details.
19
16
 * 
20
17
 * You should have received a copy of the GNU General Public License
21
 
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
 
18
 * along with this program.  If not, see
 
19
 * <http://www.gnu.org/licenses/>.
22
20
 * 
23
 
 * Contact the authors at <mandos@recompile.se>.
 
21
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
22
 * <https://www.fukt.bsnet.se/~teddy/>.
24
23
 */
25
24
 
26
 
#define _GNU_SOURCE             /* vasprintf(),
27
 
                                   program_invocation_short_name,
28
 
                                   asprintf(), getline() */
29
 
#include <sys/types.h>          /* sig_atomic_t, pid_t */
 
25
#define _GNU_SOURCE             /* getline() */
 
26
 
 
27
#include <termios.h>            /* struct termios, tcsetattr(),
 
28
                                   TCSAFLUSH, tcgetattr(), ECHO */
 
29
#include <unistd.h>             /* struct termios, tcsetattr(),
 
30
                                   STDIN_FILENO, TCSAFLUSH,
 
31
                                   tcgetattr(), ECHO */
 
32
#include <signal.h>             /* sig_atomic_t, raise(), struct
 
33
                                   sigaction, sigemptyset(),
 
34
                                   sigaction(), sigaddset(), SIGINT,
 
35
                                   SIGQUIT, SIGHUP, SIGTERM */
 
36
#include <stddef.h>             /* NULL, size_t */
 
37
#include <sys/types.h>          /* ssize_t */
 
38
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
 
39
                                   getopt_long */
 
40
#include <stdio.h>              /* fprintf(), stderr, getline(),
 
41
                                   stdin, feof(), perror(), fputc(),
 
42
                                   stdout, getopt_long */
 
43
#include <errno.h>              /* errno, EINVAL */
 
44
#include <iso646.h>             /* or, not */
30
45
#include <stdbool.h>            /* bool, false, true */
31
 
#include <argp.h>               /* argp_program_version,
32
 
                                   argp_program_bug_address,
33
 
                                   struct argp_option,
34
 
                                   struct argp_state, argp_state_help,
35
 
                                   ARGP_HELP_STD_HELP,
36
 
                                   ARGP_HELP_EXIT_ERR,
37
 
                                   ARGP_HELP_EXIT_OK, ARGP_HELP_USAGE,
38
 
                                   argp_err_exit_status,
39
 
                                   ARGP_ERR_UNKNOWN, argp_parse(),
40
 
                                   ARGP_IN_ORDER, ARGP_NO_HELP */
41
 
#include <stdarg.h>             /* va_list, va_start(), vfprintf() */
42
 
#include <stdio.h>              /* vasprintf(), fprintf(), stderr,
43
 
                                   vfprintf(), asprintf(), getline(),
44
 
                                   stdin, feof(), clearerr(),
45
 
                                   fputc() */
46
 
#include <errno.h>              /* program_invocation_short_name,
47
 
                                   errno, ENOENT, error_t, ENOMEM,
48
 
                                   EINVAL, EBADF, ENOTTY, EFAULT,
49
 
                                   EFBIG, EIO, ENOSPC, EINTR */
50
 
#include <string.h>             /* strerror(), strrchr(), strcmp() */
51
 
#include <error.h>              /* error() */
52
 
#include <stdlib.h>             /* free(), realloc(), EXIT_SUCCESS,
53
 
                                   EXIT_FAILURE, getenv() */
54
 
#include <unistd.h>             /* access(), R_OK, ssize_t, close(),
55
 
                                   read(), STDIN_FILENO, write(),
56
 
                                   STDOUT_FILENO */
57
 
#include <dirent.h>             /* struct dirent, scandir(),
58
 
                                   alphasort() */
59
 
#include <inttypes.h>           /* uintmax_t, strtoumax() */
60
 
#include <iso646.h>             /* or, and, not */
61
 
#include <fcntl.h>              /* open(), O_RDONLY */
62
 
#include <stddef.h>             /* NULL, size_t */
63
 
#include <termios.h>            /* struct termios, tcgetattr(),
64
 
                                   tcflag_t, ECHO, tcsetattr(),
65
 
                                   TCSAFLUSH */
66
 
#include <signal.h>             /* struct sigaction, sigemptyset(),
67
 
                                   sigaddset(), SIGINT, SIGHUP,
68
 
                                   SIGTERM, SIG_IGN, SIG_DFL,
69
 
                                   raise() */
70
 
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
71
 
                                   EX_IOERR, EX_OSFILE, EX_OK */
 
46
#include <string.h>             /* strlen, rindex, strncmp, strcmp */
 
47
#include <getopt.h>             /* getopt_long */
72
48
 
73
 
volatile sig_atomic_t quit_now = 0;
74
 
int signal_received;
 
49
volatile bool quit_now = false;
75
50
bool debug = false;
76
 
const char *argp_program_version = "password-prompt " VERSION;
77
 
const char *argp_program_bug_address = "<mandos@recompile.se>";
78
 
 
79
 
/* Needed for conflict resolution */
80
 
const char plymouth_name[] = "plymouthd";
81
 
 
82
 
/* Function to use when printing errors */
83
 
__attribute__((format (gnu_printf, 3, 4)))
84
 
void error_plus(int status, int errnum, const char *formatstring,
85
 
                ...){
86
 
  va_list ap;
87
 
  char *text;
88
 
  int ret;
89
 
  
90
 
  va_start(ap, formatstring);
91
 
  ret = vasprintf(&text, formatstring, ap);
92
 
  if(ret == -1){
93
 
    fprintf(stderr, "Mandos plugin %s: ",
94
 
            program_invocation_short_name);
95
 
    vfprintf(stderr, formatstring, ap);
96
 
    fprintf(stderr, ": %s\n", strerror(errnum));
97
 
    error(status, errno, "vasprintf while printing error");
98
 
    return;
99
 
  }
100
 
  fprintf(stderr, "Mandos plugin ");
101
 
  error(status, errnum, "%s", text);
102
 
  free(text);
103
 
}
104
 
 
105
 
static void termination_handler(int signum){
106
 
  if(quit_now){
107
 
    return;
108
 
  }
109
 
  quit_now = 1;
110
 
  signal_received = signum;
111
 
}
112
 
 
113
 
bool conflict_detection(void){
114
 
 
115
 
  /* plymouth conflicts with password-prompt since both want to read
116
 
     from the terminal.  Password-prompt will exit if it detects
117
 
     plymouth since plymouth performs the same functionality.
118
 
   */
119
 
  if(access("/run/plymouth/pid", R_OK) == 0){
120
 
    return true;
121
 
  }
122
 
  
123
 
  __attribute__((nonnull))
124
 
  int is_plymouth(const struct dirent *proc_entry){
125
 
    int ret;
126
 
    int cl_fd;
127
 
    {
128
 
      uintmax_t proc_id;
129
 
      char *tmp;
130
 
      errno = 0;
131
 
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
132
 
      
133
 
      if(errno != 0 or *tmp != '\0'
134
 
         or proc_id != (uintmax_t)((pid_t)proc_id)){
135
 
        return 0;
136
 
      }
137
 
    }
138
 
    
139
 
    char *cmdline_filename;
140
 
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
141
 
                   proc_entry->d_name);
142
 
    if(ret == -1){
143
 
      error_plus(0, errno, "asprintf");
144
 
      return 0;
145
 
    }
146
 
    
147
 
    /* Open /proc/<pid>/cmdline */
148
 
    cl_fd = open(cmdline_filename, O_RDONLY);
149
 
    free(cmdline_filename);
150
 
    if(cl_fd == -1){
151
 
      if(errno != ENOENT){
152
 
        error_plus(0, errno, "open");
153
 
      }
154
 
      return 0;
155
 
    }
156
 
    
157
 
    char *cmdline = NULL;
158
 
    {
159
 
      size_t cmdline_len = 0;
160
 
      size_t cmdline_allocated = 0;
161
 
      char *tmp;
162
 
      const size_t blocksize = 1024;
163
 
      ssize_t sret;
164
 
      do {
165
 
        /* Allocate more space? */
166
 
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
167
 
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
168
 
          if(tmp == NULL){
169
 
            error_plus(0, errno, "realloc");
170
 
            free(cmdline);
171
 
            close(cl_fd);
172
 
            return 0;
173
 
          }
174
 
          cmdline = tmp;
175
 
          cmdline_allocated += blocksize;
176
 
        }
177
 
        
178
 
        /* Read data */
179
 
        sret = read(cl_fd, cmdline + cmdline_len,
180
 
                    cmdline_allocated - cmdline_len);
181
 
        if(sret == -1){
182
 
          error_plus(0, errno, "read");
183
 
          free(cmdline);
184
 
          close(cl_fd);
185
 
          return 0;
186
 
        }
187
 
        cmdline_len += (size_t)sret;
188
 
      } while(sret != 0);
189
 
      ret = close(cl_fd);
190
 
      if(ret == -1){
191
 
        error_plus(0, errno, "close");
192
 
        free(cmdline);
193
 
        return 0;
194
 
      }
195
 
      cmdline[cmdline_len] = '\0'; /* Make sure it is terminated */
196
 
    }
197
 
    /* we now have cmdline */
198
 
    
199
 
    /* get basename */
200
 
    char *cmdline_base = strrchr(cmdline, '/');
201
 
    if(cmdline_base != NULL){
202
 
      cmdline_base += 1;                /* skip the slash */
203
 
    } else {
204
 
      cmdline_base = cmdline;
205
 
    }
206
 
    
207
 
    if(strcmp(cmdline_base, plymouth_name) != 0){
208
 
      if(debug){
209
 
        fprintf(stderr, "\"%s\" is not \"%s\"\n", cmdline_base,
210
 
                plymouth_name);
211
 
      }
212
 
      free(cmdline);
213
 
      return 0;
214
 
    }
215
 
    if(debug){
216
 
      fprintf(stderr, "\"%s\" equals \"%s\"\n", cmdline_base,
217
 
              plymouth_name);
218
 
    }
219
 
    free(cmdline);
220
 
    return 1;
221
 
  }
222
 
  
223
 
  struct dirent **direntries = NULL;
224
 
  int ret;
225
 
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
226
 
  if(ret == -1){
227
 
    error_plus(1, errno, "scandir");
228
 
  }
229
 
  {
230
 
    int i = ret;
231
 
    while(i--){
232
 
      free(direntries[i]);
233
 
    }
234
 
  }
235
 
  free(direntries);
236
 
  return ret > 0;
237
 
}
238
 
 
 
51
 
 
52
void termination_handler(__attribute__((unused))int signum){
 
53
  quit_now = true;
 
54
}
239
55
 
240
56
int main(int argc, char **argv){
241
 
  ssize_t sret;
242
 
  int ret;
 
57
  ssize_t ret;
243
58
  size_t n;
244
59
  struct termios t_new, t_old;
245
60
  char *buffer = NULL;
246
61
  char *prefix = NULL;
247
 
  char *prompt = NULL;
248
62
  int status = EXIT_SUCCESS;
249
63
  struct sigaction old_action,
250
64
    new_action = { .sa_handler = termination_handler,
251
65
                   .sa_flags = 0 };
252
 
  {
253
 
    struct argp_option options[] = {
254
 
      { .name = "prefix", .key = 'p',
255
 
        .arg = "PREFIX", .flags = 0,
256
 
        .doc = "Prefix shown before the prompt", .group = 2 },
257
 
      { .name = "prompt", .key = 129,
258
 
        .arg = "PROMPT", .flags = 0,
259
 
        .doc = "The prompt to show", .group = 2 },
260
 
      { .name = "debug", .key = 128,
261
 
        .doc = "Debug mode", .group = 3 },
262
 
      /*
263
 
       * These reproduce what we would get without ARGP_NO_HELP
264
 
       */
265
 
      { .name = "help", .key = '?',
266
 
        .doc = "Give this help list", .group = -1 },
267
 
      { .name = "usage", .key = -3,
268
 
        .doc = "Give a short usage message", .group = -1 },
269
 
      { .name = "version", .key = 'V',
270
 
        .doc = "Print program version", .group = -1 },
271
 
      { .name = NULL }
272
 
    };
273
 
    
274
 
    __attribute__((nonnull(3)))
275
 
    error_t parse_opt (int key, char *arg, struct argp_state *state){
276
 
      errno = 0;
277
 
      switch (key){
278
 
      case 'p':                 /* --prefix */
279
 
        prefix = arg;
280
 
        break;
281
 
      case 128:                 /* --debug */
282
 
        debug = true;
283
 
        break;
284
 
      case 129:                 /* --prompt */
285
 
        prompt = arg;
286
 
        break;
287
 
        /*
288
 
         * These reproduce what we would get without ARGP_NO_HELP
289
 
         */
290
 
      case '?':                 /* --help */
291
 
        argp_state_help(state, state->out_stream,
292
 
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
293
 
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
294
 
        __builtin_unreachable();
295
 
      case -3:                  /* --usage */
296
 
        argp_state_help(state, state->out_stream,
297
 
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
298
 
        __builtin_unreachable();
299
 
      case 'V':                 /* --version */
300
 
        fprintf(state->out_stream, "%s\n", argp_program_version);
301
 
        exit(argp_err_exit_status);
302
 
        break;
303
 
      default:
304
 
        return ARGP_ERR_UNKNOWN;
305
 
      }
306
 
      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;
307
78
    }
308
 
    
309
 
    struct argp argp = { .options = options, .parser = parse_opt,
310
 
                         .args_doc = "",
311
 
                         .doc = "Mandos password-prompt -- Read and"
312
 
                         " output a password" };
313
 
    ret = argp_parse(&argp, argc, argv,
314
 
                     ARGP_IN_ORDER | ARGP_NO_HELP, NULL, NULL);
 
79
      
315
80
    switch(ret){
316
81
    case 0:
317
82
      break;
318
 
    case ENOMEM:
 
83
    case 'p':
 
84
      prefix = optarg;
 
85
      break;
319
86
    default:
320
 
      errno = ret;
321
 
      error_plus(0, errno, "argp_parse");
322
 
      return EX_OSERR;
323
 
    case EINVAL:
324
 
      return EX_USAGE;
 
87
      fprintf(stderr, "bad arguments\n");
 
88
      exit(EXIT_FAILURE);
325
89
    }
326
90
  }
327
 
  
328
 
  if(debug){
 
91
      
 
92
  if (debug){
329
93
    fprintf(stderr, "Starting %s\n", argv[0]);
330
94
  }
331
 
 
332
 
  if(conflict_detection()){
333
 
    if(debug){
334
 
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
335
 
    }
336
 
    return EXIT_FAILURE;
337
 
  }
338
 
  
339
 
  if(debug){
 
95
  if (debug){
340
96
    fprintf(stderr, "Storing current terminal attributes\n");
341
97
  }
342
98
  
343
 
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
344
 
    int e = errno;
345
 
    error_plus(0, errno, "tcgetattr");
346
 
    switch(e){
347
 
    case EBADF:
348
 
    case ENOTTY:
349
 
      return EX_UNAVAILABLE;
350
 
    default:
351
 
      return EX_OSERR;
352
 
    }
 
99
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
 
100
    return EXIT_FAILURE;
353
101
  }
354
102
  
355
103
  sigemptyset(&new_action.sa_mask);
356
 
  ret = sigaddset(&new_action.sa_mask, SIGINT);
357
 
  if(ret == -1){
358
 
    error_plus(0, errno, "sigaddset");
359
 
    return EX_OSERR;
360
 
  }
361
 
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
362
 
  if(ret == -1){
363
 
    error_plus(0, errno, "sigaddset");
364
 
    return EX_OSERR;
365
 
  }
366
 
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
367
 
  if(ret == -1){
368
 
    error_plus(0, errno, "sigaddset");
369
 
    return EX_OSERR;
370
 
  }
371
 
  /* Need to check if the handler is SIG_IGN before handling:
372
 
     | [[info:libc:Initial Signal Actions]] |
373
 
     | [[info:libc:Basic Signal Handling]]  |
374
 
  */
375
 
  ret = sigaction(SIGINT, NULL, &old_action);
376
 
  if(ret == -1){
377
 
    error_plus(0, errno, "sigaction");
378
 
    return EX_OSERR;
379
 
  }
380
 
  if(old_action.sa_handler != SIG_IGN){
381
 
    ret = sigaction(SIGINT, &new_action, NULL);
382
 
    if(ret == -1){
383
 
      error_plus(0, errno, "sigaction");
384
 
      return EX_OSERR;
385
 
    }
386
 
  }
387
 
  ret = sigaction(SIGHUP, NULL, &old_action);
388
 
  if(ret == -1){
389
 
    error_plus(0, errno, "sigaction");
390
 
    return EX_OSERR;
391
 
  }
392
 
  if(old_action.sa_handler != SIG_IGN){
393
 
    ret = sigaction(SIGHUP, &new_action, NULL);
394
 
    if(ret == -1){
395
 
      error_plus(0, errno, "sigaction");
396
 
      return EX_OSERR;
397
 
    }
398
 
  }
399
 
  ret = sigaction(SIGTERM, NULL, &old_action);
400
 
  if(ret == -1){
401
 
    error_plus(0, errno, "sigaction");
402
 
    return EX_OSERR;
403
 
  }
404
 
  if(old_action.sa_handler != SIG_IGN){
405
 
    ret = sigaction(SIGTERM, &new_action, NULL);
406
 
    if(ret == -1){
407
 
      error_plus(0, errno, "sigaction");
408
 
      return EX_OSERR;
409
 
    }
410
 
  }
411
 
  
412
 
  
413
 
  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){
414
119
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
415
120
  }
416
121
  
417
122
  t_new = t_old;
418
 
  t_new.c_lflag &= ~(tcflag_t)ECHO;
419
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
420
 
    int e = errno;
421
 
    error_plus(0, errno, "tcsetattr-echo");
422
 
    switch(e){
423
 
    case EBADF:
424
 
    case ENOTTY:
425
 
      return EX_UNAVAILABLE;
426
 
    case EINVAL:
427
 
    default:
428
 
      return EX_OSERR;
429
 
    }
 
123
  t_new.c_lflag &= ~ECHO;
 
124
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
 
125
    perror("tcsetattr-echo");
 
126
    return EXIT_FAILURE;
430
127
  }
431
 
  
432
 
  if(debug){
 
128
 
 
129
  if (debug){
433
130
    fprintf(stderr, "Waiting for input from stdin \n");
434
131
  }
435
132
  while(true){
436
 
    if(quit_now){
437
 
      if(debug){
438
 
        fprintf(stderr, "Interrupted by signal, exiting.\n");
439
 
      }
 
133
    if (quit_now){
440
134
      status = EXIT_FAILURE;
441
135
      break;
442
136
    }
443
137
 
444
138
    if(prefix){
445
 
      fprintf(stderr, "%s ", prefix);
446
 
    }
447
 
    if(prompt != NULL){
448
 
      fprintf(stderr, "%s: ", prompt);
 
139
      fprintf(stderr, "%s Password: ", prefix);
449
140
    } else {
450
 
      const char *cryptsource = getenv("CRYPTTAB_SOURCE");
451
 
      const char *crypttarget = getenv("CRYPTTAB_NAME");
452
 
      /* Before cryptsetup 1.1.0~rc2 */
453
 
      if(cryptsource == NULL){
454
 
        cryptsource = getenv("cryptsource");
455
 
      }
456
 
      if(crypttarget == NULL){
457
 
        crypttarget = getenv("crypttarget");
458
 
      }
459
 
      const char *const prompt1 = "Unlocking the disk";
460
 
      const char *const prompt2 = "Enter passphrase";
461
 
      if(cryptsource == NULL){
462
 
        if(crypttarget == NULL){
463
 
          fprintf(stderr, "%s to unlock the disk: ", prompt2);
464
 
        } else {
465
 
          fprintf(stderr, "%s (%s)\n%s: ", prompt1, crypttarget,
466
 
                  prompt2);
467
 
        }
468
 
      } else {
469
 
        if(crypttarget == NULL){
470
 
          fprintf(stderr, "%s %s\n%s: ", prompt1, cryptsource,
471
 
                  prompt2);
472
 
        } else {
473
 
          fprintf(stderr, "%s %s (%s)\n%s: ", prompt1, cryptsource,
474
 
                  crypttarget, prompt2);
475
 
        }
476
 
      }
477
 
    }
478
 
    sret = getline(&buffer, &n, stdin);
479
 
    if(sret > 0){
 
141
      fprintf(stderr, "Password: ");
 
142
    }      
 
143
    ret = getline(&buffer, &n, stdin);
 
144
    if (ret > 0){
 
145
      fprintf(stdout, "%s", buffer);
480
146
      status = EXIT_SUCCESS;
481
 
      /* Make n = data size instead of allocated buffer size */
482
 
      n = (size_t)sret;
483
 
      /* Strip final newline */
484
 
      if(n > 0 and buffer[n-1] == '\n'){
485
 
        buffer[n-1] = '\0';     /* not strictly necessary */
486
 
        n--;
487
 
      }
488
 
      size_t written = 0;
489
 
      while(written < n){
490
 
        sret = write(STDOUT_FILENO, buffer + written, n - written);
491
 
        if(sret < 0){
492
 
          int e = errno;
493
 
          error_plus(0, errno, "write");
494
 
          switch(e){
495
 
          case EBADF:
496
 
          case EFAULT:
497
 
          case EINVAL:
498
 
          case EFBIG:
499
 
          case EIO:
500
 
          case ENOSPC:
501
 
          default:
502
 
            status = EX_IOERR;
503
 
            break;
504
 
          case EINTR:
505
 
            status = EXIT_FAILURE;
506
 
            break;
507
 
          }
508
 
          break;
509
 
        }
510
 
        written += (size_t)sret;
511
 
      }
512
 
      sret = close(STDOUT_FILENO);
513
 
      if(sret == -1){
514
 
        int e = errno;
515
 
        error_plus(0, errno, "close");
516
 
        switch(e){
517
 
        case EBADF:
518
 
          status = EX_OSFILE;
519
 
          break;
520
 
        case EIO:
521
 
        default:
522
 
          status = EX_IOERR;
523
 
          break;
524
 
        }
525
 
      }
526
147
      break;
527
148
    }
528
 
    if(sret < 0){
529
 
      int e = errno;
530
 
      if(errno != EINTR){
531
 
        if(not feof(stdin)){
532
 
          error_plus(0, errno, "getline");
533
 
          switch(e){
534
 
          case EBADF:
535
 
            status = EX_UNAVAILABLE;
536
 
            break;
537
 
          case EIO:
538
 
          case EINVAL:
539
 
          default:
540
 
            status = EX_IOERR;
541
 
            break;
542
 
          }
543
 
          break;
544
 
        } else {
545
 
          clearerr(stdin);
546
 
        }
 
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)){
 
152
        perror("getline");
 
153
        status = EXIT_FAILURE;
 
154
        break;
547
155
      }
548
156
    }
549
 
    /* if(sret == 0), then the only sensible thing to do is to retry
550
 
       to read from stdin */
551
157
    fputc('\n', stderr);
552
 
    if(debug and not quit_now){
553
 
      /* If quit_now is nonzero, we were interrupted by a signal, and
554
 
         will print that later, so no need to show this too. */
555
 
      fprintf(stderr, "getline() returned 0, retrying.\n");
556
 
    }
557
158
  }
558
 
  
559
 
  free(buffer);
560
 
  
561
 
  if(debug){
 
159
 
 
160
  if (debug){
562
161
    fprintf(stderr, "Restoring terminal attributes\n");
563
162
  }
564
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
565
 
    error_plus(0, errno, "tcsetattr+echo");
566
 
  }
567
 
  
568
 
  if(quit_now){
569
 
    sigemptyset(&old_action.sa_mask);
570
 
    old_action.sa_handler = SIG_DFL;
571
 
    ret = sigaction(signal_received, &old_action, NULL);
572
 
    if(ret == -1){
573
 
      error_plus(0, errno, "sigaction");
574
 
    }
575
 
    raise(signal_received);
576
 
  }
577
 
  
578
 
  if(debug){
579
 
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
580
 
            status);
581
 
  }
582
 
  if(status == EXIT_SUCCESS or status == EX_OK){
583
 
    fputc('\n', stderr);
 
163
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
164
    perror("tcsetattr+echo");
 
165
  }
 
166
 
 
167
  if (debug){
 
168
    fprintf(stderr, "%s is exiting\n", argv[0]);
584
169
  }
585
170
  
586
171
  return status;