/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: 2009-09-16 23:28:39 UTC
  • Revision ID: teddy@fukt.bsnet.se-20090916232839-3o7i8qmcdcz5j1ya
* init.d-mandos (Required-Start, Required-Stop): Bug fix: Added
                 "$syslog", thanks to Petter Reinholdtsen
                 <pere@hungry.com> (Debian bug #546928).

* initramfs-tools-script: Removed erroneous comment.

* plugins.d/askpass-fifo.c: Removed TEMP_FAILURE_RETRY since it is
                            not needed.

* plugins.d/mandos-client.c (main): Bug fix: Initialize
                                    "old_sigterm_action".

* plugins.d/splashy.c (main): Bug fix: really check return value from
                              "sigaddset".  Fix some warnings on
                              64-bit systems.

* plugins.d/usplash.c (termination_handler, main): Save received
                                                   signal and
                                                   re-raise it on
                                                   exit.
  (usplash_write): Do not close FIFO, instead, take an additional file
                   descriptor pointer to it and open only when needed
                   (all callers changed).  Abort immediately on EINTR.
                   Bug fix:  Add NUL byte on single-word commands.
                   Ignore "interrupted_by_signal".
  (makeprompt, find_usplash): New; broken out from "main()".
  (find_usplash): Bug fix: close /proc/<pid>/cmdline FD on error.
  (main): Reorganized to jump to a new "failure" label on any error.
          Bug fix: check return values from sigaddset.
          New variable "usplash_accessed" to flag if usplash(8) needs
          to be killed and restarted.  Removed the "an_error_occured"
          variable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
#include <fcntl.h>              /* open(), O_WRONLY, O_RDONLY */
32
32
#include <iso646.h>             /* and, or, not*/
33
33
#include <errno.h>              /* errno, EINTR */
34
 
#include <error.h>
35
34
#include <sys/types.h>          /* size_t, ssize_t, pid_t, DIR, struct
36
35
                                   dirent */
37
36
#include <stddef.h>             /* NULL */
38
37
#include <string.h>             /* strlen(), memcmp() */
39
 
#include <stdio.h>              /* asprintf()*/
 
38
#include <stdio.h>              /* asprintf(), perror() */
40
39
#include <unistd.h>             /* close(), write(), readlink(),
41
40
                                   read(), STDOUT_FILENO, sleep(),
42
41
                                   fork(), setuid(), geteuid(),
43
42
                                   setsid(), chdir(), dup2(),
44
43
                                   STDERR_FILENO, execv() */
45
44
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
46
 
                                   EXIT_SUCCESS, malloc(), _exit(),
47
 
                                   getenv() */
 
45
                                   EXIT_SUCCESS, malloc(), _exit() */
 
46
#include <stdlib.h>             /* getenv() */
48
47
#include <dirent.h>             /* opendir(), readdir(), closedir() */
49
48
#include <inttypes.h>           /* intmax_t, strtoimax() */
50
49
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
51
 
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
52
50
 
53
51
sig_atomic_t interrupted_by_signal = 0;
54
52
int signal_received;
154
152
  size_t cmdline_len = 0;
155
153
  DIR *proc_dir = opendir("/proc");
156
154
  if(proc_dir == NULL){
157
 
    error(0, errno, "opendir");
 
155
    perror("opendir");
158
156
    return -1;
159
157
  }
160
158
  errno = 0;
182
180
      char *exe_link;
183
181
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
184
182
      if(ret == -1){
185
 
        error(0, errno, "asprintf");
 
183
        perror("asprintf");
186
184
        goto fail_find_usplash;
187
185
      }
188
186
      
194
192
          free(exe_link);
195
193
          continue;
196
194
        }
197
 
        error(0, errno, "lstat");
 
195
        perror("lstat");
198
196
        free(exe_link);
199
197
        goto fail_find_usplash;
200
198
      }
225
223
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
226
224
                       proc_ent->d_name);
