/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

First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8 -*- */
2
 
/*
3
 
 * Plymouth - Read a password from Plymouth and output it
4
 
 * 
5
 
 * Copyright © 2010-2019 Teddy Hogeborn
6
 
 * Copyright © 2010-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
16
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 
 * General Public License for more details.
19
 
 * 
20
 
 * You should have received a copy of the GNU General Public License
21
 
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
22
 
 * 
23
 
 * Contact the authors at <mandos@recompile.se>.
24
 
 */
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 */
31
 
#include <stdbool.h>            /* bool, false, true */
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(), reallocarray() */
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
 
#include <argz.h>               /* argz_count(), argz_extract() */
55
 
#include <stdarg.h>             /* va_list, va_start(), ... */
56
 
#include <argp.h>
57
 
 
58
 
sig_atomic_t interrupted_by_signal = 0;
59
 
const char *argp_program_version = "plymouth " VERSION;
60
 
const char *argp_program_bug_address = "<mandos@recompile.se>";
61
 
 
62
 
/* Used by Ubuntu 11.04 (Natty Narwahl) */
63
 
const char plymouth_old_old_pid[] = "/dev/.initramfs/plymouth.pid";
64
 
/* Used by Ubuntu 11.10 (Oneiric Ocelot) */
65
 
const char plymouth_old_pid[] = "/run/initramfs/plymouth.pid";
66
 
/* Used by Debian 9 (stretch) */
67
 
const char plymouth_pid[] = "/run/plymouth/pid";
68
 
 
69
 
const char plymouth_path[] = "/bin/plymouth";
70
 
const char plymouthd_path[] = "/sbin/plymouthd";
71
 
const char *plymouthd_default_argv[] = {"/sbin/plymouthd",
72
 
                                        "--mode=boot",
73
 
                                        "--attach-to-session",
74
 
                                        NULL };
75
 
bool debug = false;
76
 
 
77
 
static void termination_handler(__attribute__((unused))int signum){
78
 
  if(interrupted_by_signal){
79
 
    return;
80
 
  }
81
 
  interrupted_by_signal = 1;
82
 
}
83
 
 
84
 
__attribute__((format (gnu_printf, 2, 3), nonnull))
85
 
int fprintf_plus(FILE *stream, const char *format, ...){
86
 
  va_list ap;
87
 
  va_start (ap, format);
88
 
  fprintf(stream, "Mandos plugin %s: ", program_invocation_short_name);
89
 
  return vfprintf(stream, format, ap);
90
 
}
91
 
 
92
 
/* Function to use when printing errors */
93
 
__attribute__((format (gnu_printf, 3, 4)))
94
 
void error_plus(int status, int errnum, const char *formatstring,
95
 
                ...){
96
 
  va_list ap;
97
 
  char *text;
98
 
  int ret;
99
 
  
100
 
  va_start(ap, formatstring);
101
 
  ret = vasprintf(&text, formatstring, ap);
102
 
  if(ret == -1){
103
 
    fprintf(stderr, "Mandos plugin %s: ",
104
 
            program_invocation_short_name);
105
 
    vfprintf(stderr, formatstring, ap);
106
 
    fprintf(stderr, ": ");
107
 
    fprintf(stderr, "%s\n", strerror(errnum));
108
 
    error(status, errno, "vasprintf while printing error");
109
 
    return;
110
 
  }
111
 
  fprintf(stderr, "Mandos plugin ");
112
 
  error(status, errnum, "%s", text);
113
 
  free(text);
114
 
}
115
 
 
116
 
/* Create prompt string */
117
 
