/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: 2011-12-31 20:07:11 UTC
  • mfrom: (535.1.9 wireless-network-hook)
  • Revision ID: teddy@recompile.se-20111231200711-6dli3r8drftem57r
Merge new wireless network hook.  Fix bridge network hook to use
hardware addresses instead of interface names.  Implement and document
new "CONNECT" environment variable for network hooks.

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-2011 Teddy Hogeborn
 
6
 * Copyright © 2008-2011 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() */
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
                                */
51
51
#include <stdbool.h>            /* bool, false, true */
52
52
#include <inttypes.h>           /* strtoumax() */
53
53
#include <sys/stat.h>           /* struct stat, lstat(), open() */
54
 
#include <string.h>             /* strlen, rindex, memcmp */
 
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>";
 
70
const char *argp_program_bug_address = "<mandos@recompile.se>";
69
71
 
70
72
/* Needed for conflict resolution */
71
73
const char plymouth_name[] = "plymouthd";
72
74
 
 
75
__attribute__((format (gnu_printf, 2, 3), nonnull(1)))
 
76
int fprintf_plus(FILE *stream, const char *format, ...){
 
77
  va_list ap;
 
78
  va_start (ap, format);
 
79
  
 
80
  TEMP_FAILURE_RETRY(fprintf(stream, "Mandos plugin %s: ",
 
81
                             program_invocation_short_name));
 
82
  return TEMP_FAILURE_RETRY(vfprintf(stream, format, ap));
 
83
}
 
84
 
 
85
/* Function to use when printing errors */
 
86
__attribute__((format (gnu_printf, 3, 4)))
 
87
void error_plus(int status, int errnum, const char *formatstring,
 
88
                ...){
 
89
  va_list ap;
 
90
  char *text;
 
91
  int ret;
 
92
  
 
93
  va_start(ap, formatstring);
 
94
  ret = vasprintf(&text, formatstring, ap);
 
95
  if (ret == -1){
 
96
    fprintf(stderr, "Mandos plugin %s: ",
 
97
            program_invocation_short_name);
 
98
    vfprintf(stderr, formatstring, ap);
 
99
    fprintf(stderr, ": %s\n", strerror(errnum));
 
100
    error(status, errno, "vasprintf while printing error");
 
101
    return;
 
102
  }
 
103
  fprintf(stderr, "Mandos plugin ");
 
104
  error(status, errnum, "%s", text);
 
105
  free(text);
 
106
}
 
107
 
73
108
static void termination_handler(int signum){
74
109
  if(quit_now){
75
110
    return;
84
119
     from the terminal.  Password-prompt will exit if it detects
85
120
     plymouth since plymouth performs the same functionality.
86
121
   */
 
122
  __attribute__((nonnull))
87
123
  int is_plymouth(const struct dirent *proc_entry){
88
124
    int ret;
89
125
    int cl_fd;
90
126
    {
91
 
      uintmax_t maxvalue;
 
127
      uintmax_t proc_id;
92
128
      char *tmp;
93
129
      errno = 0;
94
 
      maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
130
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
95
131
      
96
132
      if(errno != 0 or *tmp != '\0'
97
 
         or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
133
         or proc_id != (uintmax_t)((pid_t)proc_id)){
98
134
        return 0;
99
135
      }
100
136
    }
103
139
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
104
140
                   proc_entry->d_name);
105
141
    if(ret == -1){
106
 
      error(0, errno, "asprintf");
 
142
      error_plus(0, errno, "asprintf");
107
143
      return 0;
108
144
    }
109
145
    
112
148
    free(cmdline_filename);
113
149
    if(cl_fd == -1){
114
150
      if(errno != ENOENT){
115
 
        error(0, errno, "open");
 
151
        error_plus(0, errno, "open");
116
152
      }
117
153
      return 0;
118
154
    }
129
165
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
130
166
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
131
167
          if(tmp == NULL){
132
 
            error(0, errno, "realloc");
 
168
            error_plus(0, errno, "realloc");
133
169
            free(cmdline);
134
170
            close(cl_fd);
135
171
            return 0;
142
178
        sret = read(cl_fd, cmdline + cmdline_len,
143
179
                    cmdline_allocated - cmdline_len);
144
180
        if(sret == -1){
145
 
          error(0, errno, "read");
 
181
          error_plus(0, errno, "read");
146
182
          free(cmdline);
147
183
          close(cl_fd);
148
184
          return 0;
151
187
      } while(sret != 0);
152
188
      ret = close(cl_fd);
153
189
      if(ret == -1){
154
 
        error(0, errno, "close");
 
190
        error_plus(0, errno, "close");
155
191
        free(cmdline);
156
192
        return 0;
157
193
      }
183
219
    return 1;
184
220
  }
185
221
  
186
 
  struct dirent **direntries;
 
222
  struct dirent **direntries = NULL;
187
223
  int ret;
188
224
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
189
225
  if (ret == -1){
190
 
    error(1, errno, "scandir");
 
226
    error_plus(1, errno, "scandir");
191
227
  }
 
228
  free(direntries);
192
229
  return ret > 0;
193
230
}
194
231
 
223
260
      { .name = NULL }
224
261
    };
225
262
    
 
263
    __attribute__((nonnull(3)))
