/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/usplash.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-16 03:29:08 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080816032908-ihw7c05r2mnyk389
Add feature to specify custom environment variables for plugins.

* plugin-runner.c (plugin): New members "environ" and "envc" to
                            contain possible custom environment.
  (getplugin): Return NULL on failure instead of doing exit(); all
               callers changed.
  (add_to_char_array): New helper function for "add_argument" and
                       "add_environment".
  (addargument): Renamed to "add_argument".  Return bool.  Call
                 "add_to_char_array" to actually do things.
  (add_environment): New; analogous to "add_argument".
  (addcustomargument): Renamed to "add_to_argv" to avoid confusion
                       with "add_argument".
  (main): New options "--global-envs" and "--envs-for" to specify
          custom environment for plugins.  Print environment for
          plugins in debug mode.  Use asprintf instead of strcpy and
          strcat.  Use execve() for plugins with custom environments.
          Free environment for plugin when freeing plugin list.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8 -*- */
2
 
/*
3
 
 * Usplash - Read a password from usplash and output it
4
 
 * 
5
 
 * Copyright © 2008-2018, 2021-2022 Teddy Hogeborn
6
 
 * Copyright © 2008-2018, 2021-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             /* vasprintf(),
27
 
                                   program_invocation_short_name,
28
 
                                   asprintf(), TEMP_FAILURE_RETRY() */
29
 
#include <sys/types.h>          /* sig_atomic_t, pid_t, setuid(),
30
 
                                   geteuid(), setsid() */
31
 
#include <stdarg.h>             /* va_list, va_start(), vfprintf() */
32
 
#include <stdio.h>              /* vasprintf(), fprintf(), stderr,
33
 
                                   vfprintf(), asprintf() */
34
 
#include <errno.h>              /* program_invocation_short_name,
35
 
                                   errno, ENOENT, EINTR */
36
 
#include <string.h>             /* strerror(), strlen(), memcmp() */
37
 
#include <error.h>              /* error() */
38
 
#include <stdlib.h>             /* free(), getenv(), realloc(),
39
 
                                   EXIT_FAILURE, EXIT_SUCCESS,
40
 
                                   malloc(), abort() */
41
 
#include <stdbool.h>            /* bool, false, true */
42
 
#include <fcntl.h>              /* open(), O_WRONLY, O_RDONLY */
43
 
#include <stddef.h>             /* size_t, NULL */
44
 
#include <unistd.h>             /* close(), ssize_t, write(),
45
 
                                   readlink(), read(), STDOUT_FILENO,
46
 
                                   sleep(), fork(), setuid(),
47
 
                                   geteuid(), setsid(), chdir(),
48
 
                                   _exit(), dup2(), STDERR_FILENO,
49
 
                                   execv(), TEMP_FAILURE_RETRY(),
50
 
                                   pause() */
51
 
#include <dirent.h>             /* DIR, opendir(), struct dirent,
52
 
                                   readdir(), closedir() */
53
 
#include <inttypes.h>           /* intmax_t, strtoimax() */
54
 
#include <iso646.h>             /* or, not, and */
55
 
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK() */
56
 
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
57
 
#include <signal.h>             /* struct sigaction, sigemptyset(),
58
 
                                   sigaddset(), SIGINT, SIGHUP,
59
 
                                   SIGTERM, SIG_IGN, kill(), SIGKILL,
60
 
                                   SIG_DFL, raise() */
61
 
#include <argz.h>               /* argz_count(), argz_extract() */
62
 
 
63
 
sig_atomic_t interrupted_by_signal = 0;
64
 
int signal_received;
65
 
const char usplash_name[] = "/sbin/usplash";
66
 
 
67
 
/* Function to use when printing errors */
68
 
__attribute__((format (gnu_printf, 3, 4)))
69
 
void error_plus(int status, int errnum, const char *formatstring,
70
 
                ...){
71
 
  va_list ap;
72
 
  char *text;
73
 
  int ret;
74
 
  
75
 
  va_start(ap, formatstring);
76
 
  ret = vasprintf(&text, formatstring, ap);
77
 
  if(ret == -1){
78
 
    fprintf(stderr, "Mandos plugin %s: ",
79
 
            program_invocation_short_name);
80
 
    vfprintf(stderr, formatstring, ap);
81
 
    fprintf(stderr, ": ");
82
 
    fprintf(stderr, "%s\n", strerror(errnum));
83
 
    error(status, errno, "vasprintf while printing error");
84
 
    return;
85
 
  }
86
 
  fprintf(stderr, "Mandos plugin ");
87
 
  error(status, errnum, "%s", text);
88
 
  free(text);
89
 
}
90
 
 
91
 
