/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-12-10 01:26:02 UTC
  • mfrom: (237.1.2 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20081210012602-vhz3h75xkj24t340
First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

Show diffs side-by-side

added added

removed removed

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