/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 at recompile
  • Date: 2020-12-03 20:30:45 UTC
  • Revision ID: teddy@recompile.se-20201203203045-iqd6nq9y5nwalh1x
Minor fix of a test function

In dracut-module/password-agent, the test function
test_send_password_to_socket_EMSGSIZE() (which tests that the
send_password_to_socket() task function aborts properly when getting
EMSGSIZE when writing to the password socket), part of the test code
is supposed to find a message size which definitely does trigger
EMSGSIZE when send()ing to a socket.  Without a "break" in the proper
place, however, the size given is always exactly 1024 bytes too large.

This is very probably not a problem, since a too large message will
still be too large if it is increased by 1024 bytes, and send(2) in
practice checks the size before reading the buffer.  The biggest issue
would be if some version of send(2) would try to look at the last 1024
bytes of the message buffer before checking the message size; this
would then lead to a buffer over-read when running this test function.
(But even then there would be no security implications since the tests
are not run in the normal operation of the program.)

* dracut-module/password-agent.c
  (test_send_password_to_socket_EMSGSIZE): Break out early when ssret
  < 0 and errno == EMSGSIZE; don't allow loop to increase message_size
  again.

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-2020 Teddy Hogeborn
 
6
 * Copyright © 2010-2020 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
 
1
26
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
2
27
#include <signal.h>             /* sig_atomic_t, struct sigaction,
3
28
                                   sigemptyset(), sigaddset(), SIGINT,
6
31
#include <stdbool.h>            /* bool, false, true */
7
32
#include <fcntl.h>              /* open(), O_RDONLY */
8
33
#include <iso646.h>             /* and, or, not*/
9
 
#include <sys/types.h>          /* size_t, ssize_t, pid_t, struct dirent,
10
 
                                   waitpid() */
 
34
#include <sys/types.h>          /* size_t, ssize_t, pid_t, struct
 
35
                                   dirent, waitpid() */
11
36
#include <sys/wait.h>           /* waitpid() */
12
37
#include <stddef.h>             /* NULL */
13
38
#include <string.h>             /* strchr(), memcmp() */
14
 
#include <stdio.h>              /* asprintf(), perror(), fopen(), fscanf() */
15
 
#include <unistd.h>             /* close(), readlink(), read(), fork()
16
 
                                   setsid(), chdir(), dup2()
 
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(),
17
44
                                   STDERR_FILENO, execv(), access() */
18
45
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
19
46
                                   EXIT_SUCCESS, malloc(), _exit(),
20
 
                                   getenv() */
 
47
                                   getenv(), reallocarray() */
21
48
#include <dirent.h>             /* scandir(), alphasort() */
22
49
#include <inttypes.h>           /* intmax_t, strtoumax(), SCNuMAX */
23
50
#include <sys/stat.h>           /* struct stat, lstat() */
24
 
#include <sysexits.h>           /* EX_OSERR */
 
51
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
25
52
#include <error.h>              /* error() */
26
53
#include <errno.h>              /* TEMP_FAILURE_RETRY */
27
 
#include <stdarg.h>
 
54
#include <argz.h>               /* argz_count(), argz_extract() */
 
55
#include <stdarg.h>             /* va_list, va_start(), ... */
 
56
#include <argp.h>
28
57
 
29
58
sig_atomic_t interrupted_by_signal = 0;
30
 
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
 
31
69
const char plymouth_path[] = "/bin/plymouth";
32
70
const char plymouthd_path[] = "/sbin/plymouthd";
33
 
