/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: 2019-03-12 20:13:34 UTC
  • Revision ID: teddy@recompile.se-20190312201334-my3htrprewjosuw5
mandos-ctl: Refactor

* mandos-ctl: Reorder everything into logical order; put main() first,
              and put every subsequent definition as soon as possible
              after its first use, except superclasses which need to
              be placed before the classes inheriting from them.
              Reorder all tests to match.

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
7
 
 * 
8
 
 * This program is free software: you can redistribute it and/or
9
 
 * modify it under the terms of the GNU General Public License as
10
 
 * published by the Free Software Foundation, either version 3 of the
11
 
 * License, or (at your option) any later version.
12
 
 * 
13
 
 * This program is distributed in the hope that it will be useful, but
 
5
 * Copyright © 2008-2019 Teddy Hogeborn
 
6
 * Copyright © 2008-2019 Björn Påhlsson
 
7
 * 
 
8
 * This file is part of Mandos.
 
9
 * 
 
10
 * Mandos is free software: you can redistribute it and/or modify it
 
11
 * under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation, either version 3 of the License, or
 
13
 * (at your option) any later version.
 
14
 * 
 
15
 * Mandos is distributed in the hope that it will be useful, but
14
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
18
 * General Public License for more details.
17
19
 * 
18
20
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program.  If not, see
20
 
 * <http://www.gnu.org/licenses/>.
 
21
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
21
22
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
23
 * Contact the authors at <mandos@recompile.se>.
23
24
 */
24
25
 
25
26
#define _GNU_SOURCE             /* getline(), asprintf() */
41
42
                                   getenv(), free() */
42
43
#include <dirent.h>             /* scandir(), alphasort() */
43
44
#include <stdio.h>              /* fprintf(), stderr, getline(),
44
 
                                   stdin, feof(), fputc()
45
 
                                */
 
45
                                   stdin, feof(), fputc(), vfprintf(),
 
46
                                   vasprintf() */
46
47
#include <errno.h>              /* errno, EBADF, ENOTTY, EINVAL,
47
48
                                   EFAULT, EFBIG, EIO, ENOSPC, EINTR
48
49
                                */
51
52
#include <stdbool.h>            /* bool, false, true */
52
53
#include <inttypes.h>           /* strtoumax() */
53
54
#include <sys/stat.h>           /* struct stat, lstat(), open() */
54
 
#include <string.h>             /* strlen, rindex, memcmp */
 
55
#include <string.h>             /* strlen, rindex, memcmp, strerror()
 
56
                                 */
55
57
#include <argp.h>               /* struct argp_option, struct
56
58
                                   argp_state, struct argp,
57
59
                                   argp_parse(), error_t,
60
62
#include <sysexits.h>           /* EX_SOFTWARE, EX_OSERR,
61
63
                                   EX_UNAVAILABLE, EX_IOERR, EX_OK */
62
64
#include <fcntl.h>              /* open() */
 
65
#include <stdarg.h>             /* va_list, va_start(), ... */
63
66
 
64
67
volatile sig_atomic_t quit_now = 0;
65
68
int signal_received;
66
69
bool debug = false;
67
70
const char *argp_program_version = "password-prompt " VERSION;
68
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
71
const char *argp_program_bug_address = "<mandos@recompile.se>";
69
72
 
70
73
/* Needed for conflict resolution */
71
74
const char plymouth_name[] = "plymouthd";
72
75
 
 
76
/* Function to use when printing errors */
 
77
__attribute__((format (gnu_printf, 3, 4)))
 
78
void error_plus(int status, int errnum, const char *formatstring,
 
79
                ...){
 
80
  va_list ap;
 
81
  char *text;
 
82
  int ret;
 
83
  
 
84
  va_start(ap, formatstring);
 
85
  ret = vasprintf(&text, formatstring, ap);
 
86
  if(ret == -1){
 
87
    fprintf(stderr, "Mandos plugin %s: ",
 
88
            program_invocation_short_name);
 
89
    vfprintf(stderr, formatstring, ap);
 
90
    fprintf(stderr, ": %s\n", strerror(errnum));
 
91
    error(status, errno, "vasprintf while printing error");
 
92
    return;
 
93
  }
 
94
  fprintf(stderr, "Mandos plugin ");
 
95
  error(status, errnum, "%s", text);
 
96
  free(text);
 
97
}
 
98
 
