/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: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support:
Pluginbased client handler
rewritten Mandos client
       Avahi instead of udp server discovery
       openpgp encrypted key support
Passprompt stand alone application for direct console input
Added logging for Mandos server

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