227
225
        if(ret == -1){
228
 
          error(0, errno, "asprintf");
 
226
          perror("asprintf");
229
227
          goto fail_find_usplash;
230
228
        }
231
229
        cl_fd = open(cmdline_filename, O_RDONLY);
232
230
        free(cmdline_filename);
233
231
        if(cl_fd == -1){
234
 
          error(0, errno, "open");
 
232
          perror("open");
235
233
          goto fail_find_usplash;
236
234
        }
237
235
      }
243
241
        if(cmdline_len + blocksize > cmdline_allocated){
244
242
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
245
243
          if(tmp == NULL){
246
 
            error(0, errno, "realloc");
 
244
            perror("realloc");
247
245
            close(cl_fd);
248
246
            goto fail_find_usplash;
249
247
          }
254
252
        sret = read(cl_fd, cmdline + cmdline_len,
255
253
                    cmdline_allocated - cmdline_len);
256
254
        if(sret == -1){
257
 
          error(0, errno, "read");
 
255
          perror("read");
258
256
          close(cl_fd);
259
257
          goto fail_find_usplash;
260
258
        }
262
260
      } while(sret != 0);
263
261
      ret = close(cl_fd);
264
262
      if(ret == -1){
265
 
        error(0, errno, "close");
 
263
        perror("close");
266
264
        goto fail_find_usplash;
267
265
      }
268
266
    }
269
267
    /* Close directory */
270
268
    ret = closedir(proc_dir);
271
269
    if(ret == -1){
272
 
      error(0, errno, "closedir");
 
270
      perror("closedir");
273
271
      goto fail_find_usplash;
274
272
    }
275
273
    /* Success */
299
297
  size_t buf_len = 0;
300
298
  pid_t usplash_pid = -1;
301
299
  bool usplash_accessed = false;
302
 
  int status = EXIT_FAILURE;    /* Default failure exit status */
303
300
  
304
301
  char *prompt = makeprompt();
305
302
  if(prompt == NULL){
306
 
    status = EX_OSERR;
307
303
    goto failure;
308
304
  }
309
305
  
312
308
  size_t cmdline_len = 0;
313
309
  usplash_pid = find_usplash(&cmdline, &cmdline_len);
314
310
  if(usplash_pid == 0){
315
 
    status = EX_UNAVAILABLE;
316
311
    goto failure;
317
312
  }
318
313
  
324
319
    sigemptyset(&new_action.sa_mask);
325
320
    ret = sigaddset(&new_action.sa_mask, SIGINT);
326
321
    if(ret == -1){
327
 
      error(0, errno, "sigaddset");
328
 
      status = EX_OSERR;
 
322
      perror("sigaddset");
329
323
      goto failure;
330
324
    }
331
325
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
332
326
    if(ret == -1){
333
 
      error(0, errno, "sigaddset");
334
 
      status = EX_OSERR;
 
327
      perror("sigaddset");
335
328
      goto failure;
336
329
    }
337
330
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
338
331
    if(ret == -1){
339
 
      error(0, errno, "sigaddset");
340
 
      status = EX_OSERR;
 
332
      perror("sigaddset");
341
333
      goto failure;
342
334
    }
343
335
    ret = sigaction(SIGINT, NULL, &old_action);
344
336
    if(ret == -1){
345
337
      if(errno != EINTR){
346
 
        error(0, errno, "sigaction");
347
 
        status = EX_OSERR;
 
338
        perror("sigaction");
348
339
      }
349
340
      goto failure;
350
341
    }
352
343
      ret = sigaction(SIGINT, &new_action, NULL);
353
344
      if(ret == -1){
354
345
        if(errno != EINTR){
355
 
          error(0, errno, "sigaction");
356
 
          status = EX_OSERR;
 
346
          perror("sigaction");
357
347
        }
358
348
        goto failure;
359
349
      }
361
351
    ret = sigaction(SIGHUP, NULL, &old_action);
