/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,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 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
 
#define _GNU_SOURCE             /* getline() */
 
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,
31
 
                                   tcgetattr(), ECHO */
 
31
                                   tcgetattr(), ECHO, readlink() */
32
32
#include <signal.h>             /* sig_atomic_t, raise(), struct
33
33
                                   sigaction, sigemptyset(),
34
34
                                   sigaction(), sigaddset(), SIGINT,
35
35
                                   SIGQUIT, SIGHUP, SIGTERM,
36
36
                                   raise() */
37
37
#include <stddef.h>             /* NULL, size_t, ssize_t */
38
 
#include <sys/types.h>          /* ssize_t */
 
38
#include <sys/types.h>          /* ssize_t, struct dirent, pid_t,
 
39
                                   ssize_t, open() */
39
40
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
40
 
                                   getenv() */
 
41
                                   getenv(), free() */
 
42
#include <dirent.h>             /* scandir(), alphasort() */
41
43
#include <stdio.h>              /* fprintf(), stderr, getline(),
42
 
                                   stdin, feof(), fputc()
43
 
                                */
 
44
                                   stdin, feof(), fputc(), vfprintf(),
 
45
                                   vasprintf() */
44
46
#include <errno.h>              /* errno, EBADF, ENOTTY, EINVAL,
45
47
                                   EFAULT, EFBIG, EIO, ENOSPC, EINTR
46
48
                                */
47
49
#include <error.h>              /* error() */
48
50
#include <iso646.h>             /* or, not */
49
51
#include <stdbool.h>            /* bool, false, true */
50
 
#include <string.h>             /* strlen, rindex */
 
52
#include <inttypes.h>           /* strtoumax() */
 
53
#include <sys/stat.h>           /* struct stat, lstat(), open() */
 
54
#include <string.h>             /* strlen, rindex, memcmp, strerror()
 
55
                                 */
51
56
#include <argp.h>               /* struct argp_option, struct
52
57
                                   argp_state, struct argp,
53
58
                                   argp_parse(), error_t,
55
60
                                   ARGP_ERR_UNKNOWN */
56
61
#include <sysexits.h>           /* EX_SOFTWARE, EX_OSERR,
57
62
                                   EX_UNAVAILABLE, EX_IOERR, EX_OK */
 
63
#include <fcntl.h>              /* open() */
 
64
#include <stdarg.h>             /* va_list, va_start(), ... */
58
65
 
59
66
volatile sig_atomic_t quit_now = 0;
60
67
int signal_received;
61
68
bool debug = false;
62
69
const char *argp_program_version = "password-prompt " VERSION;
63
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
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
}
64
97
 
65
98
static void termination_handler(int signum){
66
99
  if(quit_now){
70
103
  signal_received = signum;
71
104
}
72
105
 
 
106
bool conflict_detection(void){
 
107
 
 
108
  /* plymouth conflicts with password-prompt since both want to read
 
109
     from the terminal.  Password-prompt will exit if it detects
 
110
     plymouth since plymouth performs the same functionality.
 
111
   */
 
112
  __attribute__((nonnull))
 
113
  int is_plymouth(const struct dirent *proc_entry){
 
114
    int ret;
 
115
    int cl_fd;
 
116
    {
 
117
      uintmax_t proc_id;
 
118
      char *tmp;
 
119
      errno = 0;
 
120
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
 
121
      
 
122
      if(errno != 0 or *tmp != '\0'
 
123
         or proc_id != (uintmax_t)((pid_t)proc_id)){
 
124
        return 0;
 
125
      }
 
126
    }
 
127
    
 
128
    char *cmdline_filename;
 
129
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
 
130
                   proc_entry->d_name);
 
131
    if(ret == -1){
 
132
      error_plus(0, errno, "asprintf");
 
133
      return 0;
 
134
    }
 
135
    
 
136
    /* Open /proc/<pid>/cmdline */
 
137
    cl_fd = open(cmdline_filename, O_RDONLY);
 
138
    free(cmdline_filename);
 
139
    if(cl_fd == -1){
 
140
      if(errno != ENOENT){
 
141
        error_plus(0, errno, "open");
 
142
      }
 
143
      return 0;
 
144
    }
 
145
    
 
146
    char *cmdline = NULL;
 
147
    {
 
148
      size_t cmdline_len = 0;
 
149
      size_t cmdline_allocated = 0;
 
150
      char *tmp;
 
151
      const size_t blocksize = 1024;
 
152
      ssize_t sret;
 
153
      do {
 
154
        /* Allocate more space? */
 
155
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
 
156
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
 
157
          if(tmp == NULL){
 
158
            error_plus(0, errno, "realloc");
 
159
            free(cmdline);
 
160
            close(cl_fd);
 
161
            return 0;
 
162
          }
 
163
          cmdline = tmp;
 
164
          cmdline_allocated += blocksize;
 
165
        }
 
166
        
 
167
        /* Read data */
 
168
        sret = read(cl_fd, cmdline + cmdline_len,
 
169
                    cmdline_allocated - cmdline_len);
 
170
        if(sret == -1){
 
171
          error_plus(0, errno, "read");
 
172
          free(cmdline);
 
173
          close(cl_fd);
 
174
          return 0;
 
175
        }
 
176
        cmdline_len += (size_t)sret;
 
177
      } while(sret != 0);
 
178
      ret = close(cl_fd);
 
179
      if(ret == -1){
 
180
        error_plus(0, errno, "close");
 
181
        free(cmdline);
 
182
        return 0;
 
183
      }
 
184
      cmdline[cmdline_len] = '\0'; /* Make sure it is terminated */
 
185
    }
 
186
    /* we now have cmdline */
 
187
    
 
188
    /* get basename */
 
189
    char *cmdline_base = strrchr(cmdline, '/');
 
190
    if(cmdline_base != NULL){
 
191
      cmdline_base += 1;                /* skip the slash */
 
192
    } else {
 
193
      cmdline_base = cmdline;
 
194
    }
 
195
    
 
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
      }
 
