/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

  • Committer: Teddy Hogeborn
  • Date: 2008-08-16 03:29:08 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080816032908-ihw7c05r2mnyk389
Add feature to specify custom environment variables for plugins.

* plugin-runner.c (plugin): New members "environ" and "envc" to
                            contain possible custom environment.
  (getplugin): Return NULL on failure instead of doing exit(); all
               callers changed.
  (add_to_char_array): New helper function for "add_argument" and
                       "add_environment".
  (addargument): Renamed to "add_argument".  Return bool.  Call
                 "add_to_char_array" to actually do things.
  (add_environment): New; analogous to "add_argument".
  (addcustomargument): Renamed to "add_to_argv" to avoid confusion
                       with "add_argument".
  (main): New options "--global-envs" and "--envs-for" to specify
          custom environment for plugins.  Print environment for
          plugins in debug mode.  Use asprintf instead of strcpy and
          strcat.  Use execve() for plugins with custom environments.
          Free environment for plugin when freeing plugin list.

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 Teddy Hogeborn
6
 
 * Copyright © 2008-2019, 2021 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, ssize_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 <argp.h>               /* struct argp_option, struct
 
48
                                   argp_state, struct argp,
 
49
                                   argp_parse(), error_t,
 
50
                                   ARGP_KEY_ARG, ARGP_KEY_END,
 
51
                                   ARGP_ERR_UNKNOWN */
72
52
 
73
 
volatile sig_atomic_t quit_now = 0;
74
 
int signal_received;
 
53
volatile bool quit_now = false;
75
54
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
 
 
 
55
const char *argp_program_version = "password-prompt 1.0";
 
56
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
57
 
 
58
static void termination_handler(__attribute__((unused))int signum){
 
59
  quit_now = true;
 
60
}
239
61
 
240
62
int main(int argc, char **argv){
241
 
  ssize_t sret;
242
 
  int ret;
 
63
  ssize_t ret;
243
64
  size_t n;
244
65
  struct termios t_new, t_old;
245
66
  char *buffer = NULL;
246
67
  char *prefix = NULL;
247
 
  char *prompt = NULL;
248
68
  int status = EXIT_SUCCESS;
249
69
  struct sigaction old_action,
250
70
    new_action = { .sa_handler = termination_handler,
253
73
    struct argp_option options[] = {
254
74
      { .name = "prefix", .key = 'p',
255
75
        .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 },
 
76
        .doc = "Prefix used before the passprompt", .group = 2 },
260
77
      { .name = "debug", .key = 128,
261
78
        .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
79
      { .name = NULL }
272
80
    };
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 */
 
81
  
 
82
    error_t parse_opt (int key, char *arg, struct argp_state *state) {
 
83
      /* Get the INPUT argument from `argp_parse', which we know is a
 
84
         pointer to our plugin list pointer. */
 
85
      switch (key) {
 
86
      case 'p':
279
87
        prefix = arg;
280
88
        break;
281
 
      case 128:                 /* --debug */
 
89
      case 128:
282
90
        debug = true;
283
91
        break;
284
 
      case 129:                 /* --prompt */
285
 
        prompt = arg;
 
92
      case ARGP_KEY_ARG:
 
93
        argp_usage (state);
286
94
        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);
 
95
      case ARGP_KEY_END:
302
96
        break;
303
97
      default:
304
98
        return ARGP_ERR_UNKNOWN;
305
99
      }
306
 
      return errno;
 
100
      return 0;
307
101
    }
308
 
    
 
102
  
309
103
    struct argp argp = { .options = options, .parser = parse_opt,
310
104
                         .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);
315
 
    switch(ret){
316
 
    case 0:
317
 
      break;
318
 
    case ENOMEM:
319
 
    default:
320
 
      errno = ret;
321
 
      error_plus(0, errno, "argp_parse");
322
 
      return EX_OSERR;
323
 
    case EINVAL:
324
 
      return EX_USAGE;
 
105
                         .doc = "Mandos Passprompt -- Provides a passprompt" };
 
106
    ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
107
    if (ret == ARGP_ERR_UNKNOWN){
 
108
      fprintf(stderr, "Unknown error while parsing arguments\n");
 
109
      return EXIT_FAILURE;
325
110
    }
326
111
  }
327
 
  
328
 
  if(debug){
 
112
    
 
113
  if (debug){
329
114
    fprintf(stderr, "Starting %s\n", argv[0]);
330
115
  }
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){
 
116
  if (debug){
340
117
    fprintf(stderr, "Storing current terminal attributes\n");
341
118
  }
342
119
  
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
 
    }
 
120
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
 
121
    return EXIT_FAILURE;
353
122
  }
354
123
  
355
124
  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
 
  */
 
125
  sigaddset(&new_action.sa_mask, SIGINT);
 
