/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/password-prompt.c

  • Committer: Teddy Hogeborn
  • Date: 2021-02-04 17:59:45 UTC
  • mto: This revision was merged to the branch mainline in revision 406.
  • Revision ID: teddy@recompile.se-20210204175945-8druo6d88ipc1z58
Fix issue with french translation

Initial white space was missing in both msgid and msgstr of the french
translation, leading to checking tools reporing an incomplete
translation.  The string is a raw key id, and therefore did not need
translation, so this was never a user-visible issue.

* debian/po/fr.po: Add missing whitespace to the id and translation
  for msgid " ${key_id}".

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, 2021 Teddy Hogeborn
 
6
 * Copyright © 2008-2019, 2021 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
 
#define _GNU_SOURCE             /* getline(), asprintf() */
26
 
 
27
 
#include <termios.h>            /* struct termios, tcsetattr(),
28
 
                                   TCSAFLUSH, tcgetattr(), ECHO */
29
 
#include <unistd.h>             /* struct termios, tcsetattr(),
30
 
                                   STDIN_FILENO, TCSAFLUSH,
31
 
                                   tcgetattr(), ECHO, readlink() */
32
 
#include <signal.h>             /* sig_atomic_t, raise(), struct
33
 
                                   sigaction, sigemptyset(),
34
 
                                   sigaction(), sigaddset(), SIGINT,
35
 
                                   SIGQUIT, SIGHUP, SIGTERM,
 
26
#define _GNU_SOURCE             /* vasprintf(),
 
27
                                   program_invocation_short_name,
 
28
                                   asprintf(), getline() */
 
29
#include <sys/types.h>          /* sig_atomic_t, pid_t */
 
30
#include <stdbool.h>            /* bool, false, true */
 
31
#include <argp.h>               /* argp_program_version,
 
32
                                   argp_program_bug_address,
 
33
                                   struct argp_option,
 
34
                                   struct argp_state, argp_state_help,
 
35
                                   ARGP_HELP_STD_HELP,
 
36
                                   ARGP_HELP_EXIT_ERR,
 
37
                                   ARGP_HELP_EXIT_OK, ARGP_HELP_USAGE,
 
38
                                   argp_err_exit_status,
 
39
                                   ARGP_ERR_UNKNOWN, argp_parse(),
 
40
                                   ARGP_IN_ORDER, ARGP_NO_HELP */
 
41
#include <stdarg.h>             /* va_list, va_start(), vfprintf() */
 
42
#include <stdio.h>              /* vasprintf(), fprintf(), stderr,
 
43
                                   vfprintf(), asprintf(), getline(),
 
44
                                   stdin, feof(), clearerr(),
 
45
                                   fputc() */
 
46
#include <errno.h>              /* program_invocation_short_name,
 
47
                                   errno, ENOENT, error_t, ENOMEM,
 
48
                                   EINVAL, EBADF, ENOTTY, EFAULT,
 
49
                                   EFBIG, EIO, ENOSPC, EINTR */
 
50
#include <string.h>             /* strerror(), strrchr(), strcmp() */
 
51
#include <error.h>              /* error() */
 
52
#include <stdlib.h>             /* free(), realloc(), EXIT_SUCCESS,
 
53
                                   EXIT_FAILURE, getenv() */
 
54
#include <unistd.h>             /* access(), R_OK, ssize_t, close(),
 
55
                                   read(), STDIN_FILENO, write(),
 
56
                                   STDOUT_FILENO */
 
57
#include <dirent.h>             /* struct dirent, scandir(),
 
58
                                   alphasort() */
 
59
#include <inttypes.h>           /* uintmax_t, strtoumax() */
 
60
#include <iso646.h>             /* or, and, not */
 
61
#include <fcntl.h>              /* open(), O_RDONLY */
 
62
#include <stddef.h>             /* NULL, size_t */
 
63
#include <termios.h>            /* struct termios, tcgetattr(),
 
64
                                   tcflag_t, ECHO, tcsetattr(),
 
65
                                   TCSAFLUSH */
 
66
#include <signal.h>             /* struct sigaction, sigemptyset(),
 
67
                                   sigaddset(), SIGINT, SIGHUP,
 
68
                                   SIGTERM, SIG_IGN, SIG_DFL,
36
69
                                   raise() */
37
 
#include <stddef.h>             /* NULL, size_t, ssize_t */
38
 
#include <sys/types.h>          /* ssize_t, struct dirent, pid_t,
39
 
                                   ssize_t, open() */
40
 
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
41
 
                                   getenv(), free() */
42
 
#include <dirent.h>             /* scandir(), alphasort() */
43
 
#include <stdio.h>              /* fprintf(), stderr, getline(),
44
 
                                   stdin, feof(), fputc(), vfprintf(), vasprintf()
45
 
                                */
46
 
