/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,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 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
 
#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
__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
}
64
107
 
65
108
static void termination_handler(int signum){
66
109
  if(quit_now){
70
113
  signal_received = signum;
71
114
}
72
115
 
 
116
bool conflict_detection(void){
 
117
 
 
118
  /* plymouth conflicts with password-prompt since both want to read
 
119
     from the terminal.  Password-prompt will exit if it detects
 
120
     plymouth since plymouth performs the same functionality.
 
121
   */
 
122
  __attribute__((nonnull))
 
123
  int is_plymouth(const struct dirent *proc_entry){
 
124
    int ret;
 
125
    int cl_fd;
 
126
    {
 
127
      uintmax_t proc_id;
 
128
      char *tmp;
 
129
      errno = 0;
 
130
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
 
131
      
 
132
      if(errno != 0 or *tmp != '\0'
 
133
         or proc_id != (uintmax_t)((pid_t)proc_id)){
 
134
        return 0;
 
135
      }
 
136
    }
 
137
    
 
138
    char *cmdline_filename;
 
139
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
 
140
                   proc_entry->d_name);
 
141
    if(ret == -1){
 
142
      error_plus(0, errno, "asprintf");
 
143
      return 0;
 
144
    }
 
145
    
 
146
    /* Open /proc/<pid>/cmdline */
 
147
    cl_fd = open(cmdline_filename, O_RDONLY);
 
148
    free(cmdline_filename);
 
149
    if(cl_fd == -1){
 
150
      if(errno != ENOENT){
 
151
        error_plus(0, errno, "open");
 
152
      }
 
153
      return 0;
 
154
    }
 
155
    
 
156
    char *cmdline = NULL;
 
157
    {
 
158
      size_t cmdline_len = 0;
 
159
      size_t cmdline_allocated = 0;
 
160
      char *tmp;
 
161
      const size_t blocksize = 1024;
 
162
      ssize_t sret;
 
163
      do {
 
164
        /* Allocate more space? */
 
165
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
 
166
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
 
167
          if(tmp == NULL){
 
168
            error_plus(0, errno, "realloc");
 
169
            free(cmdline);
 
170
            close(cl_fd);
 
171
            return 0;
 
172
          }
 
173
          cmdline = tmp;
 
174
          cmdline_allocated += blocksize;
 
175
        }
 
176
        
 
177
        /* Read data */
 
178
        sret = read(cl_fd, cmdline + cmdline_len,
 
179
                    cmdline_allocated - cmdline_len);
 
180
        if(sret == -1){
 
181
          error_plus(0, errno, "read");
 
182
          free(cmdline);
 
183
          close(cl_fd);
 
184
          return 0;
 
185
        }
 
186
        cmdline_len += (size_t)sret;
 
187
      } while(sret != 0);
 
188
      ret = close(cl_fd);
 
189
      if(ret == -1){
 
190
        error_plus(0, errno, "close");
 
191
        free(cmdline);
 
192
        return 0;
 
193
      }
 
194
      cmdline[cmdline_len] = '\0'; /* Make sure it is terminated */
 
195
    }
 
196
    /* we now have cmdline */
 
197
    
 
198
    /* get basename */
 
199
    char *cmdline_base = strrchr(cmdline, '/');
 
200
    if(cmdline_base != NULL){
 
201
      cmdline_base += 1;                /* skip the slash */
 
202
    } else {
 
203
      cmdline_base = cmdline;
 
204
    }
 
205
    
 
206
    if(strcmp(cmdline_base, plymouth_name) != 0){
 
207
      if(debug){
 
208
        fprintf(stderr, "\"%s\" is not \"%s\"\n", cmdline_base,
 
209
                plymouth_name);
 
210
      }
 
211
      free(cmdline);
 
212
      return 0;
 
213
    }
 
214
    if(debug){
 
215
      fprintf(stderr, "\"%s\" equals \"%s\"\n", cmdline_base,
 
216
              plymouth_name);
 
217
    }
 
218
    free(cmdline);
 
219
    return 1;
 
220
  }
 
221
  
 
222
  struct dirent **direntries = NULL;
 
223
  int ret;
 
224
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
 
225
  if (ret == -1){
 
226
    error_plus(1, errno, "scandir");
 
227
  }
 
228
  free(direntries);
 
229
  return ret > 0;
 
230
}
 
231
 
 
232
 
73
233
int main(int argc, char **argv){
74
234
  ssize_t sret;
75
235
  int ret;
100
260
      { .name = NULL }
101
261
    };
102
262
    
 
263
    __attribute__((nonnull(3)))
