/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/plymouth.c

  • Committer: Teddy Hogeborn
  • Date: 2019-03-12 20:13:34 UTC
  • mto: This revision was merged to the branch mainline in revision 382.
  • 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
 * Plymouth - Read a password from Plymouth and output it
4
4
 * 
5
 
 * Copyright © 2010-2022 Teddy Hogeborn
6
 
 * Copyright © 2010-2022 Björn Påhlsson
 
5
 * Copyright © 2010-2018 Teddy Hogeborn
 
6
 * Copyright © 2010-2018 Björn Påhlsson
7
7
 * 
8
8
 * This file is part of Mandos.
9
9
 * 
23
23
 * Contact the authors at <mandos@recompile.se>.
24
24
 */
25
25
 
26
 
#define _GNU_SOURCE             /* program_invocation_short_name,
27
 
                                   vasprintf(), asprintf(),
28
 
                                   TEMP_FAILURE_RETRY() */
29
 
#include <sys/types.h>          /* sig_atomic_t, pid_t, setuid(),
30
 
                                   geteuid(), setsid() */
31
 
#include <argp.h>               /* argp_program_version,
32
 
                                   argp_program_bug_address,
33
 
                                   struct argp_option,
34
 
                                   struct argp_state,
35
 
                                   ARGP_ERR_UNKNOWN, struct argp,
36
 
                                   argp_parse(), ARGP_IN_ORDER */
37
 
#include <stddef.h>             /* NULL, size_t */
 
26
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
 
27
#include <signal.h>             /* sig_atomic_t, struct sigaction,
 
28
                                   sigemptyset(), sigaddset(), SIGINT,
 
29
                                   SIGHUP, SIGTERM, sigaction(),
 
30
                                   kill(), SIG_IGN */
38
31
#include <stdbool.h>            /* bool, false, true */
39
 
#include <stdio.h>              /* FILE, fprintf(), vfprintf(),
40
 
                                   vasprintf(), stderr, asprintf(),
41
 
                                   fopen(), fscanf(), fclose(),
42
 
                                   sscanf() */
43
 
#include <stdarg.h>             /* va_list, va_start(), vfprintf() */
44
 
#include <errno.h>              /* program_invocation_short_name,
45
 
                                   errno, ENOMEM, EINTR, ENOENT,
46
 
                                   error_t, EINVAL */
47
 
#include <string.h>             /* strerror(), strdup(), memcmp() */
 
32
#include <fcntl.h>              /* open(), O_RDONLY */
 
33
#include <iso646.h>             /* and, or, not*/
 
34
#include <sys/types.h>          /* size_t, ssize_t, pid_t, struct
 
35
                                   dirent, waitpid() */
 
36
#include <sys/wait.h>           /* waitpid() */
 
37
#include <stddef.h>             /* NULL */
 
38
#include <string.h>             /* strchr(), memcmp() */
 
39
#include <stdio.h>              /* asprintf(), perror(), fopen(),
 
40
                                   fscanf(), vasprintf(), fprintf(),
 
41
                                   vfprintf() */
 
42
#include <unistd.h>             /* close(), readlink(), read(),
 
43
                                   fork(), setsid(), chdir(), dup2(),
 
44
                                   STDERR_FILENO, execv(), access() */
 
45
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
 
46
                                   EXIT_SUCCESS, malloc(), _exit(),
 
47
                                   getenv() */
 
48
#include <dirent.h>             /* scandir(), alphasort() */
 
49
#include <inttypes.h>           /* intmax_t, strtoumax(), SCNuMAX */
 
50
#include <sys/stat.h>           /* struct stat, lstat() */
 
51
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
48
52
#include <error.h>              /* error() */
49
 
#include <stdlib.h>             /* free(), getenv(), malloc(),
50
 
                                   reallocarray(), realloc(),
51
 
                                   EXIT_FAILURE, EXIT_SUCCESS */
52
 
#include <unistd.h>             /* TEMP_FAILURE_RETRY(), setuid(),
53
 
                                   geteuid(), setsid(), chdir(),
54
 
                                   dup2(), STDERR_FILENO,
55
 
                                   STDOUT_FILENO, fork(), _exit(),
56
 
                                   execv(), ssize_t, readlink(),
57
 
                                   close(), read(), access(), X_OK */
58
 
#include <signal.h>             /* kill(), SIGTERM, struct sigaction,
59
 
                                   sigemptyset(), SIGINT, SIGHUP,
60
 
                                   sigaddset(), SIG_IGN */
61
 
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
62
 
                                   WEXITSTATUS(), WIFSIGNALED(),
