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

  • Committer: Teddy Hogeborn
  • Date: 2008-08-29 05:53:59 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080829055359-wkdasnyxtylmnxus
* mandos.xml (EXAMPLE): Replaced all occurences of command name with
                        "&COMMANDNAME;".

* plugins.d/password-prompt.c (main): Improved some documentation
                                      strings.  Do perror() of
                                      tcgetattr() fails.  Add debug
                                      output if interrupted by signal.
                                      Loop over write() instead of
                                      using fwrite() when outputting
                                      password.  Add debug output if
                                      getline() returns 0, unless it
                                      was caused by a signal.  Add
                                      exit status code to debug
                                      output.

* plugins.d/password-prompt.xml: Changed all single quotes to double
                                 quotes for consistency.  Removed
                                 <?xml-stylesheet>.
  (ENTITY TIMESTAMP): New.  Automatically updated by Emacs time-stamp
                      by using Emacs local variables.
  (/refentry/refentryinfo/title): Changed to "Mandos Manual".
  (/refentry/refentryinfo/productname): Changed to "Mandos".
  (/refentry/refentryinfo/date): New; set to "&TIMESTAMP;".
  (/refentry/refentryinfo/copyright): Split copyright holders.
  (/refentry/refnamediv/refpurpose): Improved wording.
  (SYNOPSIS): Fix to use correct markup.  Add short options.
  (DESCRIPTION, OPTIONS): Improved wording.
  (OPTIONS): Improved wording.  Use more correct markup.  Document
             short options.
  (EXIT STATUS): Add text.
  (ENVIRONMENT): Document use of "cryptsource" and "crypttarget".
  (FILES): REMOVED.
  (BUGS): Add text.
  (EXAMPLE): Added some examples.
  (SECURITY): Added text.
  (SEE ALSO): Remove reference to mandos(8).  Add reference to
              crypttab(5).

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