char *makeprompt(void){
118
 
  int ret = 0;
119
 
  char *prompt;
120
 
  const char *const cryptsource = getenv("cryptsource");
121
 
  const char *const crypttarget = getenv("crypttarget");
122
 
  const char prompt_start[] = "Unlocking the disk";
123
 
  const char prompt_end[] = "Enter passphrase";
124
 
  
125
 
  if(cryptsource == NULL){
126
 
    if(crypttarget == NULL){
127
 
      ret = asprintf(&prompt, "%s\n%s", prompt_start, prompt_end);
128
 
    } else {
129
 
      ret = asprintf(&prompt, "%s (%s)\n%s", prompt_start,
130
 
                     crypttarget, prompt_end);
131
 
    }
132
 
  } else {
133
 
    if(crypttarget == NULL){
134
 
      ret = asprintf(&prompt, "%s %s\n%s", prompt_start, cryptsource,
135
 
                     prompt_end);
136
 
    } else {
137
 
      ret = asprintf(&prompt, "%s %s (%s)\n%s", prompt_start,
138
 
                     cryptsource, crypttarget, prompt_end);
139
 
    }
140
 
  }
141
 
  if(ret == -1){
142
 
    return NULL;
143
 
  }
144
 
  return prompt;
145
 
}
146
 
 
147
 
void kill_and_wait(pid_t pid){
148
 
  TEMP_FAILURE_RETRY(kill(pid, SIGTERM));
149
 
  TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
150
 
}
151
 
 
152
 
bool become_a_daemon(void){
153
 
  int ret = setuid(geteuid());
154
 
  if(ret == -1){
155
 
    error_plus(0, errno, "setuid");
156
 
  }
157
 
    
158
 
  setsid();
159
 
  ret = chdir("/");
160
 
  if(ret == -1){
161
 
    error_plus(0, errno, "chdir");
162
 
    return false;
163
 
  }
164
 
  ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
165
 
  if(ret == -1){
166
 
    error_plus(0, errno, "dup2");
167
 
    return false;
168
 
  }
169
 
  return true;
170
 
}
171
 
 
172
 
__attribute__((nonnull (2, 3)))
173
 
bool exec_and_wait(pid_t *pid_return, const char *path,
174
 
                   const char * const * const argv, bool interruptable,
175
 
                   bool daemonize){
176
 
  int status;
177
 
  int ret;
178
 
  pid_t pid;
179
 
  if(debug){
180
 
    for(const char * const *arg = argv; *arg != NULL; arg++){
181
 
      fprintf_plus(stderr, "exec_and_wait arg: %s\n", *arg);
182
 
    }
183
 
    fprintf_plus(stderr, "exec_and_wait end of args\n");
184
 
  }
185
 
 
186
 
  pid = fork();
187
 
  if(pid == -1){
188
 
    error_plus(0, errno, "fork");
189
 
    return false;
190
 
  }
191
 
  if(pid == 0){
192
 
    /* Child */
193
 
    if(daemonize){
194
 
      if(not become_a_daemon()){
195
 
        _exit(EX_OSERR);
196
 
      }
197
 
    }
198
 
    
199
 
    char **new_argv = malloc(sizeof(const char *));
200
 
    if(new_argv == NULL){
201
 
      error_plus(0, errno, "malloc");
202
 
      _exit(EX_OSERR);
203
 
    }
204
 
    char **tmp;
205
 
    int i = 0;
206
 
    for (; argv[i] != NULL; i++){
207
 
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
208
 
      tmp = reallocarray(new_argv, ((size_t)i + 2),
209
 
                         sizeof(const char *));
210
 
#else
211
 
      if(((size_t)i + 2) > (SIZE_MAX / sizeof(const char *))){
212
 
        /* overflow */
213
 
        tmp = NULL;
214
 
        errno = ENOMEM;
215
 
      } else {
216
 
        tmp = realloc(new_argv, ((size_t)i + 2) * sizeof(const char *));
217
 
      }
218
 
#endif
219
 
      if(tmp == NULL){
220
 
        error_plus(0, errno, "reallocarray");
221
 
        free(new_argv);
222
 
        _exit(EX_OSERR);
223
 
      }
224
 
      new_argv = tmp;
225
 
      new_argv[i] = strdup(argv[i]);
226
 
    }
227
 
    new_argv[i] = NULL;
228
 
    
229
 
    execv(path, (char *const *)new_argv);
230
 
    error_plus(0, errno, "execv");
231
 
    _exit(EXIT_FAILURE);
232
 
  }
233
 
  if(pid_return != NULL){
234
 
    *pid_return = pid;
235
 
  }
236
 
  do {
237
 
    ret = waitpid(pid, &status, 0);
238
 
  } while(ret == -1 and errno == EINTR
239
 
          and ((not interrupted_by_signal)
240
 
               or (not interruptable)));
241
 
  if(interrupted_by_signal and interruptable){
242
 
    if(debug){
243
 
      fprintf_plus(stderr, "Interrupted by signal\n");
244
 
    }
245
 
    return false;
246
 
  }
247
 
  if(ret == -1){
248
 
    error_plus(0, errno, "waitpid");
249
 
    return false;
250
 
  }
251
 
  if(debug){
252
 
    if(WIFEXITED(status)){
253
 
      fprintf_plus(stderr, "exec_and_wait exited: %d\n",
254
 
                   WEXITSTATUS(status));
255
 
    } else if(WIFSIGNALED(status)) {
256
 
      fprintf_plus(stderr, "exec_and_wait signaled: %d\n",
257
 
                   WTERMSIG(status));
258
 
    }
259
 
  }
260
 
  if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
261
 
    return true;
262
 
  }
