/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-08-05 21:14:05 UTC
  • Revision ID: teddy@recompile.se-20190805211405-9m6hecekaihpttz9
Override lintian warnings about upgrading from old versions

There are some really things which are imperative that we fix in case
someone were to upgrade from a really old version.  We want to keep
these fixes in the postinst maintainer scripts, even though lintian
complains about such old upgrades not being supported by Debian in
general.  We prefer the code being there, for the sake of the users.

* debian/mandos-client.lintian-overrides
  (maintainer-script-supports-ancient-package-version): New.
  debian/mandos.lintian-overrides
  (maintainer-script-supports-ancient-package-version): - '' -

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-2011 Teddy Hogeborn
6
 
 * Copyright © 2008-2011 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
23
 * Contact the authors at <mandos@recompile.se>.
23
24
 */
26
27
 
27
28
#include <termios.h>            /* struct termios, tcsetattr(),
28
29
                                   TCSAFLUSH, tcgetattr(), ECHO */
29
 
#include <unistd.h>             /* struct termios, tcsetattr(),
30
 
                                   STDIN_FILENO, TCSAFLUSH,
31
 
                                   tcgetattr(), ECHO, readlink() */
 
30
#include <unistd.h>             /* access(), struct termios,
 
31
                                   tcsetattr(), STDIN_FILENO,
 
32
                                   TCSAFLUSH, tcgetattr(), ECHO,
 
33
                                   readlink() */
32
34
#include <signal.h>             /* sig_atomic_t, raise(), struct
33
35
                                   sigaction, sigemptyset(),
34
36
                                   sigaction(), sigaddset(), SIGINT,
82
84
  
83
85
  va_start(ap, formatstring);
84
86
  ret = vasprintf(&text, formatstring, ap);
