/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: 2015-01-25 00:02:51 UTC
  • Revision ID: teddy@recompile.se-20150125000251-j2bw50gfq9smqyxe
mandos.xml (SEE ALSO): Update links.

Update link to GnuPG home page, change reference from TLS 1.1 to TLS
1.2, and change to latest RFC for using OpenPGP keys with TLS (and use
its correct title).

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Password-prompt - 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-2014 Teddy Hogeborn
 
6
 * Copyright © 2008-2014 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 <mandos@recompile.se>.
23
23
 */
24
24
 
25
25
#define _GNU_SOURCE             /* getline(), asprintf() */
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,
41
41
                                   getenv(), free() */
42
42
#include <dirent.h>             /* scandir(), alphasort() */
43
43
#include <stdio.h>              /* fprintf(), stderr, getline(),
44
 
                                   stdin, feof(), fputc()
45
 
                                */
 
44
                                   stdin, feof(), fputc(), vfprintf(),
 
45
                                   vasprintf() */
46
46
#include <errno.h>              /* errno, EBADF, ENOTTY, EINVAL,
47
47
                                   EFAULT, EFBIG, EIO, ENOSPC, EINTR
48
48
                                */
50
50
#include <iso646.h>             /* or, not */
51
51
#include <stdbool.h>            /* bool, false, true */
52
52
#include <inttypes.h>           /* strtoumax() */
53
 
#include <sys/stat.h>           /* struct stat, lstat(), open() */
54
 
#include <string.h>             /* strlen, rindex, memcmp */
 
53
#include <sys/stat.h>           /* struct stat, lstat(), open() */
 
54
#include <string.h>             /* strlen, rindex, memcmp, strerror()
 
55
                                 */
55
56
#include <argp.h>               /* struct argp_option, struct
56
57
                                   argp_state, struct argp,
57
58
                                   argp_parse(), error_t,
60
61
#include <sysexits.h>           /* EX_SOFTWARE, EX_OSERR,
61
62
                                   EX_UNAVAILABLE, EX_IOERR, EX_OK */
62
63
#include <fcntl.h>              /* open() */
 
64
#include <stdarg.h>             /* va_list, va_start(), ... */
63
65
 
64
66
volatile sig_atomic_t quit_now = 0;
65
67
int signal_received;
66
68
bool debug = false;
67
69
const char *argp_program_version = "password-prompt " VERSION;
68
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
69
 
 
70
 
/* Needed for conflic resolution */
71
 
const char plymouthd_name[] = "plymouthd";
72
 
 
 
70
const char *argp_program_bug_address = "<mandos@recompile.se>";
 
71
 
 
72
/* Needed for conflict resolution */
 
73
const char plymouth_name[] = "plymouthd";
 
74
 
 
75
/* Function to use when printing errors */
 
76
__attribute__((format (gnu_printf, 3, 4)))
 
77
void error_plus(int status, int errnum, const char *formatstring,
 
78
                ...){
 
79
  va_list ap;
 
80
  char *text;
 
81
  int ret;
 
82
  
 
83
  va_start(ap, formatstring);
 
84
  ret = vasprintf(&text, formatstring, ap);
 
85
  if(ret == -1){
 
86
    fprintf(stderr, "Mandos plugin %s: ",
 
87
            program_invocation_short_name);
 
88
    vfprintf(stderr, formatstring, ap);
 
89
    fprintf(stderr, ": %s\n", strerror(errnum));
 
90
    error(status, errno, "vasprintf while printing error");
 
91
    return;
 
92
  }
 
93
  fprintf(stderr, "Mandos plugin ");
 
94
  error(status, errnum, "%s", text);
 
95
  free(text);
 
96
}
73
97
 