226
264
    error_t parse_opt (int key, char *arg, struct argp_state *state){
227
265
      errno = 0;
228
266
      switch (key){
264
302
    case ENOMEM:
265
303
    default:
266
304
      errno = ret;
267
 
      error(0, errno, "argp_parse");
 
305
      error_plus(0, errno, "argp_parse");
268
306
      return EX_OSERR;
269
307
    case EINVAL:
270
308
      return EX_USAGE;
288
326
  
289
327
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
290
328
    int e = errno;
291
 
    error(0, errno, "tcgetattr");
 
329
    error_plus(0, errno, "tcgetattr");
292
330
    switch(e){
293
331
    case EBADF:
294
332
    case ENOTTY:
301
339
  sigemptyset(&new_action.sa_mask);
302
340
  ret = sigaddset(&new_action.sa_mask, SIGINT);
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
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
308
346
  if(ret == -1){
309
 
    error(0, errno, "sigaddset");
 
347
    error_plus(0, errno, "sigaddset");
310
348
    return EX_OSERR;
311
349
  }
312
350
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
313
351
  if(ret == -1){
314
 
    error(0, errno, "sigaddset");
 
352
    error_plus(0, errno, "sigaddset");
315
353
    return EX_OSERR;
316
354
  }
317
355
  /* Need to check if the handler is SIG_IGN before handling:
320
358
  */
321
359
  ret = sigaction(SIGINT, NULL, &old_action);
322
360
  if(ret == -1){
323
 
    error(0, errno, "sigaction");
 
361
    error_plus(0, errno, "sigaction");
324
362
    return EX_OSERR;
325
363
  }
326
364
  if(old_action.sa_handler != SIG_IGN){
327
365
    ret = sigaction(SIGINT, &new_action, NULL);
328
366
    if(ret == -1){
329
 
      error(0, errno, "sigaction");
 
367
      error_plus(0, errno, "sigaction");
330
368
      return EX_OSERR;
331
369
    }
332
370
  }
333
371
  ret = sigaction(SIGHUP, NULL, &old_action);
334
372
  if(ret == -1){
335
 
    error(0, errno, "sigaction");
 
373
    error_plus(0, errno, "sigaction");
336
374
    return EX_OSERR;
337
375
  }
338
376
  if(old_action.sa_handler != SIG_IGN){
339
377
    ret = sigaction(SIGHUP, &new_action, NULL);
340
378
    if(ret == -1){
341
 
      error(0, errno, "sigaction");
 
379
      error_plus(0, errno, "sigaction");
342
380
      return EX_OSERR;
343
381
    }
344
382
  }
345
383
  ret = sigaction(SIGTERM, NULL, &old_action);
346
384
  if(ret == -1){
347
 
    error(0, errno, "sigaction");
 
385
    error_plus(0, errno, "sigaction");
348
386
    return EX_OSERR;
349
387
  }
350
388
  if(old_action.sa_handler != SIG_IGN){
351
389
    ret = sigaction(SIGTERM, &new_action, NULL);
352
390
    if(ret == -1){
353
 
      error(0, errno, "sigaction");
 
391
      error_plus(0, errno, "sigaction");
354
392
      return EX_OSERR;
355
393
    }
356
394
  }
364
402
  t_new.c_lflag &= ~(tcflag_t)ECHO;
365
403
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
366
404
    int e = errno;
367
 
    error(0, errno, "tcsetattr-echo");
 
405
    error_plus(0, errno, "tcsetattr-echo");
368
406
    switch(e){
369
407
    case EBADF:
370
408
    case ENOTTY:
434
472
        sret = write(STDOUT_FILENO, buffer + written, n - written);
435
473
        if(sret < 0){
436
474
          int e = errno;
437
 
          error(0, errno, "write");
 
475
          error_plus(0, errno, "write");
438
476
          switch(e){
439
477
          case EBADF:
440
478
          case EFAULT:
456
494
      sret = close(STDOUT_FILENO);
457
495
      if(sret == -1){
458
496
        int e = errno;
459
 
        error(0, errno, "close");
 
497
        error_plus(0, errno, "close");
460
498
        switch(e){
461
499
        case EBADF:
462
500
          status = EX_OSFILE;
472
510
    if(sret < 0){
473
511
      int e = errno;
474
512
      if(errno != EINTR and not feof(stdin)){
475
 
        error(0, errno, "getline");
 
513
        error_plus(0, errno, "getline");
476
514
        switch(e){
477
515
        case EBADF:
478
516
          status = EX_UNAVAILABLE;
 
517
          break;
479
518
        case EIO:
480
519
        case EINVAL:
481
520
        default:
501
540
    fprintf(stderr, "Restoring terminal attributes\n");
502
541
  }
503
542
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
504
 
    error(0, errno, "tcsetattr+echo");
 
543
    error_plus(0, errno, "tcsetattr+echo");
505
544
  }
506
545
  
507
546
  if(quit_now){
509
548
    old_action.sa_handler = SIG_DFL;
510
549
    ret = sigaction(signal_received, &old_action, NULL);
511
550
    if(ret == -1){
512
 
      error(0, errno, "sigaction");
 
551
      error_plus(0, errno, "sigaction");
513
552
    }
514
553
    raise(signal_received);
515
554
  }