/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 at recompile
  • Date: 2020-04-05 21:30:59 UTC
  • mto: This revision was merged to the branch mainline in revision 398.
  • Revision ID: teddy@recompile.se-20200405213059-fb2a61ckqynrmatk
Fix file descriptor leak in mandos-client

When the local network has Mandos servers announcing themselves using
real, globally reachable, IPv6 addresses (i.e. not link-local
addresses), but there is no router on the local network providing IPv6
RA (Router Advertisement) packets, the client cannot reach the server
by normal means, since the client only has a link-local IPv6 address,
and has no usable route to reach the server's global IPv6 address.
(This is not a common situation, and usually only happens when the
router itself reboots and runs a Mandos client, since it cannot then
give RA packets to itself.)  The client code has a solution for
this, which consists of adding a temporary local route to reach the
address of the server during communication, and removing this
temporary route afterwards.

This solution with a temporary route works, but has a file descriptor
leak; it leaks one file descriptor for each addition and for each
removal of a route.  If one server requiring an added route is present
on the network, but no servers gives a password, making the client
retry after the default ten seconds, and we furthermore assume a
default 1024 open files limit, the client runs out of file descriptors
after about 90 minutes, after which time the client process will be
useless and fail to retrieve any passwords, necessitating manual
password entry via the keyboard.

Fix this by eliminating the file descriptor leak in the client.

* plugins.d/mandos-client.c (add_delete_local_route): Do
  close(devnull) also in parent process, also if fork() fails, and on
  any failure in child process.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Usplash - Read a password from usplash and output it
4
 
 * 
5
 
 * Copyright © 2010 Teddy Hogeborn
6
 
 * Copyright © 2010 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
 
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
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
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
23
 * Contact the authors at <mandos@recompile.se>.
23
24
 */
24
25
 
25
26
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
36
37
#include <stddef.h>             /* NULL */
37
38
#include <string.h>             /* strchr(), memcmp() */
38
39
#include <stdio.h>              /* asprintf(), perror(), fopen(),
39
 
                                   fscanf() */
 
40
                                   fscanf(), vasprintf(), fprintf(),
 
41
                                   vfprintf() */
40
42
#include <unistd.h>             /* close(), readlink(), read(),
41
43
                                   fork(), setsid(), chdir(), dup2(),
42
44
                                   STDERR_FILENO, execv(), access() */
43
45
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
44
46
                                   EXIT_SUCCESS, malloc(), _exit(),
45
 
                                   getenv() */
 
47
                                   getenv(), reallocarray() */
46
48
#include <dirent.h>             /* scandir(), alphasort() */
47
49
#include <inttypes.h>           /* intmax_t, strtoumax(), SCNuMAX */
48
50
#include <sys/stat.h>           /* struct stat, lstat() */
50
52
#include <error.h>              /* error() */
51
53
#include <errno.h>              /* TEMP_FAILURE_RETRY */
52
54
#include <argz.h>               /* argz_count(), argz_extract() */
 
55
#include <stdarg.h>             /* va_list, va_start(), ... */
 
56
#include <argp.h>
53
57
 
54
58
sig_atomic_t interrupted_by_signal = 0;
55
 
const char plymouth_pid[] = "/dev/.initramfs/plymouth.pid";
 
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
 
56
69
const char plymouth_path[] = "/bin/plymouth";
57
70
const char plymouthd_path[] = "/sbin/plymouthd";
58
71
const char *plymouthd_default_argv[] = {"/sbin/plymouthd",
59
72
                                        "--mode=boot",
60
73
                                        "--attach-to-session",
61
 
                                        "--pid-file="
62
 
                                        "/dev/.initramfs/"
63
 
                                        "plymouth.pid",
64
74
                                        NULL };
 
75
bool debug = false;
65
76
 