85
 
  if (ret == -1){
 
87
  if(ret == -1){
86
88
    fprintf(stderr, "Mandos plugin %s: ",
87
89
            program_invocation_short_name);
88
90
    vfprintf(stderr, formatstring, ap);
89
 
    fprintf(stderr, ": ");
90
 
    fprintf(stderr, "%s\n", strerror(errnum));
 
91
    fprintf(stderr, ": %s\n", strerror(errnum));
91
92
    error(status, errno, "vasprintf while printing error");
92
93
    return;
93
94
  }
110
111
     from the terminal.  Password-prompt will exit if it detects
111
112
     plymouth since plymouth performs the same functionality.
112
113
   */
 
114
  if(access("/run/plymouth/pid", R_OK) == 0){
 
115
    return true;
 
116
  }
 
117
  
 
118
  __attribute__((nonnull))
113
119
  int is_plymouth(const struct dirent *proc_entry){
114
120
    int ret;
115
121
    int cl_fd;
116
122
    {
117
 
      uintmax_t maxvalue;
 
123
      uintmax_t proc_id;
118
124
      char *tmp;
119
125
      errno = 0;
120
 
      maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
126
      proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
121
127
      
122
128
      if(errno != 0 or *tmp != '\0'
123
 
         or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
129
         or proc_id != (uintmax_t)((pid_t)proc_id)){
124
130
        return 0;
125
131
      }
126
132
    }
129
135
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
130
136
                   proc_entry->d_name);
131
137
    if(ret == -1){
132
 
      error(0, errno, "asprintf");
 
138
      error_plus(0, errno, "asprintf");
133
139
      return 0;
134
140
    }
135
141
    
138
144
    free(cmdline_filename);
139
145
    if(cl_fd == -1){
140
146
      if(errno != ENOENT){
141
 
        error(0, errno, "open");
 
147
        error_plus(0, errno, "open");
142
148
      }
143
149
      return 0;
144
150
    }
155
161
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
156
162
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
157
163
          if(tmp == NULL){
158
 
            error(0, errno, "realloc");
 
164
            error_plus(0, errno, "realloc");
159
165
            free(cmdline);
160
166
            close(cl_fd);
161
167
            return 0;
168
174
        sret = read(cl_fd, cmdline + cmdline_len,
169
175
                    cmdline_allocated - cmdline_len);
170
176
        if(sret == -1){
171
 
          error(0, errno, "read");
 
177
          error_plus(0, errno, "read");
172
178
          free(cmdline);
173
179
          close(cl_fd);
174
180
          return 0;
177
183
      } while(sret != 0);
178
184
      ret = close(cl_fd);
179
185
      if(ret == -1){
180
 
        error(0, errno, "close");
 
186
        error_plus(0, errno, "close");
181
187
        free(cmdline);
182
188
        return 0;
183
189
      }
212
218
  struct dirent **direntries = NULL;
213
219
  int ret;
214
220
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
215
 
  if (ret == -1){
216
 
    error(1, errno, "scandir");
 
221
  if(ret == -1){
 
222
    error_plus(1, errno, "scandir");
 
223
  }
 
224
  {
 
225
    int i = ret;
 
226
    while(i--){
 
227
      free(direntries[i]);
 
228
    }
217
229
  }
218
230
  free(direntries);
219
231
  return ret > 0;
227
239
  struct termios t_new, t_old;
228
240
  char *buffer = NULL;
229
241
  char *prefix = NULL;
 
242
  char *prompt = NULL;
230
243
  int status = EXIT_SUCCESS;
231
244
  struct sigaction old_action,
232
245
    new_action = { .sa_handler = termination_handler,
236
249
      { .name = "prefix", .key = 'p',
237
250
        .arg = "PREFIX", .flags = 0,
238
251
        .doc = "Prefix shown before the prompt", .group = 2 },
 
252
      { .name = "prompt", .key = 129,
 
253
        .arg = "PROMPT", .flags = 0,
 
254
        .doc = "The prompt to show", .group = 2 },
239
255
      { .name = "debug", .key = 128,
240
256
        .doc = "Debug mode", .group = 3 },
241
257
      /*
250
266
      { .name = NULL }
251
267
    };
252
268
    
 
269
    __attribute__((nonnull(3)))
253
270
    error_t parse_opt (int key, char *arg, struct argp_state *state){
254
271
      errno = 0;
255
272
      switch (key){
256
 
      case 'p':
 
273
      case 'p':                 /* --prefix */
257
274
        prefix = arg;
258
275
        break;
259
 
      case 128:
 
276
      case 128:                 /* --debug */
260
277
        debug = true;
261
278
        break;
 
279
      case 129:                 /* --prompt */
 
280
        prompt = arg;
 
281
        break;
262
282
        /*
263
283
         * These reproduce what we would get without ARGP_NO_HELP
264
284
         */
266
286
        argp_state_help(state, state->out_stream,
267
287
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
268
288
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
289
        __builtin_unreachable();
269
290
      case -3:                  /* --usage */
270
291
        argp_state_help(state, state->out_stream,
271
292
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
293
        __builtin_unreachable();
272
294
      case 'V':                 /* --version */
273
295
        fprintf(state->out_stream, "%s\n", argp_program_version);
274
296
        exit(argp_err_exit_status);
291
313
    case ENOMEM:
292
314
    default:
293
315
      errno = ret;
294
 
      error(0, errno, "argp_parse");
 
316
      error_plus(0, errno, "argp_parse");
295
317
      return EX_OSERR;
296
318
    case EINVAL:
297
319
      return EX_USAGE;
302
324
    fprintf(stderr, "Starting %s\n", argv[0]);
303
325
  }
304
326
 
305
 
  if (conflict_detection()){
 
327
  if(conflict_detection()){
306
328
    if(debug){
307
329
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
308
330
    }
315
337
  
316
338
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
317
339
    int e = errno;
318
 
    error(0, errno, "tcgetattr");
 
340
    error_plus(0, errno, "tcgetattr");
319
341
    switch(e){
320
342
    case EBADF:
321
343
    case ENOTTY:
328
350
  sigemptyset(&new_action.sa_mask);
329
351
  ret = sigaddset(&new_action.sa_mask, SIGINT);
330
352
  if(ret == -1){
331
 
    error(0, errno, "sigaddset");
 
353
    error_plus(0, errno, "sigaddset");
332
354
    return EX_OSERR;
333
355
  }
334
356
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
335
357
  if(ret == -1){
336
 
    error(0, errno, "sigaddset");
 
358
    error_plus(0, errno, "sigaddset");
337
359
    return EX_OSERR;
338
360
  }
339
361
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
340
362
  if(ret == -1){
341
 
    error(0, errno, "sigaddset");
 
363
    error_plus(0, errno, "sigaddset");
342
364
    return EX_OSERR;
343
365
  }
344
366
  /* Need to check if the handler is SIG_IGN before handling:
347
369
  */
348
370
  ret = sigaction(SIGINT, NULL, &old_action);
349
371
  if(ret == -1){
350
 
    error(0, errno, "sigaction");
 
372
    error_plus(0, errno, "sigaction");
351
373
    return EX_OSERR;
352
374
  }
353
375
  if(old_action.sa_handler != SIG_IGN){
354
376
    ret = sigaction(SIGINT, &new_action, NULL);
355
377
    if(ret == -1){
356
 
      error(0, errno, "sigaction");
 
378
      error_plus(0, errno, "sigaction");
357
379
      return EX_OSERR;
358
380
    }
359
381
  }
360
382
  ret = sigaction(SIGHUP, NULL, &old_action);
361
383
  if(ret == -1){
362
 
    error(0, errno, "sigaction");
 
384
    error_plus(0, errno, "sigaction");
363
385
    return EX_OSERR;
364
386
  }
365
387
  if(old_action.sa_handler != SIG_IGN){
366
388
    ret = sigaction(SIGHUP, &new_action, NULL);
367
389
    if(ret == -1){
368
 
      error(0, errno, "sigaction");
 
390
      error_plus(0, errno, "sigaction");
369
391
      return EX_OSERR;
370
392
    }
371
393
  }
372
394
  ret = sigaction(SIGTERM, NULL, &old_action);
373
395
  if(ret == -1){
374
 
    error(0, errno, "sigaction");
 
396
    error_plus(0, errno, "sigaction");
375
397
    return EX_OSERR;
376
398
  }
377
399
  if(old_action.sa_handler != SIG_IGN){
378
400
    ret = sigaction(SIGTERM, &new_action, NULL);
379
401
    if(ret == -1){
380
 
      error(0, errno, "sigaction");
 
402
      error_plus(0, errno, "sigaction");
381
403
      return EX_OSERR;
382
404
    }
383
405
  }
391
413
  t_new.c_lflag &= ~(tcflag_t)ECHO;
392
414
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
393
415
    int e = errno;
394
 
    error(0, errno, "tcsetattr-echo");
 
416
    error_plus(0, errno, "tcsetattr-echo");
395
417
    switch(e){
396
418
    case EBADF:
397
419
    case ENOTTY:
417
439
    if(prefix){
418
440
      fprintf(stderr, "%s ", prefix);
419
441
    }
420
 
    {
 
442
    if(prompt != NULL){
 
443
      fprintf(stderr, "%s: ", prompt);
 
444
    } else {
421
445
      const char *cryptsource = getenv("CRYPTTAB_SOURCE");
422
446
      const char *crypttarget = getenv("CRYPTTAB_NAME");
423
447
      /* Before cryptsetup 1.1.0~rc2 */
461
485
        sret = write(STDOUT_FILENO, buffer + written, n - written);
462
486
        if(sret < 0){
463
487
          int e = errno;
464
 
          error(0, errno, "write");
 
488
          error_plus(0, errno, "write");
465
489
          switch(e){
466
490
          case EBADF:
467
491
          case EFAULT:
483
507
      sret = close(STDOUT_FILENO);
484
508
      if(sret == -1){
485
509
        int e = errno;
486
 
        error(0, errno, "close");
 
510
        error_plus(0, errno, "close");
487
511
        switch(e){
488
512
        case EBADF:
489
513
          status = EX_OSFILE;
498
522
    }
499
523
    if(sret < 0){
500
524
      int e = errno;
501
 
      if(errno != EINTR and not feof(stdin)){
502
 
        error(0, errno, "getline");
503
 
        switch(e){
504
 
        case EBADF:
505
 
          status = EX_UNAVAILABLE;
506
 
        case EIO:
507
 
        case EINVAL:
508
 
        default:
509
 
          status = EX_IOERR;
 
525
      if(errno != EINTR){
 
526
        if(not feof(stdin)){
 
527
          error_plus(0, errno, "getline");
 
528
          switch(e){
 
529
          case EBADF:
 
530
            status = EX_UNAVAILABLE;
 
531
            break;
 
532
          case EIO:
 
533
          case EINVAL:
 
534
          default:
 
535
            status = EX_IOERR;
 
536
            break;
 
537
          }
510
538
          break;
 
539
        } else {
 
540
          clearerr(stdin);
511
541
        }
512
 
        break;
513
542
      }
514
543
    }
515
544
    /* if(sret == 0), then the only sensible thing to do is to retry
528
557
    fprintf(stderr, "Restoring terminal attributes\n");
529
558
  }
530
559
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
531
 
    error(0, errno, "tcsetattr+echo");
 
560
    error_plus(0, errno, "tcsetattr+echo");
532
561
  }
533
562
  
534
563
  if(quit_now){
536
565
    old_action.sa_handler = SIG_DFL;
537
566
    ret = sigaction(signal_received, &old_action, NULL);
538
567
    if(ret == -1){
539
 
      error(0, errno, "sigaction");
 
568
      error_plus(0, errno, "sigaction");
540
569
    }
541
570
    raise(signal_received);
542
571
  }