static void termination_handler(int signum){
92
 
  if(interrupted_by_signal){
93
 
    return;
94
 
  }
95
 
  interrupted_by_signal = 1;
96
 
  signal_received = signum;
97
 
}
98
 
 
99
 
static bool usplash_write(int *fifo_fd_r,
100
 
                          const char *cmd, const char *arg){
101
 
  /* 
102
 
   * usplash_write(&fd, "TIMEOUT", "15") will write "TIMEOUT 15\0"
103
 
   * usplash_write(&fd, "PULSATE", NULL) will write "PULSATE\0"
104
 
   * SEE ALSO
105
 
   *         usplash_write(8)
106
 
   */
107
 
  int ret;
108
 
  if(*fifo_fd_r == -1){
109
 
    ret = open("/dev/.initramfs/usplash_fifo", O_WRONLY);
110
 
    if(ret == -1){
111
 
      return false;
112
 
    }
113
 
    *fifo_fd_r = ret;
114
 
  }
115
 
  
116
 
  const char *cmd_line;
117
 
  size_t cmd_line_len;
118
 
  char *cmd_line_alloc = NULL;
119
 
  if(arg == NULL){
120
 
    cmd_line = cmd;
121
 
    cmd_line_len = strlen(cmd) + 1;
122
 
  } else {
123
 
    do {
124
 
      ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg);
125
 
      if(ret == -1){
126
 
        int e = errno;
127
 
        close(*fifo_fd_r);
128
 
        errno = e;
129
 
        return false;
130
 
      }
131
 
    } while(ret == -1);
132
 
    cmd_line = cmd_line_alloc;
133
 
    cmd_line_len = (size_t)ret + 1;
134
 
  }
135
 
  
136
 
  size_t written = 0;
137
 
  ssize_t sret = 0;
138
 
  while(written < cmd_line_len){
139
 
    sret = write(*fifo_fd_r, cmd_line + written,
140
 
                 cmd_line_len - written);
141
 
    if(sret == -1){
142
 
      int e = errno;
143
 
      close(*fifo_fd_r);
144
 
      free(cmd_line_alloc);
145
 
      errno = e;
146
 
      return false;
147
 
    }
148
 
    written += (size_t)sret;
149
 
  }
150
 
  free(cmd_line_alloc);
151
 
  
152
 
  return true;
153
 
}
154
 
 
155
 
/* Create prompt string */
156
 
char *makeprompt(void){
157
 
  int ret = 0;
158
 
  char *prompt;
159
 
  const char *const cryptsource = getenv("cryptsource");
160
 
  const char *const crypttarget = getenv("crypttarget");
161
 
  const char prompt_start[] = "Enter passphrase to unlock the disk";
162
 
  
163
 
  if(cryptsource == NULL){
164
 
    if(crypttarget == NULL){
165
 
      ret = asprintf(&prompt, "%s: ", prompt_start);
166
 
    } else {
167
 
      ret = asprintf(&prompt, "%s (%s): ", prompt_start,
168
 
                     crypttarget);
169
 
    }
170
 
  } else {
171
 
    if(crypttarget == NULL){
172
 
      ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
173
 
    } else {
174
 
      ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
175
 
                     cryptsource, crypttarget);
176
 
    }
177
 
  }
178
 
  if(ret == -1){
179
 
    return NULL;
180
 
  }
181
 
  return prompt;
182
 
}
183
 
 
184
 