#include <errno.h>              /* errno, EBADF, ENOTTY, EINVAL,
47
 
                                   EFAULT, EFBIG, EIO, ENOSPC, EINTR
48
 
                                */
49
 
#include <error.h>              /* error() */
50
 
#include <iso646.h>             /* or, not */
51
 
#include <stdbool.h>            /* bool, false, true */
52
 
#include <inttypes.h>           /* strtoumax() */
53
 
#include <sys/stat.h>           /* struct stat, lstat(), open() */
54
 
#include <string.h>             /* strlen, rindex, memcmp, strerror() */
55
 
#include <argp.h>               /* struct argp_option, struct
56
 
                                   argp_state, struct argp,
57
 
                                   argp_parse(), error_t,
58
 
                                   ARGP_KEY_ARG, ARGP_KEY_END,
59
 
                                   ARGP_ERR_UNKNOWN */
60
 
#include <sysexits.h>           /* EX_SOFTWARE, EX_OSERR,
61
 
                                   EX_UNAVAILABLE, EX_IOERR, EX_OK */
62
 
#include <fcntl.h>              /* open() */
63
 
#include <stdarg.h>             /* va_list, va_start(), ... */
 
70
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
 
71
                                   EX_IOERR, EX_OSFILE, EX_OK */
64
72
 
65
73
volatile sig_atomic_t quit_now = 0;
66
74
int signal_received;
67
75
bool debug = false;
68
76
const char *argp_program_version = "password-prompt " VERSION;
69
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
77
const char *argp_program_bug_address = "<mandos@recompile.se>";
70
78
 
71
79
/* Needed for conflict resolution */
72
80
const char plymouth_name[] = "plymouthd";
73
81
 
74
82
/* Function to use when printing errors */
75
 
