/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: 2021-02-03 23:10:42 UTC
  • Revision ID: teddy@recompile.se-20210203231042-2z3egrvpo1zt7nej
mandos-ctl: Fix bad test for command.Remove and related minor issues

The test for command.Remove removes all clients from the spy server,
and then loops over all clients, looking for the corresponding Remove
command as recorded by the spy server.  But since since there aren't
any clients left after they were removed, no assertions are made, and
the test therefore does nothing.  Fix this.

In tests for command.Approve and command.Deny, add checks that clients
were not somehow removed by the command (in which case, likewise, no
assertions are made).

Add related checks to TestPropertySetterCmd.runTest; i.e. test that a
sequence is not empty before looping over it and making assertions.

* mandos-ctl (TestBaseCommands.test_Remove): Save a copy of the
  original "clients" dict, and loop over those instead.  Add assertion
  that all clients were indeed removed.  Also fix the code which looks
  for the Remove command, which now needs to actually work.
  (TestBaseCommands.test_Approve, TestBaseCommands.test_Deny): Add
  assertion that there are still clients before looping over them.
  (TestPropertySetterCmd.runTest): Add assertion that the list of
  values to get is not empty before looping over them.  Also add check
  that there are still clients before looping over clients.

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-2018 Teddy Hogeborn
6
 
 * Copyright © 2010-2018 Björn Påhlsson
 
5
 * Copyright © 2010-2021 Teddy Hogeborn
 
6
 * Copyright © 2010-2021 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             /* 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 */
 
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 */
31
38
#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() */
 
48
#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() */
32
73
#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 */
52
 
#include <error.h>              /* error() */
53
 
#include <errno.h>              /* TEMP_FAILURE_RETRY */
54
74
#include <argz.h>               /* argz_count(), argz_extract() */
55
 
#include <stdarg.h>             /* va_list, va_start(), ... */
56
75
 
57
76
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>";
58
79
 
59
80
/* Used by Ubuntu 11.04 (Natty Narwahl) */
60
81
const char plymouth_old_old_pid[] = "/dev/.initramfs/plymouth.pid";
69
90
                                        "--mode=boot",
70
91
                                        "--attach-to-session",
71
92
                                        NULL };
 
93
bool debug = false;
72
94
 
73
95
static void termination_handler(__attribute__((unused))int signum){
74
96
  if(interrupted_by_signal){
77
99
  interrupted_by_signal = 1;
78
100
}
79
101
 
 
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
 
80
110
/* Function to use when printing errors */
81
111
__attribute__((format (gnu_printf, 3, 4)))
82
112
void error_plus(int status, int errnum, const char *formatstring,
159
189
 
160
190
__attribute__((nonnull (2, 3)))
161
191
bool exec_and_wait(pid_t *pid_return, const char *path,
162
 
                   const char * const *argv, bool interruptable,
 
192
                   const char * const * const argv, bool interruptable,
163
193
                   bool daemonize){
164
194
  int status;
165
195
  int ret;
166
196
  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
 
167
204
  pid = fork();
168
205
  if(pid == -1){
169
206
    error_plus(0, errno, "fork");
185
222
    char **tmp;
186
223
    int i = 0;
187
224
    for (; argv[i] != NULL; i++){
188
 
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 2));
 
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
189
237
      if(tmp == NULL){
190
 
        error_plus(0, errno, "realloc");
 
238
        error_plus(0, errno, "reallocarray");
191
239
        free(new_argv);
192
240
        _exit(EX_OSERR);
193
241
      }
209
257
          and ((not interrupted_by_signal)
210
258
               or (not interruptable)));
211
259
  if(interrupted_by_signal and interruptable){
 
260
    if(debug){
 
261
      fprintf_plus(stderr, "Interrupted by signal\n");
 
262
    }
212
263
    return false;
213
264
  }
214
265
  if(ret == -1){
215
266
    error_plus(0, errno, "waitpid");
216
267
    return false;
217
268
  }
 
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
  }
218
278
  if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
219
279
    return true;
220
280
  }
407
467
 
408
468
int main(__attribute__((unused))int argc,
409
469
         __attribute__((unused))char **argv){
410
 
  char *prompt;
 
470
  char *prompt = NULL;
411
471
  char *prompt_arg;
412
472
  pid_t plymouth_command_pid;
413
473
  int ret;
414
474
  bool bret;
415
475
 
 
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
  
416
524
  /* test -x /bin/plymouth */
417
525
  ret = access(plymouth_path, X_OK);
418
526
  if(ret == -1){
419
527
    /* Plymouth is probably not installed.  Don't print an error
420
528
       message, just exit. */
 
529
    if(debug){
 
530
      fprintf_plus(stderr, "Plymouth (%s) not found\n",
 
531
                   plymouth_path);
 
532
    }
421
533
    exit(EX_UNAVAILABLE);
422
534
  }
423
535
  
457
569
    }
458
570
    /* Plymouth is probably not running.  Don't print an error
459
571
       message, just exit. */
 
572
    if(debug){
 
573
      fprintf_plus(stderr, "Plymouth not running\n");
 
574
    }
460
575
    exit(EX_UNAVAILABLE);
461
576
  }
462
577
  
463
 
  prompt = makeprompt();
464
 
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
465
 
  free(prompt);
 
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
  }
466
585
  if(ret == -1){
467
586
    error_plus(EX_OSERR, errno, "asprintf");
468
587
  }
469
588
  
470
589
  /* plymouth ask-for-password --prompt="$prompt" */
 
590
  if(debug){
 
591
    fprintf_plus(stderr, "Prompting for password via Plymouth\n");
 
592
  }
471
593
  bret = exec_and_wait(&plymouth_command_pid,
472
594
                       plymouth_path, (const char *[])
473
595
                       { plymouth_path, "ask-for-password",