263
 
  return false;
264
 
}
265
 
 
266
 
__attribute__((nonnull))
267
 
int is_plymouth(const struct dirent *proc_entry){
268
 
  int ret;
269
 
  {
270
 
    uintmax_t proc_id;
271
 
    char *tmp;
272
 
    errno = 0;
273
 
    proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
274
 
 
275
 
    if(errno != 0 or *tmp != '\0'
276
 
       or proc_id != (uintmax_t)((pid_t)proc_id)){
277
 
      return 0;
278
 
    }
279
 
  }
280
 
  char exe_target[sizeof(plymouthd_path)];
281
 
  char *exe_link;
282
 
  ret = asprintf(&exe_link, "/proc/%s/exe", proc_entry->d_name);
283
 
  if(ret == -1){
284
 
    error_plus(0, errno, "asprintf");
285
 
    return 0;
286
 
  }
287
 
  
288
 
  struct stat exe_stat;
289
 
  ret = lstat(exe_link, &exe_stat);
290
 
  if(ret == -1){
291
 
    free(exe_link);
292
 
    if(errno != ENOENT){
293
 
      error_plus(0, errno, "lstat");
294
 
    }
295
 
    return 0;
296
 
  }
297
 
  
298
 
  if(not S_ISLNK(exe_stat.st_mode)
299
 
     or exe_stat.st_uid != 0
300
 
     or exe_stat.st_gid != 0){
301
 
    free(exe_link);
302
 
    return 0;
303
 
  }
304
 
  
305
 
  ssize_t sret = readlink(exe_link, exe_target, sizeof(exe_target));
306
 
  free(exe_link);
307
 
  if((sret != (ssize_t)sizeof(plymouthd_path)-1) or
308
 
      (memcmp(plymouthd_path, exe_target,
309
 
              sizeof(plymouthd_path)-1) != 0)){
310
 
    return 0;
311
 
  }
312
 
  return 1;
313
 
}
314
 
 
315
 