126
  sigaddset(&new_action.sa_mask, SIGHUP);
 
127
  sigaddset(&new_action.sa_mask, SIGTERM);
375
128
  ret = sigaction(SIGINT, NULL, &old_action);
376
129
  if(ret == -1){
377
 
    error_plus(0, errno, "sigaction");
378
 
    return EX_OSERR;
 
130
    perror("sigaction");
 
131
    return EXIT_FAILURE;
379
132
  }
380
 
  if(old_action.sa_handler != SIG_IGN){
 
133
  if (old_action.sa_handler != SIG_IGN){
381
134
    ret = sigaction(SIGINT, &new_action, NULL);
382
135
    if(ret == -1){
383
 
      error_plus(0, errno, "sigaction");
384
 
      return EX_OSERR;
 
136
      perror("sigaction");
 
137
      return EXIT_FAILURE;
385
138
    }
386
139
  }
387
140
  ret = sigaction(SIGHUP, NULL, &old_action);
388
141
  if(ret == -1){
389
 
    error_plus(0, errno, "sigaction");
390
 
    return EX_OSERR;
 
142
    perror("sigaction");
 
143
    return EXIT_FAILURE;
391
144
  }
392
 
  if(old_action.sa_handler != SIG_IGN){
 
145
  if (old_action.sa_handler != SIG_IGN){
393
146
    ret = sigaction(SIGHUP, &new_action, NULL);
394
147
    if(ret == -1){
395
 
      error_plus(0, errno, "sigaction");
396
 
      return EX_OSERR;
 
148
      perror("sigaction");
 
149
      return EXIT_FAILURE;
397
150
    }
398
151
  }
399
152
  ret = sigaction(SIGTERM, NULL, &old_action);
400
153
  if(ret == -1){
401
 
    error_plus(0, errno, "sigaction");
402
 
    return EX_OSERR;
 
154
    perror("sigaction");
 
155
    return EXIT_FAILURE;
403
156
  }
404
 
  if(old_action.sa_handler != SIG_IGN){
 
157
  if (old_action.sa_handler != SIG_IGN){
405
158
    ret = sigaction(SIGTERM, &new_action, NULL);
406
159
    if(ret == -1){
407
 
      error_plus(0, errno, "sigaction");
408
 
      return EX_OSERR;
 
160
      perror("sigaction");
 
161
      return EXIT_FAILURE;
409
162
    }
410
163
  }
411
164
  
412
165
  
413
 
  if(debug){
 
166
  if (debug){
414
167
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
415
168
  }
416
169
  
417
170
  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
 
    }
 
171
  t_new.c_lflag &= ~ECHO;
 
172
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
 
173
    perror("tcsetattr-echo");
 
174
    return EXIT_FAILURE;
430
175
  }
431
 
  
432
 
  if(debug){
 
176
 
 
177
  if (debug){
433
178
    fprintf(stderr, "Waiting for input from stdin \n");
434
179
  }
435
180
  while(true){
436
 
    if(quit_now){
437
 
      if(debug){
438
 
        fprintf(stderr, "Interrupted by signal, exiting.\n");
439
 
      }
 
181
    if (quit_now){
440
182
      status = EXIT_FAILURE;
441
183
      break;
442
184
    }
443
185
 
444
186
    if(prefix){
445
 
      fprintf(stderr, "%s ", prefix);
446
 
    }
447
 
    if(prompt != NULL){
448
 
      fprintf(stderr, "%s: ", prompt);
 
187
      fprintf(stderr, "%s Password: ", prefix);
449
188
    } 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){
 
189
      fprintf(stderr, "Password: ");
 
190
    }      
 
191
    ret = getline(&buffer, &n, stdin);
 
192
    if (ret > 0){
 
193
      fprintf(stdout, "%s", buffer);
480
194
      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
195
      break;
527
196
    }
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
 
        }
 
197
    if (ret < 0){
 
198
      if (errno != EINTR and not feof(stdin)){
 
199
        perror("getline");
 
200
        status = EXIT_FAILURE;
 
201
        break;
547
202
      }
548
203
    }
549
 
    /* if(sret == 0), then the only sensible thing to do is to retry
550
 
       to read from stdin */
 
204
    /* if(ret == 0), then the only sensible thing to do is to retry to
 
205
       read from stdin */
551
206
    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
207
  }
558
208
  
559
 
  free(buffer);
560
 
  
561
 
  if(debug){
 
209
  if (debug){
562
210
    fprintf(stderr, "Restoring terminal attributes\n");
563
211
  }
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);
 
212
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
213
    perror("tcsetattr+echo");
 
214
  }
 
215
  
 
216
  if (debug){
 
217
    fprintf(stderr, "%s is exiting\n", argv[0]);
584
218
  }
585
219
  
586
220
  return status;