const char *plymouthd_default_argv[] = {"/sbin/plymouthd", "--mode=boot",
 
71
const char *plymouthd_default_argv[] = {"/sbin/plymouthd",
 
72
                                        "--mode=boot",
34
73
                                        "--attach-to-session",
35
 
                                        "--pid-file=/dev/.initramfs/plymouth.pid",
36
74
                                        NULL };
 
75
bool debug = false;
37
76
 
38
77
static void termination_handler(__attribute__((unused))int signum){
39
78
  if(interrupted_by_signal){
42
81
  interrupted_by_signal = 1;
43
82
}
44
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
 
45
116
/* Create prompt string */
46
117
char *makeprompt(void){
47
118
  int ret = 0;
48
119
  char *prompt;
49
120
  const char *const cryptsource = getenv("cryptsource");
50
121
  const char *const crypttarget = getenv("crypttarget");
51
 
  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";
52
124
  
53
125
  if(cryptsource == NULL){
54
126
    if(crypttarget == NULL){
55
 
      ret = asprintf(&prompt, "%s: ", prompt_start);
 
127
      ret = asprintf(&prompt, "%s\n%s", prompt_start, prompt_end);
56
128
    } else {
57
 
      ret = asprintf(&prompt, "%s (%s): ", prompt_start,
58
 
                     crypttarget);
 
129
      ret = asprintf(&prompt, "%s (%s)\n%s", prompt_start,
 
130
                     crypttarget, prompt_end);
59
131
    }
60
132
  } else {
61
133
    if(crypttarget == NULL){
62
 
      ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
 
134
      ret = asprintf(&prompt, "%s %s\n%s", prompt_start, cryptsource,
 
135
                     prompt_end);
63
136
    } else {
64
 
      ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
65
 
                     cryptsource, crypttarget);
 
137
      ret = asprintf(&prompt, "%s %s (%s)\n%s", prompt_start,
 
138
                     cryptsource, crypttarget, prompt_end);
66
139
    }
67
140
  }
68
141
  if(ret == -1){
79
152
bool become_a_daemon(void){
80
153
  int ret = setuid(geteuid());
81
154
  if(ret == -1){
82
 
    error(0, errno, "setuid");
 
155
    error_plus(0, errno, "setuid");
83
156
  }
84
157
    
85
158
  setsid();
86
159
  ret = chdir("/");
87
160
  if(ret == -1){
88
 
    error(0, errno, "chdir");
 
161
    error_plus(0, errno, "chdir");
89
162
    return false;
90
163
  }
91
164
  ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
92
165
  if(ret == -1){
93
 
    error(0, errno, "dup2");
 
166
    error_plus(0, errno, "dup2");
94
167
    return false;
95
168
  }
96
169
  return true;
97
170
}
98
171
 
 
172
__attribute__((nonnull (2, 3)))
99
173
bool exec_and_wait(pid_t *pid_return, const char *path,
100
 
                   const char **argv, bool interruptable,
 
174
                   const char * const * const argv, bool interruptable,
101
175
                   bool daemonize){
102
176
  int status;
103
177
  int ret;
104
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
 
105
186
  pid = fork();
106
187
  if(pid == -1){
107
 
    error(0, errno, "fork");
 
188
    error_plus(0, errno, "fork");
108
189
    return false;
109
190
  }
110
191
  if(pid == 0){
114
195
        _exit(EX_OSERR);
115
196
      }
116
197
    }
117
 
 
118
 
    char **new_argv = NULL;
119
 
    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;
120
205
    int i = 0;
121
 
    for (; argv[i]!=(char *)NULL; i++){
122
 
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 1));
123
 
      if (tmp == NULL){
124
 
        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");
125
221
        free(new_argv);
126
 
        _exit(EXIT_FAILURE);
 
222
        _exit(EX_OSERR);
127
223
      }
128
 
      new_argv = (char **)tmp;
 
224
      new_argv = tmp;
129
225
      new_argv[i] = strdup(argv[i]);
130
226
    }
131
 
    new_argv[i] = (char *) NULL;
 
227
    new_argv[i] = NULL;
132
228
    
133
229
    execv(path, (char *const *)new_argv);
134
 
    error(0, errno, "execv");
 
230
    error_plus(0, errno, "execv");
135
231
    _exit(EXIT_FAILURE);
136
232
  }