pid_t get_pid(void){
316
 
  int ret;
317
 
  uintmax_t proc_id = 0;
318
 
  FILE *pidfile = fopen(plymouth_pid, "r");
319
 
  /* Try the new pid file location */
320
 
  if(pidfile != NULL){
321
 
    ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
322
 
    if(ret != 1){
323
 
      proc_id = 0;
324
 
    }
325
 
    fclose(pidfile);
326
 
  }
327
 
  /* Try the old pid file location */
328
 
  if(proc_id == 0){
329
 
    pidfile = fopen(plymouth_old_pid, "r");
330
 
    if(pidfile != NULL){
331
 
      ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
332
 
      if(ret != 1){
333
 
        proc_id = 0;
334
 
      }
335
 
      fclose(pidfile);
336
 
    }
337
 
  }
338
 
  /* Try the old old pid file location */
339
 
  if(proc_id == 0){
340
 
    pidfile = fopen(plymouth_old_old_pid, "r");
341
 
    if(pidfile != NULL){
342
 
      ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
343
 
      if(ret != 1){
344
 
        proc_id = 0;
345
 
      }
346
 
      fclose(pidfile);
347
 
    }
348
 
  }
349
 
  /* Look for a plymouth process */
350
 
  if(proc_id == 0){
351
 
    struct dirent **direntries = NULL;
352
 
    ret = scandir("/proc", &direntries, is_plymouth, alphasort);
353
 
    if(ret == -1){
354
 
      error_plus(0, errno, "scandir");
355
 
    }
356
 
    if(ret > 0){
357
 
      for(int i = ret-1; i >= 0; i--){
358
 
        if(proc_id == 0){
359
 
          ret = sscanf(direntries[i]->d_name, "%" SCNuMAX, &proc_id);
360
 
          if(ret < 0){
361
 
            error_plus(0, errno, "sscanf");
362
 
          }
363
 
        }
364
 
        free(direntries[i]);
365
 
      }
366
 
    }
367
 
    /* scandir might preallocate for this variable (man page unclear).
368
 
       even if ret == 0, therefore we need to free it. */
369
 
    free(direntries);
370
 
  }
371
 
  pid_t pid;
372
 
  pid = (pid_t)proc_id;
373
 
  if((uintmax_t)pid == proc_id){
374
 
    return pid;
375
 
  }
376
 
  
377
 
  return 0;
378
 
}
379
 
 
380
 
char **getargv(pid_t pid){
381
 
  int cl_fd;
382
 
  char *cmdline_filename;
383
 
  ssize_t sret;
384
 
  int ret;
385
 
  
386
 
  ret = asprintf(&cmdline_filename, "/proc/%" PRIuMAX "/cmdline",
387
 
                 (uintmax_t)pid);
388
 
  if(ret == -1){
389
 
    error_plus(0, errno, "asprintf");
390
 
    return NULL;
391
 
  }
392
 
  
393
 
  /* Open /proc/<pid>/cmdline  */
394
 
  cl_fd = open(cmdline_filename, O_RDONLY);
395
 
  free(cmdline_filename);
396
 
  if(cl_fd == -1){
397
 
    error_plus(0, errno, "open");
398
 
    return NULL;
399
 
  }
400
 
  
401
 
  size_t cmdline_allocated = 0;
402
 
  size_t cmdline_len = 0;
403
 
  char *cmdline = NULL;
404
 
  char *tmp;
405
 
  const size_t blocksize = 1024;
406
 
  do {
407
 
    /* Allocate more space? */
408
 
    if(cmdline_len + blocksize > cmdline_allocated){
409
 
      tmp = realloc(cmdline, cmdline_allocated + blocksize);
410
 
      if(tmp == NULL){
411
 
        error_plus(0, errno, "realloc");
412
 
        free(cmdline);
413
 
        close(cl_fd);
414
 
        return NULL;
415
 
      }
416
 
      cmdline = tmp;
417
 
      cmdline_allocated += blocksize;
418
 
    }
419
 
    
420
 
    /* Read data */
421
 
    sret = read(cl_fd, cmdline + cmdline_len,
422
 
                cmdline_allocated - cmdline_len);
423
 
    if(sret == -1){
424
 
      error_plus(0, errno, "read");
425
 
      free(cmdline);
426
 
      close(cl_fd);
427
 
      return NULL;
428
 
    }
429
 
    cmdline_len += (size_t)sret;
430
 
  } while(sret != 0);
431
 
  ret = close(cl_fd);
432
 
  if(ret == -1){
433
 
    error_plus(0, errno, "close");
434
 
    free(cmdline);
435
 
    return NULL;
436
 
  }
437
 
  
438
 
  /* we got cmdline and cmdline_len, ignore rest... */
439
 
  char **argv = malloc((argz_count(cmdline, cmdline_len) + 1)
440
 
                       * sizeof(char *)); /* Get number of args */
441
 
  if(argv == NULL){
442
 
    error_plus(0, errno, "argv = malloc()");
443
 
    free(cmdline);
444
 
    return NULL;
445
 
  }
446
 
  argz_extract(cmdline, cmdline_len, argv); /* Create argv */
447
 
  return argv;
448
 
}
449
 
 
450
 