73
99
static void termination_handler(int signum){
74
100
  if(quit_now){
75
101
    return;
84
110
     from the terminal.  Password-prompt will exit if it detects
85
111
     plymouth since plymouth performs the same functionality.
86
112
   */
 
113
  __attribute__((nonnull))
87
114
  int is_plymouth(const struct dirent *proc_entry){
88
115
    int ret;
89
116
    int cl_fd;
90
117
    {
91
 
      uintmax_t maxvalue;
 
118
      uintmax_t proc_id;
92
119
      char *tmp;
93
120
      errno = 0;
94
 
      maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
121
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
95
122
      
96
123
      if(errno != 0 or *tmp != '\0'
97
 
         or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
124
         or proc_id != (uintmax_t)((pid_t)proc_id)){
98
125
        return 0;
99
126
      }
100
127
    }
103
130
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
104
131
                   proc_entry->d_name);
105
132
    if(ret == -1){
106
 
      error(0, errno, "asprintf");
 
133
      error_plus(0, errno, "asprintf");
107
134
      return 0;
108
135
    }
109
136
    
112
139
    free(cmdline_filename);
113
140
    if(cl_fd == -1){
114
141
      if(errno != ENOENT){
115
 
        error(0, errno, "open");
 
142
        error_plus(0, errno, "open");
116
143
      }
117
144
      return 0;
118
145
    }
129
156
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
130
157
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
131
158
          if(tmp == NULL){
132
 
            error(0, errno, "realloc");
 
159
            error_plus(0, errno, "realloc");
133
160
            free(cmdline);
134
161
            close(cl_fd);
135
162
            return 0;
142
169
        sret = read(cl_fd, cmdline + cmdline_len,
143
170
                    cmdline_allocated - cmdline_len);
144
171
        if(sret == -1){
145
 
          error(0, errno, "read");
 
172
          error_plus(0, errno, "read");
146
173
          free(cmdline);
147
174
          close(cl_fd);
148
175
          return 0;
151
178
      } while(sret != 0);
152
179
      ret = close(cl_fd);
153
180
      if(ret == -1){
154
 
        error(0, errno, "close");
 
181
        error_plus(0, errno, "close");
155
182
        free(cmdline);
156
183
        return 0;
157
184
      }
183
210
    return 1;
184
211
  }
185
212
  
186
 
  struct dirent **direntries;
 
213
  struct dirent **direntries = NULL;
187
214
  int ret;
188
215
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
189
 
  if (ret == -1){
190
 
    error(1, errno, "scandir");
191
 
  }
 
216
  if(ret == -1){
 
217
    error_plus(1, errno, "scandir");
 
218
  }
 
219
  {
 
220
    int i = ret;
 
221
    while(i--){
 
222
      free(direntries[i]);
 
223
    }
 
224
  }
 
225
  free(direntries);
192
226
  return ret > 0;
193
227
}
194
228
 
223
257
      { .name = NULL }
224
258
    };
225
259
    
 
260
    __attribute__((nonnull(3)))