66
77
static void termination_handler(__attribute__((unused))int signum){
67
78
  if(interrupted_by_signal){
70
81
  interrupted_by_signal = 1;
71
82
}
72
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
 
73
116
/* Create prompt string */
74
117
char *makeprompt(void){
75
118
  int ret = 0;
76
119
  char *prompt;
77
120
  const char *const cryptsource = getenv("cryptsource");
78
121
  const char *const crypttarget = getenv("crypttarget");
79
 
  const char prompt_start[] = "Enter passphrase to unlock the disk";
 
122
  const char prompt_start[] = "Unlocking the disk";
 
123
  const char prompt_end[] = "Enter passphrase";
80
124
  
81
125
  if(cryptsource == NULL){
82
126
    if(crypttarget == NULL){
83
 
      ret = asprintf(&prompt, "%s: ", prompt_start);
 
127
      ret = asprintf(&prompt, "%s\n%s", prompt_start, prompt_end);
84
128
    } else {
85
 
      ret = asprintf(&prompt, "%s (%s): ", prompt_start,
86
 
                     crypttarget);
 
129
      ret = asprintf(&prompt, "%s (%s)\n%s", prompt_start,
 
130
                     crypttarget, prompt_end);
87
131
    }
88
132
  } else {
89
133
    if(crypttarget == NULL){
90
 
      ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
 
134
      ret = asprintf(&prompt, "%s %s\n%s", prompt_start, cryptsource,
 
135
                     prompt_end);
91
136
    } else {
92
 
      ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
93
 
                     cryptsource, crypttarget);
 
137
      ret = asprintf(&prompt, "%s %s (%s)\n%s", prompt_start,
 
138
                     cryptsource, crypttarget, prompt_end);
94
139
    }
95
140
  }
96
141
  if(ret == -1){
107
152
bool become_a_daemon(void){
108
153
  int ret = setuid(geteuid());
109
154
  if(ret == -1){
110
 
    error(0, errno, "setuid");
 
155
    error_plus(0, errno, "setuid");
111
156
  }
112
157
    
113
158
  setsid();
114
159
  ret = chdir("/");
115
160
  if(ret == -1){
116
 
    error(0, errno, "chdir");
 
161
    error_plus(0, errno, "chdir");
117
162
    return false;
118
163
  }
119
164
  ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
120
165
  if(ret == -1){
121
 
    error(0, errno, "dup2");
 
166
    error_plus(0, errno, "dup2");
122
167
    return false;
123
168
  }
124
169
  return true;
125
170
}
126
171
 
 
172
__attribute__((nonnull (2, 3)))
127
173
bool exec_and_wait(pid_t *pid_return, const char *path,
128
 
                   const char **argv, bool interruptable,
 
174
                   const char * const * const argv, bool interruptable,
129
175
                   bool daemonize){
130
176
  int status;
131
177
  int ret;
132
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
 
133
186
  pid = fork();
134
187
  if(pid == -1){
135
 
    error(0, errno, "fork");
 
188
    error_plus(0, errno, "fork");
136
189
    return false;
137
190
  }
138
191
  if(pid == 0){
142
195
        _exit(EX_OSERR);
143
196
      }
144
197
    }
145
 
 
146
 
    char **new_argv = NULL;
147
 
    char *tmp;
 
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;
148
205
    int i = 0;
149
 
    for (; argv[i]!=(char *)NULL; i++){
150
 
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 1));
151
 
      if (tmp == NULL){
152
 
        error(0, errno, "realloc");
 
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");
153
221
        free(new_argv);
154
222
        _exit(EX_OSERR);
155
223
      }
156
 
      new_argv = (char **)tmp;
 
224
      new_argv = tmp;
157
225
      new_argv[i] = strdup(argv[i]);
158
226
    }
159
 
    new_argv[i] = (char *) NULL;
 
227
    new_argv[i] = NULL;
160
228
    
161
229
    execv(path, (char *const *)new_argv);
162
 
    error(0, errno, "execv");
 
230
    error_plus(0, errno, "execv");
163
231
    _exit(EXIT_FAILURE);
164
232
  }
165
233
  if(pid_return != NULL){
171
239
          and ((not interrupted_by_signal)
172
240
               or (not interruptable)));
173
241
  if(interrupted_by_signal and interruptable){
 
242
    if(debug){
 
243
      fprintf_plus(stderr, "Interrupted by signal\n");
 
244
    }
174
245
    return false;
175
246
  }
176
247
  if(ret == -1){
177
 
    error(0, errno, "waitpid");
 
248
    error_plus(0, errno, "waitpid");
178
249
    return false;
179
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
  }
180
260
  if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
181
261
    return true;
182
262
  }
183
263
  return false;