pid_t find_usplash(char **cmdline_r, size_t *cmdline_len_r){
185
 
  int ret = 0;
186
 
  ssize_t sret = 0;
187
 
  char *cmdline = NULL;
188
 
  size_t cmdline_len = 0;
189
 
  DIR *proc_dir = opendir("/proc");
190
 
  if(proc_dir == NULL){
191
 
    error_plus(0, errno, "opendir");
192
 
    return -1;
193
 
  }
194
 
  errno = 0;
195
 
  for(struct dirent *proc_ent = readdir(proc_dir);
196
 
      proc_ent != NULL;
197
 
      proc_ent = readdir(proc_dir)){
198
 
    pid_t pid;
199
 
    {
200
 
      intmax_t tmpmax;
201
 
      char *tmp;
202
 
      tmpmax = strtoimax(proc_ent->d_name, &tmp, 10);
203
 
      if(errno != 0 or tmp == proc_ent->d_name or *tmp != '\0'
204
 
         or tmpmax != (pid_t)tmpmax){
205
 
        /* Not a process */
206
 
        errno = 0;
207
 
        continue;
208
 
      }
209
 
      pid = (pid_t)tmpmax;
210
 
    }
211
 
    /* Find the executable name by doing readlink() on the
212
 
       /proc/<pid>/exe link */
213
 
    char exe_target[sizeof(usplash_name)];
214
 
    {
215
 
      /* create file name string */
216
 
      char *exe_link;
217
 
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
218
 
      if(ret == -1){
219
 
        error_plus(0, errno, "asprintf");
220
 
        goto fail_find_usplash;
221
 
      }
222
 
      
223
 
      /* Check that it refers to a symlink owned by root:root */
224
 
      struct stat exe_stat;
225
 
      ret = lstat(exe_link, &exe_stat);
226
 
      if(ret == -1){
227
 
        if(errno == ENOENT){
228
 
          free(exe_link);
229
 
          continue;
230
 
        }
231
 
        error_plus(0, errno, "lstat");
232
 
        free(exe_link);
233
 
        goto fail_find_usplash;
234
 
      }
235
 
      if(not S_ISLNK(exe_stat.st_mode)
236
 
         or exe_stat.st_uid != 0
237
 
         or exe_stat.st_gid != 0){
238
 
        free(exe_link);
239
 
        continue;
240
 
      }
241
 
        
242
 
      sret = readlink(exe_link, exe_target, sizeof(exe_target));
243
 
      free(exe_link);
244
 
    }
245
 
    /* Compare executable name */
246
 
    if((sret != ((ssize_t)sizeof(exe_target)-1))
247
 
       or (memcmp(usplash_name, exe_target,
248
 
                  sizeof(exe_target)-1) != 0)){
249
 
      /* Not it */
250
 
      continue;
251
 
    }
252
 
    /* Found usplash */
253
 
    /* Read and save the command line of usplash in "cmdline" */
254
 
    {
255
 
      /* Open /proc/<pid>/cmdline  */
256
 
      int cl_fd;
257
 
      {
258
 
        char *cmdline_filename;
259
 
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
260
 
                       proc_ent->d_name);
261
 
        if(ret == -1){
262
 
          error_plus(0, errno, "asprintf");
263
 
          goto fail_find_usplash;
264
 
        }
265
 
        cl_fd = open(cmdline_filename, O_RDONLY);
266
 
        free(cmdline_filename);
267
 
        if(cl_fd == -1){
268
 
          error_plus(0, errno, "open");
269
 
          goto fail_find_usplash;
270
 
        }
271
 
      }
272
 
      size_t cmdline_allocated = 0;
273
 
      char *tmp;
274
 
      const size_t blocksize = 1024;
275
 
      do {
276
 
        /* Allocate more space? */
277
 
        if(cmdline_len + blocksize > cmdline_allocated){
278
 
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
279
 
          if(tmp == NULL){
280
 
            error_plus(0, errno, "realloc");
281
 
            close(cl_fd);
282
 
            goto fail_find_usplash;
283
 
          }
284
 
          cmdline = tmp;
285
 
          cmdline_allocated += blocksize;
286
 
        }
287
 
        /* Read data */
288
 
        sret = read(cl_fd, cmdline + cmdline_len,
289
 
                    cmdline_allocated - cmdline_len);
290
 
        if(sret == -1){
291
 
          error_plus(0, errno, "read");
292
 
          close(cl_fd);
293
 
          goto fail_find_usplash;
294
 
        }
295
 
        cmdline_len += (size_t)sret;
296
 
      } while(sret != 0);
297
 
      ret = close(cl_fd);
298
 
      if(ret == -1){
299
 
        error_plus(0, errno, "close");
300
 
        goto fail_find_usplash;
301
 
      }
302
 
    }
303
 
    /* Close directory */
304
 
    ret = closedir(proc_dir);
305
 
    if(ret == -1){
306
 
      error_plus(0, errno, "closedir");
307
 
      goto fail_find_usplash;
308
 
    }
309
 
    /* Success */
310
 
    *cmdline_r = cmdline;
311
 
    *cmdline_len_r = cmdline_len;
312
 
    return pid;
313
 
  }
