/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 Hogeborn
  • Date: 2024-11-17 18:43:11 UTC
  • mto: This revision was merged to the branch mainline in revision 412.
  • Revision ID: teddy@recompile.se-20241117184311-ox25kvngy62h209g
Debian package: Avoid suggesting a C compiler unnecessarily

The list of suggested packages, meant to enable the "mandos" program
to find the correct value of SO_BINDTODEVICE by using a C compiler,
are not necessary when Python 3.3 or later is used, since it has the
SO_BINDTODEVICE constant defined in the "socket" module.  Also, Python
2.6 or older has the same constant in the old "IN" module.  Therefore,
we should suggest these Python versions as alternatives to a C
compiler, so that a C compiler is not installed unnecessarily.

debian/control (Package: mandos/Suggests): Add "python3 (>= 3.3)" and
"python (<= 2.6)" as alternatives to "libc6-dev | libc-dev" and
"c-compiler".

Show diffs side-by-side

added added

removed removed

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