184
264
}
185
265
 
 
266
__attribute__((nonnull))
186
267
int is_plymouth(const struct dirent *proc_entry){
187
268
  int ret;
188
269
  {
189
 
    uintmax_t maxvalue;
 
270
    uintmax_t proc_id;
190
271
    char *tmp;
191
272
    errno = 0;
192
 
    maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
273
    proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
193
274
 
194
275
    if(errno != 0 or *tmp != '\0'
195
 
       or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
276
       or proc_id != (uintmax_t)((pid_t)proc_id)){
196
277
      return 0;
197
278
    }
198
279
  }
199
 
  char exe_target[sizeof(plymouth_path)];
 
280
  char exe_target[sizeof(plymouthd_path)];
200
281
  char *exe_link;
201
282
  ret = asprintf(&exe_link, "/proc/%s/exe", proc_entry->d_name);
202
283
  if(ret == -1){
203
 
    error(0, errno, "asprintf");
 
284
    error_plus(0, errno, "asprintf");
204
285
    return 0;
205
286
  }
206
287
  
209
290
  if(ret == -1){
210
291
    free(exe_link);
211
292
    if(errno != ENOENT){
212
 
      error(0, errno, "lstat");
 
293
      error_plus(0, errno, "lstat");
213
294
    }
214
295
    return 0;
215
296
  }
223
304
  
224
305
  ssize_t sret = readlink(exe_link, exe_target, sizeof(exe_target));
225
306
  free(exe_link);
226
 
  if((sret != (ssize_t)sizeof(plymouth_path)-1) or
227
 
      (memcmp(plymouth_path, exe_target,
228
 
              sizeof(plymouth_path)-1) != 0)){
 
307
  if((sret != (ssize_t)sizeof(plymouthd_path)-1) or
 
308
      (memcmp(plymouthd_path, exe_target,
 
309
              sizeof(plymouthd_path)-1) != 0)){
229
310
    return 0;
230
311
  }
231
312
  return 1;
233
314
 
234
315
pid_t get_pid(void){
235
316
  int ret;
 
317
  uintmax_t proc_id = 0;
236
318
  FILE *pidfile = fopen(plymouth_pid, "r");
237
 
  uintmax_t maxvalue = 0;
 
319
  /* Try the new pid file location */
238
320
  if(pidfile != NULL){
239
 
    ret = fscanf(pidfile, "%" SCNuMAX, &maxvalue);
 
321
    ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
240
322
    if(ret != 1){
241
 
      maxvalue = 0;
 
323
      proc_id = 0;
242
324
    }
243
325
    fclose(pidfile);
244
326
  }
245
 
  if(maxvalue == 0){
246
 
    struct dirent **direntries;
 
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;
247
352
    ret = scandir("/proc", &direntries, is_plymouth, alphasort);
248
 
    sscanf(direntries[0]->d_name, "%" SCNuMAX, &maxvalue);
 
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);
249
370
  }
250
371
  pid_t pid;
251
 
  pid = (pid_t)maxvalue;
252
 
  if((uintmax_t)pid == maxvalue){
 
372
  pid = (pid_t)proc_id;
 
373
  if((uintmax_t)pid == proc_id){
253
374
    return pid;
254
375
  }
255
376
  
256
377
  return 0;
257
378
}
258
379
 
259
 
const char **getargv(pid_t pid){
 
380
char **getargv(pid_t pid){
260
381
  int cl_fd;
261
382
  char *cmdline_filename;
262
383
  ssize_t sret;
265
386
  ret = asprintf(&cmdline_filename, "/proc/%" PRIuMAX "/cmdline",
266
387
                 (uintmax_t)pid);
267
388
  if(ret == -1){
268
 
    error(0, errno, "asprintf");
 
389
    error_plus(0, errno, "asprintf");
269
390
    return NULL;
270
391
  }
271
392
  
273
394
  cl_fd = open(cmdline_filename, O_RDONLY);
274
395
  free(cmdline_filename);
275
396
  if(cl_fd == -1){
276
 
    error(0, errno, "open");
 
397
    error_plus(0, errno, "open");
277
398
    return NULL;
278
399
  }
279
400
  
287
408
    if(cmdline_len + blocksize > cmdline_allocated){
288
409
      tmp = realloc(cmdline, cmdline_allocated + blocksize);
289
410
      if(tmp == NULL){
290
 
        error(0, errno, "realloc");
 
411
        error_plus(0, errno, "realloc");
291
412
        free(cmdline);
292
413
        close(cl_fd);
293
414
        return NULL;
300
421
    sret = read(cl_fd, cmdline + cmdline_len,
301
422
                cmdline_allocated - cmdline_len);
302
423
    if(sret == -1){
303
 
      error(0, errno, "read");
 
424
      error_plus(0, errno, "read");
304
425
      free(cmdline);
305
426
      close(cl_fd);
306
427
      return NULL;
309
430
  } while(sret != 0);
310
431
  ret = close(cl_fd);
311
432
  if(ret == -1){
312
 
    error(0, errno, "close");
 
433
    error_plus(0, errno, "close");
313
434
    free(cmdline);
314
435
    return NULL;
315
436
  }
318
439
  char **argv = malloc((argz_count(cmdline, cmdline_len) + 1)
319
440
                       * sizeof(char *)); /* Get number of args */
320
441
  if(argv == NULL){
321
 
    error(0, errno, "argv = malloc()");
 
442
    error_plus(0, errno, "argv = malloc()");
322
443
    free(cmdline);
323
444
    return NULL;
324
445
  }
325
446
  argz_extract(cmdline, cmdline_len, argv); /* Create argv */
326
 
  return (const char **)argv;
 
447
  return argv;
327
448
}
328
449
 
329
450
int main(__attribute__((unused))int argc,
330
451
         __attribute__((unused))char **argv){
331
 
  char *prompt;
 
452
  char *prompt = NULL;
332
453
  char *prompt_arg;
333
454
  pid_t plymouth_command_pid;
334
455
  int ret;
335
456
  bool bret;
336
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
  
337
506
  /* test -x /bin/plymouth */
338
507
  ret = access(plymouth_path, X_OK);
339
508
  if(ret == -1){
340
509
    /* Plymouth is probably not installed.  Don't print an error
341
510
       message, just exit. */
 
511
    if(debug){
 
512
      fprintf_plus(stderr, "Plymouth (%s) not found\n",
 
513
                   plymouth_path);
 
514
    }
342
515
    exit(EX_UNAVAILABLE);
343
516
  }
344
517
  
351
524
        *sig != 0; sig++){
352
525
      ret = sigaddset(&new_action.sa_mask, *sig);
353
526
      if(ret == -1){
354
 
        error(EX_OSERR, errno, "sigaddset");
 
527
        error_plus(EX_OSERR, errno, "sigaddset");
355
528
      }
356
529
      ret = sigaction(*sig, NULL, &old_action);
357
530
      if(ret == -1){
358
 
        error(EX_OSERR, errno, "sigaction");
 
531
        error_plus(EX_OSERR, errno, "sigaction");
359
532
      }
360
533
      if(old_action.sa_handler != SIG_IGN){
361
534
        ret = sigaction(*sig, &new_action, NULL);
362
535
        if(ret == -1){
363
 
          error(EX_OSERR, errno, "sigaction");
 
536
          error_plus(EX_OSERR, errno, "sigaction");
364
537
        }
365
538
      }
366
539
    }
378
551
    }
379
552
    /* Plymouth is probably not running.  Don't print an error
380
553
       message, just exit. */
 
554
    if(debug){
 
555
      fprintf_plus(stderr, "Plymouth not running\n");
 
556
    }
381
557
    exit(EX_UNAVAILABLE);
382
558
  }
383
559
  
384
 
  prompt = makeprompt();
385
 
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
386
 
  free(prompt);
 
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
  }
387
567
  if(ret == -1){
388
 
    error(EX_OSERR, errno, "asprintf");
 
568
    error_plus(EX_OSERR, errno, "asprintf");
389
569
  }
390
570
  
391
571
  /* plymouth ask-for-password --prompt="$prompt" */
 
572
  if(debug){
 
573
    fprintf_plus(stderr, "Prompting for password via Plymouth\n");
 
574
  }
392
575
  bret = exec_and_wait(&plymouth_command_pid,
393
576
                       plymouth_path, (const char *[])
394
577
                       { plymouth_path, "ask-for-password",
404
587
  }
405
588
  kill_and_wait(plymouth_command_pid);
406
589
  
407
 
  const char **plymouthd_argv;
 
590
  char **plymouthd_argv = NULL;
408
591
  pid_t pid = get_pid();
409
592
  if(pid == 0){
410
 
    error(0, 0, "plymouthd pid not found");
411
 
    plymouthd_argv = plymouthd_default_argv;
 
593
    error_plus(0, 0, "plymouthd pid not found");
412
594
  } else {
413
595
    plymouthd_argv = getargv(pid);
414
596
  }
417
599
                       { plymouth_path, "quit", NULL },
418
600
                       false, false);
419
601
  if(not bret){
 
602
    if(plymouthd_argv != NULL){
 
603
      free(*plymouthd_argv);
 
604
      free(plymouthd_argv);
 
605
    }
420
606
    exit(EXIT_FAILURE);
421
607
  }
422
 
  bret = exec_and_wait(NULL, plymouthd_path, plymouthd_argv,
 
608
  bret = exec_and_wait(NULL, plymouthd_path,
 
609
                       (plymouthd_argv != NULL)
 
610
                       ? (const char * const *)plymouthd_argv
 
611
                       : plymouthd_default_argv,
423
612
                       false, true);
 
613
  if(plymouthd_argv != NULL){
 
614
    free(*plymouthd_argv);
 
615
    free(plymouthd_argv);
 
616
  }
424
617
  if(not bret){
425
618
    exit(EXIT_FAILURE);
426
619
  }