63
 
                                   WTERMSIG() */
64
 
#include <iso646.h>             /* not, and, or */
65
 
#include <sysexits.h>           /* EX_OSERR, EX_USAGE,
66
 
                                   EX_UNAVAILABLE */
67
 
#include <stdint.h>             /* SIZE_MAX */
68
 
#include <dirent.h>             /* struct dirent, scandir(),
69
 
                                   alphasort() */
70
 
#include <inttypes.h>           /* uintmax_t, strtoumax(), SCNuMAX,
71
 
                                   PRIuMAX */
72
 
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK() */
73
 
#include <fcntl.h>              /* open(), O_RDONLY */
 
53
#include <errno.h>              /* TEMP_FAILURE_RETRY */
74
54
#include <argz.h>               /* argz_count(), argz_extract() */
 
55
#include <stdarg.h>             /* va_list, va_start(), ... */
75
56
 
76
57
sig_atomic_t interrupted_by_signal = 0;
77
 
const char *argp_program_version = "plymouth " VERSION;
78
 
const char *argp_program_bug_address = "<mandos@recompile.se>";
79
58
 
80
59
/* Used by Ubuntu 11.04 (Natty Narwahl) */
81
60
const char plymouth_old_old_pid[] = "/dev/.initramfs/plymouth.pid";
90
69
                                        "--mode=boot",
91
70
                                        "--attach-to-session",
92
71
                                        NULL };
93
 
bool debug = false;
94
72
 
95
73
static void termination_handler(__attribute__((unused))int signum){
96
74
  if(interrupted_by_signal){
99
77
  interrupted_by_signal = 1;
100
78
}
101
79
 
102
 
__attribute__((format (gnu_printf, 2, 3), nonnull))
103
 
int fprintf_plus(FILE *stream, const char *format, ...){
104
 
  va_list ap;
105
 
  va_start (ap, format);
106
 
  fprintf(stream, "Mandos plugin %s: ", program_invocation_short_name);
107
 
  return vfprintf(stream, format, ap);
108
 
}
109
 
 
110
80
/* Function to use when printing errors */
111
81
__attribute__((format (gnu_printf, 3, 4)))
112
82
void error_plus(int status, int errnum, const char *formatstring,
189
159
 
190
160
__attribute__((nonnull (2, 3)))
191
161
bool exec_and_wait(pid_t *pid_return, const char *path,
192
 
                   const char * const * const argv, bool interruptable,
 
162
                   const char * const *argv, bool interruptable,
193
163
                   bool daemonize){
194
164
  int status;
195
165
  int ret;
196
166
  pid_t pid;
197
 
  if(debug){
198
 
    for(const char * const *arg = argv; *arg != NULL; arg++){
199
 
      fprintf_plus(stderr, "exec_and_wait arg: %s\n", *arg);
200
 
    }
201
 
    fprintf_plus(stderr, "exec_and_wait end of args\n");
202
 
  }
203
 
 
204
167
  pid = fork();
205
168
  if(pid == -1){
206
169
    error_plus(0, errno, "fork");
222
185
    char **tmp;
223
186
    int i = 0;
224
187
    for (; argv[i] != NULL; i++){
225
 
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
226
 
      tmp = reallocarray(new_argv, ((size_t)i + 2),
227
 
                         sizeof(const char *));
228
 
#else
229
 
      if(((size_t)i + 2) > (SIZE_MAX / sizeof(const char *))){
230
 
        /* overflow */
231
 
        tmp = NULL;
232
 
        errno = ENOMEM;
233
 
      } else {
234
 
        tmp = realloc(new_argv, ((size_t)i + 2) * sizeof(const char *));
235
 
      }
236
 
#endif
 
188
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 2));
237
189
      if(tmp == NULL){
238
 
        error_plus(0, errno, "reallocarray");
 
190
        error_plus(0, errno, "realloc");
239
191
        free(new_argv);
240
192
        _exit(EX_OSERR);
241
193
      }
257
209
          and ((not interrupted_by_signal)
258
210
               or (not interruptable)));
259
211
  if(interrupted_by_signal and interruptable){
260
 
    if(debug){
261
 
      fprintf_plus(stderr, "Interrupted by signal\n");
262
 
    }
263
212
    return false;
264
213
  }
265
214
  if(ret == -1){
266
215
    error_plus(0, errno, "waitpid");
267
216
    return false;
268
217
  }
269
 
  if(debug){
270
 
    if(WIFEXITED(status)){
271
 
      fprintf_plus(stderr, "exec_and_wait exited: %d\n",
272
 
                   WEXITSTATUS(status));
273
 
    } else if(WIFSIGNALED(status)) {
274
 
      fprintf_plus(stderr, "exec_and_wait signaled: %d\n",
275
 
                   WTERMSIG(status));
276
 
    }
277
 
  }
278
218
  if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
279
219
    return true;
280
220
  }
372
312
      error_plus(0, errno, "scandir");
373
313
    }