int main(__attribute__((unused))int argc,
451
 
         __attribute__((unused))char **argv){
452
 
  char *prompt = NULL;
453
 
  char *prompt_arg;
454
 
  pid_t plymouth_command_pid;
455
 
  int ret;
456
 
  bool bret;
457
 
 
458
 
  {
459
 
    struct argp_option options[] = {
460
 
      { .name = "prompt", .key = 128, .arg = "PROMPT",
461
 
        .doc = "The prompt to show" },
462
 
      { .name = "debug", .key = 129,
463
 
        .doc = "Debug mode" },
464
 
      { .name = NULL }
465
 
    };
466
 
    
467
 
    __attribute__((nonnull(3)))
468
 
    error_t parse_opt (int key, char *arg, __attribute__((unused))
469
 
                       struct argp_state *state){
470
 
      errno = 0;
471
 
      switch (key){
472
 
      case 128:                 /* --prompt */
473
 
        prompt = arg;
474
 
        if(debug){
475
 
          fprintf_plus(stderr, "Custom prompt \"%s\"\n", prompt);
476
 
        }
477
 
        break;
478
 
      case 129:                 /* --debug */
479
 
        debug = true;
480
 
        break;
481
 
      default:
482
 
        return ARGP_ERR_UNKNOWN;
483
 
      }
484
 
      return errno;
485
 
    }
486
 
    
487
 
    struct argp argp = { .options = options, .parser = parse_opt,
488
 
                         .args_doc = "",
489
 
                         .doc = "Mandos plymouth -- Read and"
490
 
                         " output a password" };
491
 
    ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, NULL);
492
 
    switch(ret){
493
 
    case 0:
494
 
      break;
495
 
    case ENOMEM:
496
 
    default:
497
 
      errno = ret;
498
 
      error_plus(0, errno, "argp_parse");
499
 
      return EX_OSERR;
500
 
    case EINVAL:
501
 
      error_plus(0, errno, "argp_parse");
502
 
      return EX_USAGE;
503
 
    }
504
 
  }
505
 
  
506
 
  /* test -x /bin/plymouth */
507
 
  ret = access(plymouth_path, X_OK);
508
 
  if(ret == -1){
509
 
    /* Plymouth is probably not installed.  Don't print an error
510
 
       message, just exit. */
511
 
    if(debug){
512
 
      fprintf_plus(stderr, "Plymouth (%s) not found\n",
513
 
                   plymouth_path);
514
 
    }
515
 
    exit(EX_UNAVAILABLE);
516
 
  }
517
 
  
518
 
  { /* Add signal handlers */
519
 
    struct sigaction old_action,
520
 
      new_action = { .sa_handler = termination_handler,
521
 
                     .sa_flags = 0 };
522
 
    sigemptyset(&new_action.sa_mask);
523
 
    for(int *sig = (int[]){ SIGINT, SIGHUP, SIGTERM, 0 };
524
 
        *sig != 0; sig++){
525
 
      ret = sigaddset(&new_action.sa_mask, *sig);
526
 
      if(ret == -1){
527
 
        error_plus(EX_OSERR, errno, "sigaddset");
528
 
      }
529
 
      ret = sigaction(*sig, NULL, &old_action);
530
 
      if(ret == -1){
531
 
        error_plus(EX_OSERR, errno, "sigaction");
532
 
      }
533
 
      if(old_action.sa_handler != SIG_IGN){
534
 
        ret = sigaction(*sig, &new_action, NULL);
535
 
        if(ret == -1){
536
 
          error_plus(EX_OSERR, errno, "sigaction");
537
 
        }
538
 
      }
539
 
    }
540
 
  }