362
352
    if(ret == -1){
363
353
      if(errno != EINTR){
364
 
        error(0, errno, "sigaction");
365
 
        status = EX_OSERR;
 
354
        perror("sigaction");
366
355
      }
367
356
      goto failure;
368
357
    }
370
359
      ret = sigaction(SIGHUP, &new_action, NULL);
371
360
      if(ret == -1){
372
361
        if(errno != EINTR){
373
 
          error(0, errno, "sigaction");
374
 
          status = EX_OSERR;
 
362
          perror("sigaction");
375
363
        }
376
364
        goto failure;
377
365
      }
379
367
    ret = sigaction(SIGTERM, NULL, &old_action);
380
368
    if(ret == -1){
381
369
      if(errno != EINTR){
382
 
        error(0, errno, "sigaction");
383
 
        status = EX_OSERR;
 
370
        perror("sigaction");
384
371
      }
385
372
      goto failure;
386
373
    }
388
375
      ret = sigaction(SIGTERM, &new_action, NULL);
389
376
      if(ret == -1){
390
377
        if(errno != EINTR){
391
 
          error(0, errno, "sigaction");
392
 
          status = EX_OSERR;
 
378
          perror("sigaction");
393
379
        }
394
380
        goto failure;
395
381
      }
400
386
  /* Write command to FIFO */
401
387
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
402
388
    if(errno != EINTR){
403
 
      error(0, errno, "usplash_write");
404
 
      status = EX_OSERR;
 
389
      perror("usplash_write");
405
390
    }
406
391
    goto failure;
407
392
  }
412
397
  
413
398
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
414
399
    if(errno != EINTR){
415
 
      error(0, errno, "usplash_write");
416
 
      status = EX_OSERR;
 
400
      perror("usplash_write");
417
401
    }
418
402
    goto failure;
419
403
  }
430
414
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
431
415
  if(outfifo_fd == -1){
432
416
    if(errno != EINTR){
433
 
      error(0, errno, "open");
434
 
      status = EX_OSERR;
 
417
      perror("open");
435
418
    }
436
419
    goto failure;
437
420
  }
449
432
      char *tmp = realloc(buf, buf_allocated + blocksize);
450
433
      if(tmp == NULL){
451
434
        if(errno != EINTR){
452
 
          error(0, errno, "realloc");
453
 
          status = EX_OSERR;
 
435
          perror("realloc");
454
436
        }
455
437
        goto failure;
456
438
      }
461
443
                buf_allocated - buf_len);
462
444
    if(sret == -1){
463
445
      if(errno != EINTR){
464
 
        error(0, errno, "read");
465
 
        status = EX_OSERR;
 
446
        perror("read");
466
447
      }
467
448
      TEMP_FAILURE_RETRY(close(outfifo_fd));
468
449
      goto failure;
476
457
  ret = close(outfifo_fd);
477
458
  if(ret == -1){
478
459
    if(errno != EINTR){
479
 
      error(0, errno, "close");
480
 
      status = EX_OSERR;
 
460
      perror("close");
481
461
    }
482
462
    goto failure;
483
463
  }
489
469
  
490
470
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
491
471
    if(errno != EINTR){
492
 
      error(0, errno, "usplash_write");
493
 
      status = EX_OSERR;
 
472
      perror("usplash_write");
494
473
    }
495
474
    goto failure;
496
475
  }
502
481
  ret = close(fifo_fd);
503
482
  if(ret == -1){
504
483
    if(errno != EINTR){
505
 
      error(0, errno, "close");
506
 
      status = EX_OSERR;
 
484
      perror("close");
507
485
    }
508
486
    goto failure;
509
487
  }
516
494
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
517
495
      if(sret == -1){
518
496
        if(errno != EINTR){
519
 
          error(0, errno, "write");
520
 
          status = EX_OSERR;
 
497
          perror("write");
521
498
        }
522
499
        goto failure;
523
500
      }
546
523
  