74
98
static void termination_handler(int signum){
75
99
  if(quit_now){
85
109
     from the terminal.  Password-prompt will exit if it detects
86
110
     plymouth since plymouth performs the same functionality.
87
111
   */
 
112
  __attribute__((nonnull))
88
113
  int is_plymouth(const struct dirent *proc_entry){
89
114
    int ret;
90
115
    int cl_fd;
91
116
    {
92
 
      uintmax_t maxvalue;
 
117
      uintmax_t proc_id;
93
118
      char *tmp;
94
119
      errno = 0;
95
 
      maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
120
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
96
121
      
97
122
      if(errno != 0 or *tmp != '\0'
98
 
         or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
123
         or proc_id != (uintmax_t)((pid_t)proc_id)){
99
124
        return 0;
100
125
      }
101
126
    }
102
127
    
103
128
    char *cmdline_filename;
104
 
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline", proc_entry->d_name);
 
129
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
 
130
                   proc_entry->d_name);
105
131
    if(ret == -1){
106
 
      error(0, errno, "asprintf");
 
132
      error_plus(0, errno, "asprintf");
107
133
      return 0;
108
134
    }
109
135
    
110
 
    /* Open /proc/<pid>/cmdline  */
 
136
    /* Open /proc/<pid>/cmdline */
111
137
    cl_fd = open(cmdline_filename, O_RDONLY);
112
138
    free(cmdline_filename);
113
139
    if(cl_fd == -1){
114
 
      error(0, errno, "open");
 
140
      if(errno != ENOENT){
 
141
        error_plus(0, errno, "open");
 
142
      }
115
143
      return 0;
116
144
    }
117
145
    
127
155
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
128
156
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
129
157
          if(tmp == NULL){
130
 
            error(0, errno, "realloc");
 
158
            error_plus(0, errno, "realloc");
131
159
            free(cmdline);
132
160
            close(cl_fd);
133
161
            return 0;
140
168
        sret = read(cl_fd, cmdline + cmdline_len,
141
169
                    cmdline_allocated - cmdline_len);
142
170
        if(sret == -1){
143
 
          error(0, errno, "read");
 
171
          error_plus(0, errno, "read");
144
172
          free(cmdline);
145
173
          close(cl_fd);
146
174
          return 0;
149
177
      } while(sret != 0);
150
178
      ret = close(cl_fd);
151
179
      if(ret == -1){
152
 
        error(0, errno, "close");
 
180
        error_plus(0, errno, "close");
153
181
        free(cmdline);
154
182
        return 0;
155
183
      }
165
193
      cmdline_base = cmdline;
166
194
    }
167
195
    
168
 
    if(strcmp(cmdline_base, plymouthd_name) != 0){
 
196
    if(strcmp(cmdline_base, plymouth_name) != 0){
 
197
      if(debug){
 
198
        fprintf(stderr, "\"%s\" is not \"%s\"\n", cmdline_base,
 
199
                plymouth_name);
 
200
      }
169
201
      free(cmdline);
170
202
      return 0;
171
203
    }
 
204
    if(debug){
 
205
      fprintf(stderr, "\"%s\" equals \"%s\"\n", cmdline_base,
 
206
              plymouth_name);
 
207
    }
172
208
    free(cmdline);
173
209
    return 1;
174
210
  }
175
 
 
176
 
  struct dirent **direntries;
 
211
  
 
212
  struct dirent **direntries = NULL;
177
213
  int ret;
178
214
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
179
 
  if (ret == -1){
180
 
    error(1, errno, "scandir");
 
215
  if(ret == -1){
 
216
    error_plus(1, errno, "scandir");
181
217
  }
 
218
  free(direntries);
182
219
  return ret > 0;
183
220
}
184
221
 
213
250
      { .name = NULL }
214
251
    };
215
252
    
 
253
    __attribute__((nonnull(3)))
216
254
    error_t parse_opt (int key, char *arg, struct argp_state *state){
217
255
      errno = 0;
218
256
      switch (key){
254
292
    case ENOMEM:
255
293
    default:
256
294
      errno = ret;
257
 
      error(0, errno, "argp_parse");
 
295
      error_plus(0, errno, "argp_parse");
258
296
      return EX_OSERR;
259
297
    case EINVAL:
260
298
      return EX_USAGE;
265
303
    fprintf(stderr, "Starting %s\n", argv[0]);
266
304
  }
267
305
 
268
 
  if (conflict_detection()){
 
306
  if(conflict_detection()){
269
307
    if(debug){
270
 
      fprintf(stderr, "Stopping %s because of conflict", argv[0]);
 
308
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
271
309
    }
272
310
    return EXIT_FAILURE;
273
311
  }
278
316
  
279
317
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
280
318
    int e = errno;
281
 
    error(0, errno, "tcgetattr");
 
319
    error_plus(0, errno, "tcgetattr");
282
320
    switch(e){
283
321
    case EBADF:
284
322
    case ENOTTY:
291
329
  sigemptyset(&new_action.sa_mask);
292
330
  ret = sigaddset(&new_action.sa_mask, SIGINT);
293
331
  if(ret == -1){
294
 
    error(0, errno, "sigaddset");
 
332
    error_plus(0, errno, "sigaddset");
295
333
    return EX_OSERR;
296
334
  }
297
335
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
298
336
  if(ret == -1){
299
 
    error(0, errno, "sigaddset");
 
337
    error_plus(0, errno, "sigaddset");
300
338
    return EX_OSERR;
301
339
  }
302
340
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
303
341
  if(ret == -1){
304
 
    error(0, errno, "sigaddset");
 
342
    error_plus(0, errno, "sigaddset");
305
343
    return EX_OSERR;
306
344
  }
307
345
  /* Need to check if the handler is SIG_IGN before handling:
310
348
  */
311
349
  ret = sigaction(SIGINT, NULL, &old_action);
312
350
  if(ret == -1){
313
 
    error(0, errno, "sigaction");
 
351
    error_plus(0, errno, "sigaction");
314
352
    return EX_OSERR;
315
353
  }
316
354
  if(old_action.sa_handler != SIG_IGN){
317
355
    ret = sigaction(SIGINT, &new_action, NULL);
318
356
    if(ret == -1){
319
 
      error(0, errno, "sigaction");
 
357
      error_plus(0, errno, "sigaction");
320
358
      return EX_OSERR;
321
359
    }
322
360
  }
323
361
  ret = sigaction(SIGHUP, NULL, &old_action);
324
362
  if(ret == -1){
325
 
    error(0, errno, "sigaction");
 
363
    error_plus(0, errno, "sigaction");
326
364
    return EX_OSERR;
327
365
  }
328
366
  if(old_action.sa_handler != SIG_IGN){
329
367
    ret = sigaction(SIGHUP, &new_action, NULL);
330
368
    if(ret == -1){
331
 
      error(0, errno, "sigaction");
 
369
      error_plus(0, errno, "sigaction");
332
370
      return EX_OSERR;
333
371
    }
334
372
  }
335
373
  ret = sigaction(SIGTERM, NULL, &old_action);
336
374
  if(ret == -1){
337
 
    error(0, errno, "sigaction");
 
375
    error_plus(0, errno, "sigaction");
338
376
    return EX_OSERR;
339
377
  }
340
378
  if(old_action.sa_handler != SIG_IGN){
341
379
    ret = sigaction(SIGTERM, &new_action, NULL);
342
380
    if(ret == -1){
343
 
      error(0, errno, "sigaction");
 
381
      error_plus(0, errno, "sigaction");
344
382
      return EX_OSERR;
345
383
    }
346
384
  }
354
392
  t_new.c_lflag &= ~(tcflag_t)ECHO;
355
393
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
356
394
    int e = errno;
357
 
    error(0, errno, "tcsetattr-echo");
 
395
    error_plus(0, errno, "tcsetattr-echo");
358
396
    switch(e){
359
397
    case EBADF:
360
398
    case ENOTTY:
424
462
        sret = write(STDOUT_FILENO, buffer + written, n - written);
425
463
        if(sret < 0){
426
464
          int e = errno;
427
 
          error(0, errno, "write");
 
465
          error_plus(0, errno, "write");
428
466
          switch(e){
429
467
          case EBADF:
430
468
          case EFAULT:
446
484
      sret = close(STDOUT_FILENO);
447
485
      if(sret == -1){
448
486
        int e = errno;
449
 
        error(0, errno, "close");
 
487
        error_plus(0, errno, "close");
450
488
        switch(e){
451
489
        case EBADF:
452
490
          status = EX_OSFILE;
462
500
    if(sret < 0){
463
501
      int e = errno;
464
502
      if(errno != EINTR and not feof(stdin)){
465
 
        error(0, errno, "getline");
 
503
        error_plus(0, errno, "getline");
466
504
        switch(e){
467
505
        case EBADF:
468
506
          status = EX_UNAVAILABLE;
 
507
          break;
469
508
        case EIO:
470
509
        case EINVAL:
471
510
        default:
475
514
        break;
476
515
      }
477
516
    }
478
 
    /* if(sret == 0), then the only sensible thing to do is to retry to
479
 
       read from stdin */
 
517
    /* if(sret == 0), then the only sensible thing to do is to retry
 
518
       to read from stdin */
480
519
    fputc('\n', stderr);
481
520
    if(debug and not quit_now){
482
521
      /* If quit_now is nonzero, we were interrupted by a signal, and
491
530
    fprintf(stderr, "Restoring terminal attributes\n");
492
531
  }
493
532
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
494
 
    error(0, errno, "tcsetattr+echo");
 
533
    error_plus(0, errno, "tcsetattr+echo");
495
534
  }
496
535
  
497
536
  if(quit_now){
499
538
    old_action.sa_handler = SIG_DFL;
500
539
    ret = sigaction(signal_received, &old_action, NULL);
501
540
    if(ret == -1){
502
 
      error(0, errno, "sigaction");
 
541
      error_plus(0, errno, "sigaction");
503
542
    }
504
543
    raise(signal_received);
505
544
  }