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