547
524
  /* If usplash was never accessed, we can stop now */
548
525
  if(not usplash_accessed){
549
 
    return status;
 
526
    return EXIT_FAILURE;
550
527
  }
551
528
  
552
529
  /* Close FIFO */
553
530
  if(fifo_fd != -1){
554
531
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
555
532
    if(ret == -1 and errno != EINTR){
556
 
      error(0, errno, "close");
 
533
      perror("close");
557
534
    }
558
535
    fifo_fd = -1;
559
536
  }
562
539
  if(outfifo_fd != -1){
563
540
    ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
564
541
    if(ret == -1){
565
 
      error(0, errno, "close");
 
542
      perror("close");
566
543
    }
567
544
  }
568
545
  
576
553
                           (sizeof(char *)
577
554
                            * (size_t)(cmdline_argc + 2)));
578
555
      if(tmp == NULL){
579
 
        error(0, errno, "realloc");
 
556
        perror("realloc");
580
557
        free(cmdline_argv);
581
 
        return status;
 
558
        return EXIT_FAILURE;
582
559
      }
583
560
      cmdline_argv = tmp;
584
561
      cmdline_argv[cmdline_argc] = cmdline + position;
603
580
       the real user ID (_mandos) */
604
581
    ret = setuid(geteuid());
605
582
    if(ret == -1){
606
 
      error(0, errno, "setuid");
 
583
      perror("setuid");
607
584
    }
608
585
    
609
586
    setsid();
610
587
    ret = chdir("/");
611
 
    if(ret == -1){
612
 
      error(0, errno, "chdir");
613
 
      _exit(EX_OSERR);
614
 
    }
615
588
/*     if(fork() != 0){ */
616
589
/*       _exit(EXIT_SUCCESS); */
617
590
/*     } */
618
591
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
619
592
    if(ret == -1){
620
 
      error(0, errno, "dup2");
621
 
      _exit(EX_OSERR);
 
593
      perror("dup2");
 
594
      _exit(EXIT_FAILURE);
622
595
    }
623
596
    
624
597
    execv(usplash_name, cmdline_argv);
625
598
    if(not interrupted_by_signal){
626
 
      error(0, errno, "execv");
 
599
      perror("execv");
627
600
    }
628
601
    free(cmdline);
629
602
    free(cmdline_argv);
630
 
    _exit(EX_OSERR);
 
603
    _exit(EXIT_FAILURE);
631
604
  }
632
605
  free(cmdline);
633
606
  free(cmdline_argv);
634
607
  sleep(2);
635
608
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
636
609
    if(errno != EINTR){
637
 
      error(0, errno, "usplash_write");
 
610
      perror("usplash_write");
638
611
    }
639
612
  }
640
613
  
641
614
  /* Close FIFO (again) */
642
 
  if(fifo_fd != -1){
643
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
644
 
    if(ret == -1 and errno != EINTR){
645
 
      error(0, errno, "close");
646
 
    }
647
 
    fifo_fd = -1;
 
615
  ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
 
616
  if(ret == -1 and errno != EINTR){
 
617
    perror("close");
648
618
  }
 
619
  fifo_fd = -1;
649
620
  
650
621
  if(interrupted_by_signal){
651
622
    struct sigaction signal_action = { .sa_handler = SIG_DFL };
653
624
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
654
625
                                            &signal_action, NULL));
655
626
    if(ret == -1){
656
 
      error(0, errno, "sigaction");
 
627
      perror("sigaction");
657
628
    }
658
629
    do {
659
630
      ret = raise(signal_received);
660
631
    } while(ret != 0 and errno == EINTR);
661
632
    if(ret != 0){
662
 
      error(0, errno, "raise");
 
633
      perror("raise");
663
634
      abort();
664
635
    }
665
636
    TEMP_FAILURE_RETRY(pause());
666
637
  }
667
638
  
668
 
  return status;
 
639
  return EXIT_FAILURE;
669
640
}