201
      free(cmdline);
 
202
      return 0;
 
203
    }
 
204
    if(debug){
 
205
      fprintf(stderr, "\"%s\" equals \"%s\"\n", cmdline_base,
 
206
              plymouth_name);
 
207
    }
 
208
    free(cmdline);
 
209
    return 1;
 
210
  }
 
211
  
 
212
  struct dirent **direntries = NULL;
 
213
  int ret;
 
214
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
 
215
  if(ret == -1){
 
216
    error_plus(1, errno, "scandir");
 
217
  }
 
218
  free(direntries);
 
219
  return ret > 0;
 
220
}
 
221
 
 
222
 
73
223
int main(int argc, char **argv){
74
224
  ssize_t sret;
75
225
  int ret;
100
250
      { .name = NULL }
101
251
    };
102
252
    
 
253
    __attribute__((nonnull(3)))
103
254
    error_t parse_opt (int key, char *arg, struct argp_state *state){
104
255
      errno = 0;
105
256
      switch (key){
141
292
    case ENOMEM:
142
293
    default:
143
294
      errno = ret;
144
 
      error(0, errno, "argp_parse");
 
295
      error_plus(0, errno, "argp_parse");
145
296
      return EX_OSERR;
146
297
    case EINVAL:
147
298
      return EX_USAGE;
151
302
  if(debug){
152
303
    fprintf(stderr, "Starting %s\n", argv[0]);
153
304
  }
 
305
 
 
306
  if(conflict_detection()){
 
307
    if(debug){
 
308
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
 
309
    }
 
310
    return EXIT_FAILURE;
 
311
  }
 
312
  
154
313
  if(debug){
155
314
    fprintf(stderr, "Storing current terminal attributes\n");
156
315
  }
157
316
  
158
317
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
159
318
    int e = errno;
160
 
    error(0, errno, "tcgetattr");
 
319
    error_plus(0, errno, "tcgetattr");
161
320
    switch(e){
162
321
    case EBADF:
163
322
    case ENOTTY:
170
329
  sigemptyset(&new_action.sa_mask);
171
330
  ret = sigaddset(&new_action.sa_mask, SIGINT);
172
331
  if(ret == -1){
173
 
    error(0, errno, "sigaddset");
 
332
    error_plus(0, errno, "sigaddset");
174
333
    return EX_OSERR;
175
334
  }
176
335
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
177
336
  if(ret == -1){
178
 
    error(0, errno, "sigaddset");
 
337
    error_plus(0, errno, "sigaddset");
179
338
    return EX_OSERR;
180
339
  }
181
340
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
182
341
  if(ret == -1){
183
 
    error(0, errno, "sigaddset");
 
342
    error_plus(0, errno, "sigaddset");
184
343
    return EX_OSERR;
185
344
  }
186
345
  /* Need to check if the handler is SIG_IGN before handling:
189
348
  */
190
349
  ret = sigaction(SIGINT, NULL, &old_action);
191
350
  if(ret == -1){
192
 
    error(0, errno, "sigaction");
 
351
    error_plus(0, errno, "sigaction");
193
352
    return EX_OSERR;
194
353
  }
195
354
  if(old_action.sa_handler != SIG_IGN){
196
355
    ret = sigaction(SIGINT, &new_action, NULL);
197
356
    if(ret == -1){
198
 
      error(0, errno, "sigaction");
 
357
      error_plus(0, errno, "sigaction");
199
358
      return EX_OSERR;
200
359
    }
201
360
  }
202
361
  ret = sigaction(SIGHUP, NULL, &old_action);
203
362
  if(ret == -1){
204
 
    error(0, errno, "sigaction");
 
363
    error_plus(0, errno, "sigaction");
205
364
    return EX_OSERR;
206
365
  }
207
366
  if(old_action.sa_handler != SIG_IGN){
208
367
    ret = sigaction(SIGHUP, &new_action, NULL);
209
368
    if(ret == -1){
210
 
      error(0, errno, "sigaction");
 
369
      error_plus(0, errno, "sigaction");
211
370
      return EX_OSERR;
212
371
    }
213
372
  }
214
373
  ret = sigaction(SIGTERM, NULL, &old_action);
215
374
  if(ret == -1){
216
 
    error(0, errno, "sigaction");
 
375
    error_plus(0, errno, "sigaction");
217
376
    return EX_OSERR;
218
377
  }
219
378
  if(old_action.sa_handler != SIG_IGN){
220
379
    ret = sigaction(SIGTERM, &new_action, NULL);
221
380
    if(ret == -1){
222
 
      error(0, errno, "sigaction");
 
381
      error_plus(0, errno, "sigaction");
223
382
      return EX_OSERR;
224
383
    }
225
384
  }
233
392
  t_new.c_lflag &= ~(tcflag_t)ECHO;
234
393
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
235
394
    int e = errno;
236
 
    error(0, errno, "tcsetattr-echo");
 
395
    error_plus(0, errno, "tcsetattr-echo");
237
396
    switch(e){
238
397
    case EBADF:
239
398
    case ENOTTY:
303
462
        sret = write(STDOUT_FILENO, buffer + written, n - written);
304
463
        if(sret < 0){
305
464
          int e = errno;
306
 
          error(0, errno, "write");
 
465
          error_plus(0, errno, "write");
307
466
          switch(e){
308
467
          case EBADF:
309
468
          case EFAULT:
325
484
      sret = close(STDOUT_FILENO);
326
485
      if(sret == -1){
327
486
        int e = errno;
328
 
        error(0, errno, "close");
 
487
        error_plus(0, errno, "close");
329
488
        switch(e){
330
489
        case EBADF:
331
490
          status = EX_OSFILE;
341
500
    if(sret < 0){
342
501
      int e = errno;
343
502
      if(errno != EINTR and not feof(stdin)){
344
 
        error(0, errno, "getline");
 
503
        error_plus(0, errno, "getline");
345
504
        switch(e){
346
505
        case EBADF:
347
506
          status = EX_UNAVAILABLE;
 
507
          break;
348
508
        case EIO:
349
509
        case EINVAL:
350
510
        default:
354
514
        break;
355
515
      }
356
516
    }
357
 
    /* if(sret == 0), then the only sensible thing to do is to retry to
358
 
       read from stdin */
 
517
    /* if(sret == 0), then the only sensible thing to do is to retry
 
518
       to read from stdin */
359
519
    fputc('\n', stderr);
360
520
    if(debug and not quit_now){
361
521
      /* If quit_now is nonzero, we were interrupted by a signal, and
370
530
    fprintf(stderr, "Restoring terminal attributes\n");
371
531
  }
372
532
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
373
 
    error(0, errno, "tcsetattr+echo");
 
533
    error_plus(0, errno, "tcsetattr+echo");
374
534
  }
375
535
  
376
536
  if(quit_now){
378
538
    old_action.sa_handler = SIG_DFL;
379
539
    ret = sigaction(signal_received, &old_action, NULL);
380
540
    if(ret == -1){
381
 
      error(0, errno, "sigaction");
 
541
      error_plus(0, errno, "sigaction");
382
542
    }
383
543
    raise(signal_received);
384
544
  }