314
 
  
315
 
 fail_find_usplash:
316
 
  
317
 
  free(cmdline);
318
 
  if(proc_dir != NULL){
319
 
    int e = errno;
320
 
    closedir(proc_dir);
321
 
    errno = e;
322
 
  }
323
 
  return 0;
324
 
}
325
 
 
326
 
int main(__attribute__((unused))int argc,
327
 
         __attribute__((unused))char **argv){
328
 
  int ret = 0;
329
 
  ssize_t sret;
330
 
  int fifo_fd = -1;
331
 
  int outfifo_fd = -1;
332
 
  char *buf = NULL;
333
 
  size_t buf_len = 0;
334
 
  pid_t usplash_pid = -1;
335
 
  bool usplash_accessed = false;
336
 
  int status = EXIT_FAILURE;    /* Default failure exit status */
337
 
  
338
 
  char *prompt = makeprompt();
339
 
  if(prompt == NULL){
340
 
    status = EX_OSERR;
341
 
    goto failure;
342
 
  }
343
 
  
344
 
  /* Find usplash process */
345
 
  char *cmdline = NULL;
346
 
  size_t cmdline_len = 0;
347
 
  usplash_pid = find_usplash(&cmdline, &cmdline_len);
348
 
  if(usplash_pid == 0){
349
 
    status = EX_UNAVAILABLE;
350
 
    goto failure;
351
 
  }
352
 
  
353
 
  /* Set up the signal handler */
354
 
  {
355
 
    struct sigaction old_action,
356
 
      new_action = { .sa_handler = termination_handler,
357
 
                     .sa_flags = 0 };
358
 
    sigemptyset(&new_action.sa_mask);
359
 
    ret = sigaddset(&new_action.sa_mask, SIGINT);
360
 
    if(ret == -1){
361
 
      error_plus(0, errno, "sigaddset");
362
 
      status = EX_OSERR;
363
 
      goto failure;
364
 
    }
365
 
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
366
 
    if(ret == -1){
367
 
      error_plus(0, errno, "sigaddset");
368
 
      status = EX_OSERR;
369
 
      goto failure;
370
 
    }
371
 
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
372
 
    if(ret == -1){
373
 
      error_plus(0, errno, "sigaddset");
374
 
      status = EX_OSERR;
375
 
      goto failure;
376
 
    }
377
 
    ret = sigaction(SIGINT, NULL, &old_action);
378
 
    if(ret == -1){
379
 
      if(errno != EINTR){
380
 
        error_plus(0, errno, "sigaction");
381
 
        status = EX_OSERR;
382
 
      }
383
 
      goto failure;
384
 
    }
385
 
    if(old_action.sa_handler != SIG_IGN){
386
 
      ret = sigaction(SIGINT, &new_action, NULL);
387
 
      if(ret == -1){
388
 
        if(errno != EINTR){
389
 
          error_plus(0, errno, "sigaction");
390
 
          status = EX_OSERR;
391
 
        }
392
 
        goto failure;
393
 
      }
394
 
    }
395
 
    ret = sigaction(SIGHUP, NULL, &old_action);
396
 
    if(ret == -1){
397
 
      if(errno != EINTR){
398
 
        error_plus(0, errno, "sigaction");
399
 
        status = EX_OSERR;
400
 
      }
401
 
      goto failure;
402
 
    }
403
 
    if(old_action.sa_handler != SIG_IGN){
404
 
      ret = sigaction(SIGHUP, &new_action, NULL);
405
 
      if(ret == -1){
406
 
        if(errno != EINTR){
407
 
          error_plus(0, errno, "sigaction");
408
 
          status = EX_OSERR;
409
 
        }
410
 
        goto failure;
411
 
      }
412
 
    }
413
 
    ret = sigaction(SIGTERM, NULL, &old_action);
414
 
    if(ret == -1){
415
 
      if(errno != EINTR){
416
 
        error_plus(0, errno, "sigaction");
417
 
        status = EX_OSERR;
418
 
      }
419
 
      goto failure;
420
 
    }
421
 
    if(old_action.sa_handler != SIG_IGN){
422
 
      ret = sigaction(SIGTERM, &new_action, NULL);
423
 
      if(ret == -1){
424
 
        if(errno != EINTR){
425
 
          error_plus(0, errno, "sigaction");
426
 
          status = EX_OSERR;
427
 
        }
428
 
        goto failure;
429
 
      }
430
 
    }
431
 
  }
432
 
  
433
 
  usplash_accessed = true;
434
 
  /* Write command to FIFO */
435
 
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
436
 
    if(errno != EINTR){
437
 
      error_plus(0, errno, "usplash_write");
438
 
      status = EX_OSERR;
439
 
    }
440
 
    goto failure;
441
 
  }