541
 
  
542
 
  /* plymouth --ping */
543
 
  bret = exec_and_wait(&plymouth_command_pid, plymouth_path,
544
 
                       (const char *[])
545
 
                       { plymouth_path, "--ping", NULL },
546
 
                       true, false);
547
 
  if(not bret){
548
 
    if(interrupted_by_signal){
549
 
      kill_and_wait(plymouth_command_pid);
550
 
      exit(EXIT_FAILURE);
551
 
    }
552
 
    /* Plymouth is probably not running.  Don't print an error
553
 
       message, just exit. */
554
 
    if(debug){
555
 
      fprintf_plus(stderr, "Plymouth not running\n");
556
 
    }
557
 
    exit(EX_UNAVAILABLE);
558
 
  }
559
 
  
560
 
  if(prompt != NULL){
561
 
    ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
562
 
  } else {
563
 
    char *made_prompt = makeprompt();
564
 
    ret = asprintf(&prompt_arg, "--prompt=%s", made_prompt);
565
 
    free(made_prompt);
566
 
  }
567
 
  if(ret == -1){
568
 
    error_plus(EX_OSERR, errno, "asprintf");
569
 
  }
570
 
  
571
 
  /* plymouth ask-for-password --prompt="$prompt" */
572
 
  if(debug){
573
 
    fprintf_plus(stderr, "Prompting for password via Plymouth\n");
574
 
  }
575
 
  bret = exec_and_wait(&plymouth_command_pid,
576
 
                       plymouth_path, (const char *[])
577
 
                       { plymouth_path, "ask-for-password",
578
 
                           prompt_arg, NULL },
579
 
                       true, false);
580
 
  free(prompt_arg);
581
 
  if(bret){
582
 
    exit(EXIT_SUCCESS);
583
 
  }
584
 
  if(not interrupted_by_signal){
585
 
    /* exec_and_wait failed for some other reason */
586
 
    exit(EXIT_FAILURE);
587
 
  }
588
 
  kill_and_wait(plymouth_command_pid);
589
 
  
590
 
  char **plymouthd_argv = NULL;
591
 
  pid_t pid = get_pid();
592
 
  if(pid == 0){
593
 
    error_plus(0, 0, "plymouthd pid not found");
594
 
  } else {
595
 
    plymouthd_argv = getargv(pid);
596
 
  }
597
 
  
598
 
  bret = exec_and_wait(NULL, plymouth_path, (const char *[])
599
 
                       { plymouth_path, "quit", NULL },
600
 
                       false, false);
601
 
  if(not bret){
602
 
    if(plymouthd_argv != NULL){
603
 
      free(*plymouthd_argv);
604
 
      free(plymouthd_argv);
605
 
    }
606
 
    exit(EXIT_FAILURE);
607
 
  }
608
 
  bret = exec_and_wait(NULL, plymouthd_path,
609
 
                       (plymouthd_argv != NULL)
610
 
                       ? (const char * const *)plymouthd_argv
611
 
                       : plymouthd_default_argv,
612
 
                       false, true);
613
 
  if(plymouthd_argv != NULL){
614
 
    free(*plymouthd_argv);
615
 
    free(plymouthd_argv);
616
 
  }
617
 
  if(not bret){
618
 
    exit(EXIT_FAILURE);
619
 
  }
620
 
  exec_and_wait(NULL, plymouth_path, (const char *[])
621
 
                { plymouth_path, "show-splash", NULL },
622
 
                false, false);
623
 
  exit(EXIT_FAILURE);
624
 
}