374
314
    if(ret > 0){
375
 
      const int num_entries = ret;
376
 
      for(int i = 0; i < num_entries; i++){
 
315
      for(int i = ret-1; i >= 0; i--){
377
316
        if(proc_id == 0){
378
317
          ret = sscanf(direntries[i]->d_name, "%" SCNuMAX, &proc_id);
379
318
          if(ret < 0){
468
407
 
469
408
int main(__attribute__((unused))int argc,
470
409
         __attribute__((unused))char **argv){
471
 
  char *prompt = NULL;
 
410
  char *prompt;
472
411
  char *prompt_arg;
473
412
  pid_t plymouth_command_pid;
474
413
  int ret;
475
414
  bool bret;
476
415
 
477
 
  {
478
 
    struct argp_option options[] = {
479
 
      { .name = "prompt", .key = 128, .arg = "PROMPT",
480
 
        .doc = "The prompt to show" },
481
 
      { .name = "debug", .key = 129,
482
 
        .doc = "Debug mode" },
483
 
      { .name = NULL }
484
 
    };
485
 
    
486
 
    __attribute__((nonnull(3)))
487
 
    error_t parse_opt (int key, char *arg, __attribute__((unused))
488
 
                       struct argp_state *state){
489
 
      errno = 0;
490
 
      switch (key){
491
 
      case 128:                 /* --prompt */
492
 
        prompt = arg;
493
 
        if(debug){
494
 
          fprintf_plus(stderr, "Custom prompt \"%s\"\n", prompt);
495
 
        }
496
 
        break;
497
 
      case 129:                 /* --debug */
498
 
        debug = true;
499
 
        break;
500
 
      default:
501
 
        return ARGP_ERR_UNKNOWN;
502
 
      }
503
 
      return errno;
504
 
    }
505
 
    
506
 
    struct argp argp = { .options = options, .parser = parse_opt,
507
 
                         .args_doc = "",
508
 
                         .doc = "Mandos plymouth -- Read and"
509
 
                         " output a password" };
510
 
    ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, NULL);
511
 
    switch(ret){
512
 
    case 0:
513
 
      break;
514
 
    case ENOMEM:
515
 
    default:
516
 
      errno = ret;
517
 
      error_plus(0, errno, "argp_parse");
518
 
      return EX_OSERR;
519
 
    case EINVAL:
520
 
      error_plus(0, errno, "argp_parse");
521
 
      return EX_USAGE;
522
 
    }
523
 
  }
524
 
  
525
416
  /* test -x /bin/plymouth */
526
417
  ret = access(plymouth_path, X_OK);
527
418
  if(ret == -1){
528
419
    /* Plymouth is probably not installed.  Don't print an error
529
420
       message, just exit. */
530
 
    if(debug){
531
 
      fprintf_plus(stderr, "Plymouth (%s) not found\n",
532
 
                   plymouth_path);
533
 
    }
534
421
    exit(EX_UNAVAILABLE);
535
422
  }
536
423
  
570
457
    }
571
458
    /* Plymouth is probably not running.  Don't print an error
572
459
       message, just exit. */
573
 
    if(debug){
574
 
      fprintf_plus(stderr, "Plymouth not running\n");
575
 
    }
576
460
    exit(EX_UNAVAILABLE);
577
461
  }
578
462
  
579
 
  if(prompt != NULL){
580
 
    ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
581
 
  } else {
582
 
    char *made_prompt = makeprompt();
583
 
    ret = asprintf(&prompt_arg, "--prompt=%s", made_prompt);
584
 
    free(made_prompt);
585
 
  }
 
463
  prompt = makeprompt();
 
464
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
 
465
  free(prompt);
586
466
  if(ret == -1){
587
467
    error_plus(EX_OSERR, errno, "asprintf");
588
468
  }
589
469
  
590
470
  /* plymouth ask-for-password --prompt="$prompt" */
591
 
  if(debug){
592
 
    fprintf_plus(stderr, "Prompting for password via Plymouth\n");
593
 
  }
594
471
  bret = exec_and_wait(&plymouth_command_pid,
595
472
                       plymouth_path, (const char *[])
596
473
                       { plymouth_path, "ask-for-password",