442
 
  
443
 
  if(interrupted_by_signal){
444
 
    goto failure;
445
 
  }
446
 
  
447
 
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
448
 
    if(errno != EINTR){
449
 
      error_plus(0, errno, "usplash_write");
450
 
      status = EX_OSERR;
451
 
    }
452
 
    goto failure;
453
 
  }
454
 
  
455
 
  if(interrupted_by_signal){
456
 
    goto failure;
457
 
  }
458
 
  
459
 
  free(prompt);
460
 
  prompt = NULL;
461
 
  
462
 
  /* Read reply from usplash */
463
 
  /* Open FIFO */
464
 
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
465
 
  if(outfifo_fd == -1){
466
 
    if(errno != EINTR){
467
 
      error_plus(0, errno, "open");
468
 
      status = EX_OSERR;
469
 
    }
470
 
    goto failure;
471
 
  }
472
 
  
473
 
  if(interrupted_by_signal){
474
 
    goto failure;
475
 
  }
476
 
  
477
 
  /* Read from FIFO */
478
 
  size_t buf_allocated = 0;
479
 
  const size_t blocksize = 1024;
480
 
  do {
481
 
    /* Allocate more space */
482
 
    if(buf_len + blocksize > buf_allocated){
483
 
      char *tmp = realloc(buf, buf_allocated + blocksize);
484
 
      if(tmp == NULL){
485
 
        if(errno != EINTR){
486
 
          error_plus(0, errno, "realloc");
487
 
          status = EX_OSERR;
488
 
        }
489
 
        goto failure;
490
 
      }
491
 
      buf = tmp;
492
 
      buf_allocated += blocksize;
493
 
    }
494
 
    sret = read(outfifo_fd, buf + buf_len,
495
 
                buf_allocated - buf_len);
496
 
    if(sret == -1){
497
 
      if(errno != EINTR){
498
 
        error_plus(0, errno, "read");
499
 
        status = EX_OSERR;
500
 
      }
501
 
      close(outfifo_fd);
502
 
      goto failure;
503
 
    }
504
 
    if(interrupted_by_signal){
505
 
      break;
506
 
    }
507
 
    
508
 
    buf_len += (size_t)sret;
509
 
  } while(sret != 0);
510
 
  ret = close(outfifo_fd);
511
 
  if(ret == -1){
512
 
    if(errno != EINTR){
513
 
      error_plus(0, errno, "close");
514
 
      status = EX_OSERR;
515
 
    }
516
 
    goto failure;
517
 
  }
518
 
  outfifo_fd = -1;
519
 
  
520
 
  if(interrupted_by_signal){
521
 
    goto failure;
522
 
  }
523
 
  
524
 
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
525
 
    if(errno != EINTR){
526
 
      error_plus(0, errno, "usplash_write");
527
 
      status = EX_OSERR;
528
 
    }
529
 
    goto failure;
530
 
  }
531
 
  
532
 
  if(interrupted_by_signal){
533
 
    goto failure;
534
 
  }
535
 
  
536
 
  ret = close(fifo_fd);
537
 
  if(ret == -1){
538
 
    if(errno != EINTR){
539
 
      error_plus(0, errno, "close");
540
 
      status = EX_OSERR;
541
 
    }
542
 
    goto failure;
543
 
  }
544
 
  fifo_fd = -1;
545
 
  
546
 
  /* Print password to stdout */
547
 
  size_t written = 0;
548
 
  while(written < buf_len){
549
 
    do {
550
 
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
551
 
      if(sret == -1){
552
 
        if(errno != EINTR){
553
 
          error_plus(0, errno, "write");
554
 
          status = EX_OSERR;
555
 
        }
556
 
        goto failure;
557
 
      }
558
 
    } while(sret == -1);
559
 
    
560
 
    if(interrupted_by_signal){
561
 
      goto failure;
562
 
    }
563
 
    written += (size_t)sret;
564
 
  }
565
 
  free(buf);
566
 
  buf = NULL;
567
 
  
568
 
  if(interrupted_by_signal){
569
 
    goto failure;
570
 
  }