137
233
  if(pid_return != NULL){
143
239
          and ((not interrupted_by_signal)
144
240
               or (not interruptable)));
145
241
  if(interrupted_by_signal and interruptable){
 
242
    if(debug){
 
243
      fprintf_plus(stderr, "Interrupted by signal\n");
 
244
    }
146
245
    return false;
147
246
  }
148
247
  if(ret == -1){
149
 
    error(0, errno, "waitpid");
 
248
    error_plus(0, errno, "waitpid");
150
249
    return false;
151
250
  }
152
 
  if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
 
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)){
153
261
    return true;
154
262
  }
155
263
  return false;
156
264
}
157
265
 
 
266
__attribute__((nonnull))
158
267
int is_plymouth(const struct dirent *proc_entry){
159
268
  int ret;
160
269
  {
161
 
    uintmax_t maxvalue;
 
270
    uintmax_t proc_id;
162
271
    char *tmp;
163
272
    errno = 0;
164
 
    maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
273
    proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
165
274
 
166
 
    if(errno != 0 or *tmp != '\0' or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
275
    if(errno != 0 or *tmp != '\0'
 
276
       or proc_id != (uintmax_t)((pid_t)proc_id)){
167
277
      return 0;
168
278
    }
169
279
  }
170
 
  char exe_target[sizeof(plymouth_path)];
 
280
  char exe_target[sizeof(plymouthd_path)];
171
281
  char *exe_link;
172
282
  ret = asprintf(&exe_link, "/proc/%s/exe", proc_entry->d_name);
173
283
  if(ret == -1){
174
 
    error(0, errno, "asprintf");
 
284
    error_plus(0, errno, "asprintf");
175
285
    return 0;
176
286
  }
177
 
 
 
287
  
178
288
  struct stat exe_stat;
179
289
  ret = lstat(exe_link, &exe_stat);
180
290
  if(ret == -1){
181
291
    free(exe_link);
182
292
    if(errno != ENOENT){
183
 
      error(0, errno, "lstat");
 
293
      error_plus(0, errno, "lstat");
184
294
    }
185
295
    return 0;
186
296
  }
191
301
    free(exe_link);
192
302
    return 0;
193
303
  }
194
 
 
 
304
  
195
305
  ssize_t sret = readlink(exe_link, exe_target, sizeof(exe_target));
196
306
  free(exe_link);
197
 
  if((sret != (ssize_t)sizeof(plymouth_path)-1) or
198
 
      (memcmp(plymouth_path, exe_target,
199
 
              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)){
200
310
    return 0;
201
311
  }
202
312
  return 1;
204
314
 
205
315
pid_t get_pid(void){
206
316
  int ret;
 
317
  uintmax_t proc_id = 0;
207
318
  FILE *pidfile = fopen(plymouth_pid, "r");
208
 
  uintmax_t maxvalue = 0;
 
319
  /* Try the new pid file location */
209
320
  if(pidfile != NULL){
210
 
    ret = fscanf(pidfile, "%" SCNuMAX, &maxvalue);
 
321
    ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
211
322
    if(ret != 1){
212
 
      maxvalue = 0;
 
323
      proc_id = 0;
213
324
    }
214
325
    fclose(pidfile);
215
326
  }
216
 
  if(maxvalue == 0){
217
 
    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;
218
352
    ret = scandir("/proc", &direntries, is_plymouth, alphasort);
219
 
    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);
220
370
  }
221
371
  pid_t pid;
222
 
  pid = (pid_t)maxvalue;
223
 
  if((uintmax_t)pid == maxvalue){
 
372
  pid = (pid_t)proc_id;
 
373
  if((uintmax_t)pid == proc_id){
224
374
    return pid;
225
375
  }
226
376
  
227
377
  return 0;
228
378
}
229
379
 
230
 
const char **getargv(pid_t pid){
 
380
char **getargv(pid_t pid){
231
381
  int cl_fd;
232
382
  char *cmdline_filename;
233
383
  ssize_t sret;
236
386
  ret = asprintf(&cmdline_filename, "/proc/%" PRIuMAX "/cmdline",
237
387
                 (uintmax_t)pid);
238
388
  if(ret == -1){
239
 
    error(0, errno, "asprintf");
 
389
    error_plus(0, errno, "asprintf");
240
390
    return NULL;
241
391
  }
242
392
  
244
394
  cl_fd = open(cmdline_filename, O_RDONLY);
245
395
  free(cmdline_filename);
246
396
  if(cl_fd == -1){
247
 
    error(0, errno, "open");
 
397
    error_plus(0, errno, "open");
248
398
    return NULL;
249
399
  }
250
400
  
258
408
    if(cmdline_len + blocksize > cmdline_allocated){
259
409
      tmp = realloc(cmdline, cmdline_allocated + blocksize);
260
410
      if(tmp == NULL){
261
 
        error(0, errno, "realloc");
 
411
        error_plus(0, errno, "realloc");
262
412
        free(cmdline);
263
413
        close(cl_fd);
264
414
        return NULL;
271
421
    sret = read(cl_fd, cmdline + cmdline_len,
272
422
                cmdline_allocated - cmdline_len);
273
423
    if(sret == -1){
274
 
      error(0, errno, "read");
 
424
      error_plus(0, errno, "read");
275
425
      free(cmdline);
276
426
      close(cl_fd);
277
427
      return NULL;
280
430
  } while(sret != 0);
281
431
  ret = close(cl_fd);
282
432
  if(ret == -1){
283
 
    error(0, errno, "close");
 
433
    error_plus(0, errno, "close");
284
434
    free(cmdline);
285
435
    return NULL;
286
436
  }
287
437
  
288
438
  /* we got cmdline and cmdline_len, ignore rest... */
289
 
  const char **argv = NULL;
290
 
  size_t argv_size = 0;
291
 
  for(char *arg = cmdline; arg-cmdline < (ssize_t)cmdline_len;
292
 
      arg = strchr(arg, '\0')+1){
293
 
    tmp = realloc(argv, ((++argv_size)+1)*sizeof(char *));
294
 
    if(tmp == NULL){
295
 
      error(0, errno, "realloc");
296
 
      free(argv);
297
 
      return NULL;
298
 
    }
299
 
    argv = (const char **)tmp;
300
 
    argv[argv_size-1] = arg;
 
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;
301
445
  }
302
 
  argv[argv_size] = NULL;
 
446
  argz_extract(cmdline, cmdline_len, argv); /* Create argv */
303
447
  return argv;
304
448
}
305
449
 
306
450
int main(__attribute__((unused))int argc,
307
451
         __attribute__((unused))char **argv){
308
 
  char *prompt;
 
452
  char *prompt = NULL;
309
453
  char *prompt_arg;
310
454
  pid_t plymouth_command_pid;
311
455
  int ret;
312
456
  bool bret;
313
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
  
314
506
  /* test -x /bin/plymouth */
315
507
  ret = access(plymouth_path, X_OK);
316
508
  if(ret == -1){
317
 
    exit(EXIT_FAILURE);
 
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);
318
516
  }
319
 
 
 
517
  
320
518
  { /* Add signal handlers */
321
519
    struct sigaction old_action,
322
520
      new_action = { .sa_handler = termination_handler,
323
521
                     .sa_flags = 0 };
324
522
    sigemptyset(&new_action.sa_mask);
325
 
    for(int *sig = (int[]){ SIGINT, SIGHUP, SIGTERM, 0 }; *sig != 0; sig++){
 
523
    for(int *sig = (int[]){ SIGINT, SIGHUP, SIGTERM, 0 };
 
524
        *sig != 0; sig++){
326
525
      ret = sigaddset(&new_action.sa_mask, *sig);
327
526
      if(ret == -1){
328
 
        error(0, errno, "sigaddset");
329
 
        exit(EX_OSERR);
 
527
        error_plus(EX_OSERR, errno, "sigaddset");
330
528
      }
331
529
      ret = sigaction(*sig, NULL, &old_action);
332
530
      if(ret == -1){
333
 
        error(0, errno, "sigaction");
334
 
        exit(EX_OSERR);
 
531
        error_plus(EX_OSERR, errno, "sigaction");
335
532
      }
336
533
      if(old_action.sa_handler != SIG_IGN){
337
534
        ret = sigaction(*sig, &new_action, NULL);
338
535
        if(ret == -1){
339
 
          error(0, errno, "sigaction");
340
 
          exit(EX_OSERR);
 
536
          error_plus(EX_OSERR, errno, "sigaction");
341
537
        }
342
538
      }
343
539
    }
344
540
  }
345
 
    
 
541
  
346
542
  /* plymouth --ping */
347
543
  bret = exec_and_wait(&plymouth_command_pid, plymouth_path,
348
 
                       (const char *[]){ (const char *)plymouth_path, (const char *)"--ping", (const char *)NULL},
 
544
                       (const char *[])
 
545
                       { plymouth_path, "--ping", NULL },
349
546
                       true, false);
350
547
  if(not bret){
351
548
    if(interrupted_by_signal){
352
549
      kill_and_wait(plymouth_command_pid);
353
 
    }
354
 
    exit(EXIT_FAILURE);
 
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);
355
558
  }
356
559
  
357
 
  prompt = makeprompt();
358
 
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
359
 
  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
  }
360
567
  if(ret == -1){
361
 
    error(0, errno, "asprintf");
362
 
    exit(EXIT_FAILURE);
 
568
    error_plus(EX_OSERR, errno, "asprintf");
363
569
  }
364
570
  
365
571
  /* plymouth ask-for-password --prompt="$prompt" */
366
 
  bret = exec_and_wait(&plymouth_command_pid, plymouth_path,
367
 
                       (const char *[]){plymouth_path, "ask-for-password", prompt_arg, NULL},
 
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 },
368
579
                       true, false);
369
580
  free(prompt_arg);
370
 
  if(not bret){
371
 
    if(interrupted_by_signal){
372
 
      kill_and_wait(plymouth_command_pid);
373
 
    } else {
374
 
      exit(EXIT_FAILURE);
375
 
    }
376
 
  }
377
 
  
378
581
  if(bret){
379
582
    exit(EXIT_SUCCESS);
380
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);
381
589
  
382
 
  const char **plymouthd_argv = NULL;
 
590
  char **plymouthd_argv = NULL;
383
591
  pid_t pid = get_pid();
384
592
  if(pid == 0){
385
 
    error(0, 0, "plymouthd pid not found");
 
593
    error_plus(0, 0, "plymouthd pid not found");
386
594
  } else {
387
595
    plymouthd_argv = getargv(pid);
388
596
  }
389
 
  if(plymouthd_argv == NULL){
390
 
    plymouthd_argv = plymouthd_default_argv;
391
 
  }
392
597
  
393
 
  bret = exec_and_wait(NULL, plymouth_path,
394
 
                       (const char *[]){plymouth_path, "quit", NULL}, false, false);
395
 
  if(not bret){
396
 
    exit(EXIT_FAILURE);
397
 
  }
398
 
  bret = exec_and_wait(NULL, plymouthd_path, plymouthd_argv, false, true);
399
 
  if(not bret){
400
 
    exit(EXIT_FAILURE);
401
 
  }
402
 
  exec_and_wait(NULL, plymouth_path,
403
 
                (const char *[]){ plymouth_path, "show-splash", NULL }, false, false);
 
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);
404
623
  exit(EXIT_FAILURE);
405
624
}