void error_plus(int status, int errnum, const char *formatstring, ...){
 
83
__attribute__((format (gnu_printf, 3, 4)))
 
84
void error_plus(int status, int errnum, const char *formatstring,
 
85
                ...){
76
86
  va_list ap;
77
87
  char *text;
78
88
  int ret;
79
89
  
80
90
  va_start(ap, formatstring);
81
91
  ret = vasprintf(&text, formatstring, ap);
82
 
  if (ret == -1){
83
 
    fprintf(stderr, "Mandos plugin %s: ", program_invocation_short_name);
 
92
  if(ret == -1){
 
93
    fprintf(stderr, "Mandos plugin %s: ",
 
94
            program_invocation_short_name);
84
95
    vfprintf(stderr, formatstring, ap);
85
 
    fprintf(stderr, ": ");
86
 
    fprintf(stderr, "%s\n", strerror(errnum));
 
96
    fprintf(stderr, ": %s\n", strerror(errnum));
87
97
    error(status, errno, "vasprintf while printing error");
88
98
    return;
89
99
  }
106
116
     from the terminal.  Password-prompt will exit if it detects
107
117
     plymouth since plymouth performs the same functionality.
108
118
   */
 
119
  if(access("/run/plymouth/pid", R_OK) == 0){
 
120
    return true;
 
121
  }
 
122
  
 
123
  __attribute__((nonnull))
109
124
  int is_plymouth(const struct dirent *proc_entry){
110
125
    int ret;
111
126
    int cl_fd;
112
127
    {
113
 
      uintmax_t maxvalue;
 
128
      uintmax_t proc_id;
114
129
      char *tmp;
115
130
      errno = 0;
116
 
      maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
131
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
117
132
      
118
133
      if(errno != 0 or *tmp != '\0'
119
 
         or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
134
         or proc_id != (uintmax_t)((pid_t)proc_id)){
120
135
        return 0;
121
136
      }
122
137
    }
125
140
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
126
141
                   proc_entry->d_name);
127
142
    if(ret == -1){
128
 
      error(0, errno, "asprintf");
 
143
      error_plus(0, errno, "asprintf");
129
144
      return 0;
130
145
    }
131
146
    
134
149
    free(cmdline_filename);
135
150
    if(cl_fd == -1){
136
151
      if(errno != ENOENT){
137
 
        error(0, errno, "open");
 
152
        error_plus(0, errno, "open");
138
153
      }
139
154
      return 0;
140
155
    }
151
166
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
152
167
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
153
168
          if(tmp == NULL){
154
 
            error(0, errno, "realloc");
 
169
            error_plus(0, errno, "realloc");
155
170
            free(cmdline);
156
171
            close(cl_fd);
157
172
            return 0;
164
179
        sret = read(cl_fd, cmdline + cmdline_len,
165
180
                    cmdline_allocated - cmdline_len);
166
181
        if(sret == -1){
167
 
          error(0, errno, "read");
 
182
          error_plus(0, errno, "read");
168
183
          free(cmdline);
169
184
          close(cl_fd);
170
185
          return 0;
173
188
      } while(sret != 0);
174
189
      ret = close(cl_fd);
175
190
      if(ret == -1){
176
 
        error(0, errno, "close");
 
191
        error_plus(0, errno, "close");
177
192
        free(cmdline);
178
193
        return 0;
179
194
      }
205
220
    return 1;
206
221
  }
207
222
  
208
 
  struct dirent **direntries;
 
223
  struct dirent **direntries = NULL;
209
224
  int ret;
210
225
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
211
 
  if (ret == -1){
212
 
    error(1, errno, "scandir");
213
 
  }
 
226
  if(ret == -1){
 
227
    error_plus(1, errno, "scandir");
 
228
  }
 
229
  {
 
230
    int i = ret;
 
231
    while(i--){
 
232
      free(direntries[i]);
 
233
    }
 
234
  }
 
235
  free(direntries);
214
236
  return ret > 0;
215
237
}
216
238
 
222
244
  struct termios t_new, t_old;
223
245
  char *buffer = NULL;
224
246
  char *prefix = NULL;
 
247
  char *prompt = NULL;
225
248
  int status = EXIT_SUCCESS;
226
249
  struct sigaction old_action,
227
250
    new_action = { .sa_handler = termination_handler,
231
254
      { .name = "prefix", .key = 'p',
232
255
        .arg = "PREFIX", .flags = 0,
233
256
        .doc = "Prefix shown before the prompt", .group = 2 },
 
257
      { .name = "prompt", .key = 129,
 
258
        .arg = "PROMPT", .flags = 0,
 
259
        .doc = "The prompt to show", .group = 2 },
234
260
      { .name = "debug", .key = 128,
235
261
        .doc = "Debug mode", .group = 3 },
236
262
      /*
245
271
      { .name = NULL }
246
272
    };
247
273
    
 
274
    __attribute__((nonnull(3)))
248
275
    error_t parse_opt (int key, char *arg, struct argp_state *state){
249
276
      errno = 0;
250
277
      switch (key){
251
 
      case 'p':
 
278
      case 'p':                 /* --prefix */
252
279
        prefix = arg;
253
280
        break;
254
 
      case 128:
 
281
      case 128:                 /* --debug */
255
282
        debug = true;
256
283
        break;
 
284
      case 129:                 /* --prompt */
 
285
        prompt = arg;
 
286
        break;
257
287
        /*
258
288
         * These reproduce what we would get without ARGP_NO_HELP
259
289
         */
261
291
        argp_state_help(state, state->out_stream,
262
292
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
263
293
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
294
        __builtin_unreachable();
264
295
      case -3:                  /* --usage */
265
296
        argp_state_help(state, state->out_stream,
266
297
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
298
        __builtin_unreachable();
267
299
      case 'V':                 /* --version */
268
300
        fprintf(state->out_stream, "%s\n", argp_program_version);
269
301
        exit(argp_err_exit_status);
286
318
    case ENOMEM:
287
319
    default:
288
320
      errno = ret;
289
 
      error(0, errno, "argp_parse");
 
321
      error_plus(0, errno, "argp_parse");
290
322
      return EX_OSERR;
291
323
    case EINVAL:
292
324
      return EX_USAGE;
297
329
    fprintf(stderr, "Starting %s\n", argv[0]);
298
330
  }
299
331
 
300
 
  if (conflict_detection()){
 
332
  if(conflict_detection()){
301
333
    if(debug){
302
334
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
303
335
    }
310
342
  
311
343
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
312
344
    int e = errno;
313
 
    error(0, errno, "tcgetattr");
 
345
    error_plus(0, errno, "tcgetattr");
314
346
    switch(e){
315
347
    case EBADF:
316
348
    case ENOTTY:
323
355
  sigemptyset(&new_action.sa_mask);
324
356
  ret = sigaddset(&new_action.sa_mask, SIGINT);
325
357
  if(ret == -1){
326
 
    error(0, errno, "sigaddset");
 
358
    error_plus(0, errno, "sigaddset");
327
359
    return EX_OSERR;
328
360
  }
329
361
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
330
362
  if(ret == -1){
331
 
    error(0, errno, "sigaddset");
 
363
    error_plus(0, errno, "sigaddset");
332
364
    return EX_OSERR;
333
365
  }
334
366
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
335
367
  if(ret == -1){
336
 
    error(0, errno, "sigaddset");
 
368
    error_plus(0, errno, "sigaddset");
337
369
    return EX_OSERR;
338
370
  }
339
371
  /* Need to check if the handler is SIG_IGN before handling:
342
374
  */
343
375
  ret = sigaction(SIGINT, NULL, &old_action);
344
376
  if(ret == -1){
345
 
    error(0, errno, "sigaction");
 
377
    error_plus(0, errno, "sigaction");
346
378
    return EX_OSERR;
347
379
  }
348
380
  if(old_action.sa_handler != SIG_IGN){
349
381
    ret = sigaction(SIGINT, &new_action, NULL);
350
382
    if(ret == -1){
351
 
      error(0, errno, "sigaction");
 
383
      error_plus(0, errno, "sigaction");
352
384
      return EX_OSERR;
353
385
    }
354
386
  }
355
387
  ret = sigaction(SIGHUP, NULL, &old_action);
356
388
  if(ret == -1){
357
 
    error(0, errno, "sigaction");
 
389
    error_plus(0, errno, "sigaction");
358
390
    return EX_OSERR;
359
391
  }
360
392
  if(old_action.sa_handler != SIG_IGN){
361
393
    ret = sigaction(SIGHUP, &new_action, NULL);
362
394
    if(ret == -1){
363
 
      error(0, errno, "sigaction");
 
395
      error_plus(0, errno, "sigaction");
364
396
      return EX_OSERR;
365
397
    }
366
398
  }
367
399
  ret = sigaction(SIGTERM, NULL, &old_action);
368
400
  if(ret == -1){
369
 
    error(0, errno, "sigaction");
 
401
    error_plus(0, errno, "sigaction");
370
402
    return EX_OSERR;
371
403
  }
372
404
  if(old_action.sa_handler != SIG_IGN){
373
405
    ret = sigaction(SIGTERM, &new_action, NULL);
374
406
    if(ret == -1){
375
 
      error(0, errno, "sigaction");
 
407
      error_plus(0, errno, "sigaction");
376
408
      return EX_OSERR;
377
409
    }
378
410
  }
386
418
  t_new.c_lflag &= ~(tcflag_t)ECHO;
387
419
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
388
420
    int e = errno;
389
 
    error(0, errno, "tcsetattr-echo");
 
421
    error_plus(0, errno, "tcsetattr-echo");
390
422
    switch(e){
391
423
    case EBADF:
392
424
    case ENOTTY:
412
444
    if(prefix){
413
445
      fprintf(stderr, "%s ", prefix);
414
446
    }
415
 
    {
 
447
    if(prompt != NULL){
 
448
      fprintf(stderr, "%s: ", prompt);
 
449
    } else {
416
450
      const char *cryptsource = getenv("CRYPTTAB_SOURCE");
417
451
      const char *crypttarget = getenv("CRYPTTAB_NAME");
418
452
      /* Before cryptsetup 1.1.0~rc2 */
456
490
        sret = write(STDOUT_FILENO, buffer + written, n - written);
457
491
        if(sret < 0){
458
492
          int e = errno;
459
 
          error(0, errno, "write");
 
493
          error_plus(0, errno, "write");
460
494
          switch(e){
461
495
          case EBADF:
462
496
          case EFAULT:
478
512
      sret = close(STDOUT_FILENO);
479
513
      if(sret == -1){
480
514
        int e = errno;
481
 
        error(0, errno, "close");
 
515
        error_plus(0, errno, "close");
482
516
        switch(e){
483
517
        case EBADF:
484
518
          status = EX_OSFILE;
493
527
    }
494
528
    if(sret < 0){
495
529
      int e = errno;
496
 
      if(errno != EINTR and not feof(stdin)){
497
 
        error(0, errno, "getline");
498
 
        switch(e){
499
 
        case EBADF:
500
 
          status = EX_UNAVAILABLE;
501
 
        case EIO:
502
 
        case EINVAL:
503
 
        default:
504
 
          status = EX_IOERR;
 
530
      if(errno != EINTR){
 
531
        if(not feof(stdin)){
 
532
          error_plus(0, errno, "getline");
 
533
          switch(e){
 
534
          case EBADF:
 
535
            status = EX_UNAVAILABLE;
 
536
            break;
 
537
          case EIO:
 
538
          case EINVAL:
 
539
          default:
 
540
            status = EX_IOERR;
 
541
            break;
 
542
          }
505
543
          break;
 
544
        } else {
 
545
          clearerr(stdin);
506
546
        }
507
 
        break;
508
547
      }
509
548
    }
510
549
    /* if(sret == 0), then the only sensible thing to do is to retry
523
562
    fprintf(stderr, "Restoring terminal attributes\n");
524
563
  }
525
564
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
526
 
    error(0, errno, "tcsetattr+echo");
 
565
    error_plus(0, errno, "tcsetattr+echo");
527
566
  }
528
567
  
529
568
  if(quit_now){
531
570
    old_action.sa_handler = SIG_DFL;
532
571
    ret = sigaction(signal_received, &old_action, NULL);
533
572
    if(ret == -1){
534
 
      error(0, errno, "sigaction");
 
573
      error_plus(0, errno, "sigaction");
535
574
    }
536
575
    raise(signal_received);
537
576
  }