226
261
    error_t parse_opt (int key, char *arg, struct argp_state *state){
227
262
      errno = 0;
228
263
      switch (key){
239
274
        argp_state_help(state, state->out_stream,
240
275
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
241
276
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
277
        __builtin_unreachable();
242
278
      case -3:                  /* --usage */
243
279
        argp_state_help(state, state->out_stream,
244
280
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
281
        __builtin_unreachable();
245
282
      case 'V':                 /* --version */
246
283
        fprintf(state->out_stream, "%s\n", argp_program_version);
247
284
        exit(argp_err_exit_status);
264
301
    case ENOMEM:
265
302
    default:
266
303
      errno = ret;
267
 
      error(0, errno, "argp_parse");
 
304
      error_plus(0, errno, "argp_parse");
268
305
      return EX_OSERR;
269
306
    case EINVAL:
270
307
      return EX_USAGE;
275
312
    fprintf(stderr, "Starting %s\n", argv[0]);
276
313
  }
277
314
 
278
 
  if (conflict_detection()){
 
315
  if(conflict_detection()){
279
316
    if(debug){
280
317
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
281
318
    }
288
325
  
289
326
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
290
327
    int e = errno;
291
 
    error(0, errno, "tcgetattr");
 
328
    error_plus(0, errno, "tcgetattr");
292
329
    switch(e){
293
330
    case EBADF:
294
331
    case ENOTTY:
301
338
  sigemptyset(&new_action.sa_mask);
302
339
  ret = sigaddset(&new_action.sa_mask, SIGINT);
303
340
  if(ret == -1){
304
 
    error(0, errno, "sigaddset");
 
341
    error_plus(0, errno, "sigaddset");
305
342
    return EX_OSERR;
306
343
  }
307
344
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
308
345
  if(ret == -1){
309
 
    error(0, errno, "sigaddset");
 
346
    error_plus(0, errno, "sigaddset");
310
347
    return EX_OSERR;
311
348
  }
312
349
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
313
350
  if(ret == -1){
314
 
    error(0, errno, "sigaddset");
 
351
    error_plus(0, errno, "sigaddset");
315
352
    return EX_OSERR;
316
353
  }
317
354
  /* Need to check if the handler is SIG_IGN before handling:
320
357
  */
321
358
  ret = sigaction(SIGINT, NULL, &old_action);
322
359
  if(ret == -1){
323
 
    error(0, errno, "sigaction");
 
360
    error_plus(0, errno, "sigaction");
324
361
    return EX_OSERR;
325
362
  }
326
363
  if(old_action.sa_handler != SIG_IGN){
327
364
    ret = sigaction(SIGINT, &new_action, NULL);
328
365
    if(ret == -1){
329
 
      error(0, errno, "sigaction");
 
366
      error_plus(0, errno, "sigaction");
330
367
      return EX_OSERR;
331
368
    }
332
369
  }
333
370
  ret = sigaction(SIGHUP, NULL, &old_action);
334
371
  if(ret == -1){
335
 
    error(0, errno, "sigaction");
 
372
    error_plus(0, errno, "sigaction");
336
373
    return EX_OSERR;
337
374
  }
338
375
  if(old_action.sa_handler != SIG_IGN){
339
376
    ret = sigaction(SIGHUP, &new_action, NULL);
340
377
    if(ret == -1){
341
 
      error(0, errno, "sigaction");
 
378
      error_plus(0, errno, "sigaction");
342
379
      return EX_OSERR;
343
380
    }
344
381
  }
345
382
  ret = sigaction(SIGTERM, NULL, &old_action);
346
383
  if(ret == -1){
347
 
    error(0, errno, "sigaction");
 
384
    error_plus(0, errno, "sigaction");
348
385
    return EX_OSERR;
349
386
  }
350
387
  if(old_action.sa_handler != SIG_IGN){
351
388
    ret = sigaction(SIGTERM, &new_action, NULL);
352
389
    if(ret == -1){
353
 
      error(0, errno, "sigaction");
 
390
      error_plus(0, errno, "sigaction");
354
391
      return EX_OSERR;
355
392
    }
356
393
  }
364
401
  t_new.c_lflag &= ~(tcflag_t)ECHO;
365
402
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
366
403
    int e = errno;
367
 
    error(0, errno, "tcsetattr-echo");
 
404
    error_plus(0, errno, "tcsetattr-echo");
368
405
    switch(e){
369
406
    case EBADF:
370
407
    case ENOTTY:
434
471
        sret = write(STDOUT_FILENO, buffer + written, n - written);
435
472
        if(sret < 0){
436
473
          int e = errno;
437
 
          error(0, errno, "write");
 
474
          error_plus(0, errno, "write");
438
475
          switch(e){
439
476
          case EBADF:
440
477
          case EFAULT:
456
493
      sret = close(STDOUT_FILENO);
457
494
      if(sret == -1){
458
495
        int e = errno;
459
 
        error(0, errno, "close");
 
496
        error_plus(0, errno, "close");
460
497
        switch(e){
461
498
        case EBADF:
462
499
          status = EX_OSFILE;
472
509
    if(sret < 0){
473
510
      int e = errno;
474
511
      if(errno != EINTR and not feof(stdin)){
475
 
        error(0, errno, "getline");
 
512
        error_plus(0, errno, "getline");
476
513
        switch(e){
477
514
        case EBADF:
478
515
          status = EX_UNAVAILABLE;
 
516
          break;
479
517
        case EIO:
480
518
        case EINVAL:
481
519
        default:
501
539
    fprintf(stderr, "Restoring terminal attributes\n");
502
540
  }
503
541
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
504
 
    error(0, errno, "tcsetattr+echo");
 
542
    error_plus(0, errno, "tcsetattr+echo");
505
543
  }
506
544
  
507
545
  if(quit_now){
509
547
    old_action.sa_handler = SIG_DFL;
510
548
    ret = sigaction(signal_received, &old_action, NULL);
511
549
    if(ret == -1){
512
 
      error(0, errno, "sigaction");
 
550
      error_plus(0, errno, "sigaction");
513
551
    }
514
552
    raise(signal_received);
515
553
  }