571
 
  
572
 
  free(cmdline);
573
 
  return EXIT_SUCCESS;
574
 
  
575
 
 failure:
576
 
  
577
 
  free(buf);
578
 
  
579
 
  free(prompt);
580
 
  
581
 
  /* If usplash was never accessed, we can stop now */
582
 
  if(not usplash_accessed){
583
 
    return status;
584
 
  }
585
 
  
586
 
  /* Close FIFO */
587
 
  if(fifo_fd != -1){
588
 
    ret = close(fifo_fd);
589
 
    if(ret == -1 and errno != EINTR){
590
 
      error_plus(0, errno, "close");
591
 
    }
592
 
    fifo_fd = -1;
593
 
  }
594
 
  
595
 
  /* Close output FIFO */
596
 
  if(outfifo_fd != -1){
597
 
    ret = close(outfifo_fd);
598
 
    if(ret == -1){
599
 
      error_plus(0, errno, "close");
600
 
    }
601
 
  }
602
 
  
603
 
  /* Create argv for new usplash*/
604
 
  char **cmdline_argv = malloc((argz_count(cmdline, cmdline_len) + 1)
605
 
                               * sizeof(char *)); /* Count args */
606
 
  if(cmdline_argv == NULL){
607
 
    error_plus(0, errno, "malloc");
608
 
    return status;
609
 
  }
610
 
  argz_extract(cmdline, cmdline_len, cmdline_argv); /* Create argv */
611
 
  
612
 
  /* Kill old usplash */
613
 
  kill(usplash_pid, SIGTERM);
614
 
  sleep(2);
615
 
  while(kill(usplash_pid, 0) == 0){
616
 
    kill(usplash_pid, SIGKILL);
617
 
    sleep(1);
618
 
  }
619
 
  
620
 
  pid_t new_usplash_pid = fork();
621
 
  if(new_usplash_pid == 0){
622
 
    /* Child; will become new usplash process */
623
 
    
624
 
    /* Make the effective user ID (root) the only user ID instead of
625
 
       the real user ID (_mandos) */
626
 
    ret = setuid(geteuid());
627
 
    if(ret == -1){
628
 
      error_plus(0, errno, "setuid");
629
 
    }
630
 
    
631
 
    setsid();
632
 
    ret = chdir("/");
633
 
    if(ret == -1){
634
 
      error_plus(0, errno, "chdir");
635
 
      _exit(EX_OSERR);
636
 
    }
637
 
/*     if(fork() != 0){ */
638
 
/*       _exit(EXIT_SUCCESS); */
639
 
/*     } */
640
 
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
641
 
    if(ret == -1){
642
 
      error_plus(0, errno, "dup2");
643
 
      _exit(EX_OSERR);
644
 
    }
645
 
    
646
 
    execv(usplash_name, cmdline_argv);
647
 
    if(not interrupted_by_signal){
648
 
      error_plus(0, errno, "execv");
649
 
    }
650
 
    free(cmdline);
651
 
    free(cmdline_argv);
652
 
    _exit(EX_OSERR);
653
 
  }
654
 
  free(cmdline);
655
 
  free(cmdline_argv);
656
 
  sleep(2);
657
 
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
658
 
    if(errno != EINTR){
659
 
      error_plus(0, errno, "usplash_write");
660
 
    }
661
 
  }
662
 
  
663
 
  /* Close FIFO (again) */
664
 
  if(fifo_fd != -1){
665
 
    ret = close(fifo_fd);
666
 
    if(ret == -1 and errno != EINTR){
667
 
      error_plus(0, errno, "close");
668
 
    }
669
 
    fifo_fd = -1;
670
 
  }
671
 
  
672
 
  if(interrupted_by_signal){
673
 
    struct sigaction signal_action = { .sa_handler = SIG_DFL };
674
 
    sigemptyset(&signal_action.sa_mask);
675
 
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
676
 
                                            &signal_action, NULL));
677
 
    if(ret == -1){
678
 
      error_plus(0, errno, "sigaction");
679
 
    }
680
 
    do {
681
 
      ret = raise(signal_received);
682
 
    } while(ret != 0 and errno == EINTR);
683
 
    if(ret != 0){
684
 
      error_plus(0, errno, "raise");
685
 
      abort();
686
 
    }
687
 
    TEMP_FAILURE_RETRY(pause());
688
 
  }
689
 
  
690
 
  return status;
691
 
}