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