103
264
    error_t parse_opt (int key, char *arg, struct argp_state *state){
104
265
      errno = 0;
105
266
      switch (key){
141
302
    case ENOMEM:
142
303
    default:
143
304
      errno = ret;
144
 
      error(0, errno, "argp_parse");
 
305
      error_plus(0, errno, "argp_parse");
145
306
      return EX_OSERR;
146
307
    case EINVAL:
147
308
      return EX_USAGE;
151
312
  if(debug){
152
313
    fprintf(stderr, "Starting %s\n", argv[0]);
153
314
  }
 
315
 
 
316
  if (conflict_detection()){
 
317
    if(debug){
 
318
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
 
319
    }
 
320
    return EXIT_FAILURE;
 
321
  }
 
322
  
154
323
  if(debug){
155
324
    fprintf(stderr, "Storing current terminal attributes\n");
156
325
  }
157
326
  
158
327
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
159
328
    int e = errno;
160
 
    error(0, errno, "tcgetattr");
 
329
    error_plus(0, errno, "tcgetattr");
161
330
    switch(e){
162
331
    case EBADF:
163
332
    case ENOTTY:
170
339
  sigemptyset(&new_action.sa_mask);
171
340
  ret = sigaddset(&new_action.sa_mask, SIGINT);
172
341
  if(ret == -1){
173
 
    error(0, errno, "sigaddset");
 
342
    error_plus(0, errno, "sigaddset");
174
343
    return EX_OSERR;
175
344
  }
176
345
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
177
346
  if(ret == -1){
178
 
    error(0, errno, "sigaddset");
 
347
    error_plus(0, errno, "sigaddset");
179
348
    return EX_OSERR;
180
349
  }
181
350
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
182
351
  if(ret == -1){
183
 
    error(0, errno, "sigaddset");
 
352
    error_plus(0, errno, "sigaddset");
184
353
    return EX_OSERR;
185
354
  }
186
355
  /* Need to check if the handler is SIG_IGN before handling:
189
358
  */
190
359
  ret = sigaction(SIGINT, NULL, &old_action);
191
360
  if(ret == -1){
192
 
    error(0, errno, "sigaction");
 
361
    error_plus(0, errno, "sigaction");
193
362
    return EX_OSERR;
194
363
  }
195
364
  if(old_action.sa_handler != SIG_IGN){
196
365
    ret = sigaction(SIGINT, &new_action, NULL);
197
366
    if(ret == -1){
198
 
      error(0, errno, "sigaction");
 
367
      error_plus(0, errno, "sigaction");
199
368
      return EX_OSERR;
200
369
    }
201
370
  }
202
371
  ret = sigaction(SIGHUP, NULL, &old_action);
203
372
  if(ret == -1){
204
 
    error(0, errno, "sigaction");
 
373
    error_plus(0, errno, "sigaction");
205
374
    return EX_OSERR;
206
375
  }
207
376
  if(old_action.sa_handler != SIG_IGN){
208
377
    ret = sigaction(SIGHUP, &new_action, NULL);
209
378
    if(ret == -1){
210
 
      error(0, errno, "sigaction");
 
379
      error_plus(0, errno, "sigaction");
211
380
      return EX_OSERR;
212
381
    }
213
382
  }
214
383
  ret = sigaction(SIGTERM, NULL, &old_action);
215
384
  if(ret == -1){
216
 
    error(0, errno, "sigaction");
 
385
    error_plus(0, errno, "sigaction");
217
386
    return EX_OSERR;
218
387
  }
219
388
  if(old_action.sa_handler != SIG_IGN){
220
389
    ret = sigaction(SIGTERM, &new_action, NULL);
221
390
    if(ret == -1){
222
 
      error(0, errno, "sigaction");
 
391
      error_plus(0, errno, "sigaction");
223
392
      return EX_OSERR;
224
393
    }
225
394
  }
233
402
  t_new.c_lflag &= ~(tcflag_t)ECHO;
234
403
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
235
404
    int e = errno;
236
 
    error(0, errno, "tcsetattr-echo");
 
405
    error_plus(0, errno, "tcsetattr-echo");
237
406
    switch(e){
238
407
    case EBADF:
239
408
    case ENOTTY:
303
472
        sret = write(STDOUT_FILENO, buffer + written, n - written);
304
473
        if(sret < 0){
305
474
          int e = errno;
306
 
          error(0, errno, "write");
 
475
          error_plus(0, errno, "write");
307
476
          switch(e){
308
477
          case EBADF:
309
478
          case EFAULT:
325
494
      sret = close(STDOUT_FILENO);
326
495
      if(sret == -1){
327
496
        int e = errno;
328
 
        error(0, errno, "close");
 
497
        error_plus(0, errno, "close");
329
498
        switch(e){
330
499
        case EBADF:
331
500
          status = EX_OSFILE;
341
510
    if(sret < 0){
342
511
      int e = errno;
343
512
      if(errno != EINTR and not feof(stdin)){
344
 
        error(0, errno, "getline");
 
513
        error_plus(0, errno, "getline");
345
514
        switch(e){
346
515
        case EBADF:
347
516
          status = EX_UNAVAILABLE;
 
517
          break;
348
518
        case EIO:
349
519
        case EINVAL:
350
520
        default:
354
524
        break;
355
525
      }
356
526
    }
357
 
    /* if(sret == 0), then the only sensible thing to do is to retry to
358
 
       read from stdin */
 
527
    /* if(sret == 0), then the only sensible thing to do is to retry
 
528
       to read from stdin */
359
529
    fputc('\n', stderr);
360
530
    if(debug and not quit_now){
361
531
      /* If quit_now is nonzero, we were interrupted by a signal, and
370
540
    fprintf(stderr, "Restoring terminal attributes\n");
371
541
  }
372
542
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
373
 
    error(0, errno, "tcsetattr+echo");
 
543
    error_plus(0, errno, "tcsetattr+echo");
374
544
  }
375
545
  
376
546
  if(quit_now){
378
548
    old_action.sa_handler = SIG_DFL;
379
549
    ret = sigaction(signal_received, &old_action, NULL);
380
550
    if(ret == -1){
381
 
      error(0, errno, "sigaction");
 
551
      error_plus(0, errno, "sigaction");
382
552
    }
383
553
    raise(signal_received);
384
554
  }