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

  • Committer: Teddy Hogeborn
  • Date: 2019-03-18 22:29:25 UTC
  • Revision ID: teddy@recompile.se-20190318222925-jvhek84dgcfgj6g3
mandos-ctl: Refactor tests

* mandos-ctl: Where the clients names "foo" and "barbar" do not refer
              to the actual mock clients in the TestCommand class,
              change all occurrences of these names to "client1" and
              "client2" (or just "client" when only one is used) .
              Also change all test doubles to use correct terminology;
              some things called mocks are actually stubs or spies,
              and rename all true mocks to have "mock" in their names.
              Also eliminate duplicate values in tests; derive values
              from previously defined values whenever possible.

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
  }
467
407
 
468
408
int main(__attribute__((unused))int argc,
469
409
         __attribute__((unused))char **argv){
470
 
  char *prompt = NULL;
 
410
  char *prompt;
471
411
  char *prompt_arg;
472
412
  pid_t plymouth_command_pid;
473
413
  int ret;
474
414
  bool bret;
475
415
 
476
 
  {
477
 
    struct argp_option options[] = {
478
 
      { .name = "prompt", .key = 128, .arg = "PROMPT",
479
 
        .doc = "The prompt to show" },
480
 
      { .name = "debug", .key = 129,
481
 
        .doc = "Debug mode" },
482
 
      { .name = NULL }
483
 
    };
484
 
    
485
 
    __attribute__((nonnull(3)))
486
 
    error_t parse_opt (int key, char *arg, __attribute__((unused))
487
 
                       struct argp_state *state){
488
 
      errno = 0;
489
 
      switch (key){
490
 
      case 128:                 /* --prompt */
491
 
        prompt = arg;
492
 
        if(debug){
493
 
          fprintf_plus(stderr, "Custom prompt \"%s\"\n", prompt);
494
 
        }
495
 
        break;
496
 
      case 129:                 /* --debug */
497
 
        debug = true;
498
 
        break;
499
 
      default:
500
 
        return ARGP_ERR_UNKNOWN;
501
 
      }
502
 
      return errno;
503
 
    }
504
 
    
505
 
    struct argp argp = { .options = options, .parser = parse_opt,
506
 
                         .args_doc = "",
507
 
                         .doc = "Mandos plymouth -- Read and"
508
 
                         " output a password" };
509
 
    ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, NULL);
510
 
    switch(ret){
511
 
    case 0:
512
 
      break;
513
 
    case ENOMEM:
514
 
    default:
515
 
      errno = ret;
516
 
      error_plus(0, errno, "argp_parse");
517
 
      return EX_OSERR;
518
 
    case EINVAL:
519
 
      error_plus(0, errno, "argp_parse");
520
 
      return EX_USAGE;
521
 
    }
522
 
  }
523
 
  
524
416
  /* test -x /bin/plymouth */
525
417
  ret = access(plymouth_path, X_OK);
526
418
  if(ret == -1){
527
419
    /* Plymouth is probably not installed.  Don't print an error
528
420
       message, just exit. */
529
 
    if(debug){
530
 
      fprintf_plus(stderr, "Plymouth (%s) not found\n",
531
 
                   plymouth_path);
532
 
    }
533
421
    exit(EX_UNAVAILABLE);
534
422
  }
535
423
  
569
457
    }
570
458
    /* Plymouth is probably not running.  Don't print an error
571
459
       message, just exit. */
572
 
    if(debug){
573
 
      fprintf_plus(stderr, "Plymouth not running\n");
574
 
    }
575
460
    exit(EX_UNAVAILABLE);
576
461
  }
577
462
  
578
 
  if(prompt != NULL){
579
 
    ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
580
 
  } else {
581
 
    char *made_prompt = makeprompt();
582
 
    ret = asprintf(&prompt_arg, "--prompt=%s", made_prompt);
583
 
    free(made_prompt);
584
 
  }
 
463
  prompt = makeprompt();
 
464
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
 
465
  free(prompt);
585
466
  if(ret == -1){
586
467
    error_plus(EX_OSERR, errno, "asprintf");
587
468
  }
588
469
  
589
470
  /* plymouth ask-for-password --prompt="$prompt" */
590
 
  if(debug){
591
 
    fprintf_plus(stderr, "Prompting for password via Plymouth\n");
592
 
  }
593
471
  bret = exec_and_wait(&plymouth_command_pid,
594
472
                       plymouth_path, (const char *[])
595
473
                       { plymouth_path, "ask-for-password",