/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

merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Usplash - Read a password from usplash and output it
4
4
 * 
5
 
 * Copyright © 2008-2011 Teddy Hogeborn
6
 
 * Copyright © 2008-2011 Björn Påhlsson
 
5
 * Copyright © 2008-2010 Teddy Hogeborn
 
6
 * Copyright © 2008-2010 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
35
35
#include <sys/types.h>          /* size_t, ssize_t, pid_t, DIR, struct
36
36
                                   dirent */
37
37
#include <stddef.h>             /* NULL */
38
 
#include <string.h>             /* strlen(), memcmp(), strerror() */
39
 
#include <stdio.h>              /* asprintf(), vasprintf(), vprintf(),
40
 
                                   fprintf() */
 
38
#include <string.h>             /* strlen(), memcmp() */
 
39
#include <stdio.h>              /* asprintf()*/
41
40
#include <unistd.h>             /* close(), write(), readlink(),
42
41
                                   read(), STDOUT_FILENO, sleep(),
43
42
                                   fork(), setuid(), geteuid(),
51
50
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
52
51
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
53
52
#include <argz.h>               /* argz_count(), argz_extract() */
54
 
#include <stdarg.h>             /* va_list, va_start(), ... */
55
53
 
56
54
sig_atomic_t interrupted_by_signal = 0;
57
55
int signal_received;
58
56
const char usplash_name[] = "/sbin/usplash";
59
57
 
60
 
/* Function to use when printing errors */
61
 
void error_plus(int status, int errnum, const char *formatstring,
62
 
                ...){
63
 
  va_list ap;
64
 
  char *text;
65
 
  int ret;
66
 
  
67
 
  va_start(ap, formatstring);
68
 
  ret = vasprintf(&text, formatstring, ap);
69
 
  if (ret == -1){
70
 
    fprintf(stderr, "Mandos plugin %s: ",
71
 
            program_invocation_short_name);
72
 
    vfprintf(stderr, formatstring, ap);
73
 
    fprintf(stderr, ": ");
74
 
    fprintf(stderr, "%s\n", strerror(errnum));
75
 
    error(status, errno, "vasprintf while printing error");
76
 
    return;
77
 
  }
78
 
  fprintf(stderr, "Mandos plugin ");
79
 
  error(status, errnum, "%s", text);
80
 
  free(text);
81
 
}
82
 
 
83
58
static void termination_handler(int signum){
84
59
  if(interrupted_by_signal){
85
60
    return;
180
155
  size_t cmdline_len = 0;
181
156
  DIR *proc_dir = opendir("/proc");
182
157
  if(proc_dir == NULL){
183
 
    error_plus(0, errno, "opendir");
 
158
    error(0, errno, "opendir");
184
159
    return -1;
185
160
  }
186
161
  errno = 0;
208
183
      char *exe_link;
209
184
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
210
185
      if(ret == -1){
211
 
        error_plus(0, errno, "asprintf");
 
186
        error(0, errno, "asprintf");
212
187
        goto fail_find_usplash;
213
188
      }
214
189
      
220
195
          free(exe_link);
221
196
          continue;
222
197
        }
223
 
        error_plus(0, errno, "lstat");
 
198
        error(0, errno, "lstat");
224
199
        free(exe_link);
225
200
        goto fail_find_usplash;
226
201
      }
251
226
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
252
227
                       proc_ent->d_name);
253
228
        if(ret == -1){
254
 
          error_plus(0, errno, "asprintf");
 
229
          error(0, errno, "asprintf");
255
230
          goto fail_find_usplash;
256
231
        }
257
232
        cl_fd = open(cmdline_filename, O_RDONLY);
258
233
        free(cmdline_filename);
259
234
        if(cl_fd == -1){
260
 
          error_plus(0, errno, "open");
 
235
          error(0, errno, "open");
261
236
          goto fail_find_usplash;
262
237
        }
263
238
      }
269
244
        if(cmdline_len + blocksize > cmdline_allocated){
270
245
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
271
246
          if(tmp == NULL){
272
 
            error_plus(0, errno, "realloc");
 
247
            error(0, errno, "realloc");
273
248
            close(cl_fd);
274
249
            goto fail_find_usplash;
275
250
          }
280
255
        sret = read(cl_fd, cmdline + cmdline_len,
281
256
                    cmdline_allocated - cmdline_len);
282
257
        if(sret == -1){
283
 
          error_plus(0, errno, "read");
 
258
          error(0, errno, "read");
284
259
          close(cl_fd);
285
260
          goto fail_find_usplash;
286
261
        }
288
263
      } while(sret != 0);
289
264
      ret = close(cl_fd);
290
265
      if(ret == -1){
291
 
        error_plus(0, errno, "close");
 
266
        error(0, errno, "close");
292
267
        goto fail_find_usplash;
293
268
      }
294
269
    }
295
270
    /* Close directory */
296
271
    ret = closedir(proc_dir);
297
272
    if(ret == -1){
298
 
      error_plus(0, errno, "closedir");
 
273
      error(0, errno, "closedir");
299
274
      goto fail_find_usplash;
300
275
    }
301
276
    /* Success */
350
325
    sigemptyset(&new_action.sa_mask);
351
326
    ret = sigaddset(&new_action.sa_mask, SIGINT);
352
327
    if(ret == -1){
353
 
      error_plus(0, errno, "sigaddset");
 
328
      error(0, errno, "sigaddset");
354
329
      status = EX_OSERR;
355
330
      goto failure;
356
331
    }
357
332
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
358
333
    if(ret == -1){
359
 
      error_plus(0, errno, "sigaddset");
 
334
      error(0, errno, "sigaddset");
360
335
      status = EX_OSERR;
361
336
      goto failure;
362
337
    }
363
338
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
364
339
    if(ret == -1){
365
 
      error_plus(0, errno, "sigaddset");
 
340
      error(0, errno, "sigaddset");
366
341
      status = EX_OSERR;
367
342
      goto failure;
368
343
    }
369
344
    ret = sigaction(SIGINT, NULL, &old_action);
370
345
    if(ret == -1){
371
346
      if(errno != EINTR){
372
 
        error_plus(0, errno, "sigaction");
 
347
        error(0, errno, "sigaction");
373
348
        status = EX_OSERR;
374
349
      }
375
350
      goto failure;
378
353
      ret = sigaction(SIGINT, &new_action, NULL);
379
354
      if(ret == -1){
380
355
        if(errno != EINTR){
381
 
          error_plus(0, errno, "sigaction");
 
356
          error(0, errno, "sigaction");
382
357
          status = EX_OSERR;
383
358
        }
384
359
        goto failure;
387
362
    ret = sigaction(SIGHUP, NULL, &old_action);
388
363
    if(ret == -1){
389
364
      if(errno != EINTR){
390
 
        error_plus(0, errno, "sigaction");
 
365
        error(0, errno, "sigaction");
391
366
        status = EX_OSERR;
392
367
      }
393
368
      goto failure;
396
371
      ret = sigaction(SIGHUP, &new_action, NULL);
397
372
      if(ret == -1){
398
373
        if(errno != EINTR){
399
 
          error_plus(0, errno, "sigaction");
 
374
          error(0, errno, "sigaction");
400
375
          status = EX_OSERR;
401
376
        }
402
377
        goto failure;
405
380
    ret = sigaction(SIGTERM, NULL, &old_action);
406
381
    if(ret == -1){
407
382
      if(errno != EINTR){
408
 
        error_plus(0, errno, "sigaction");
 
383
        error(0, errno, "sigaction");
409
384
        status = EX_OSERR;
410
385
      }
411
386
      goto failure;
414
389
      ret = sigaction(SIGTERM, &new_action, NULL);
415
390
      if(ret == -1){
416
391
        if(errno != EINTR){
417
 
          error_plus(0, errno, "sigaction");
 
392
          error(0, errno, "sigaction");
418
393
          status = EX_OSERR;
419
394
        }
420
395
        goto failure;
426
401
  /* Write command to FIFO */
427
402
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
428
403
    if(errno != EINTR){
429
 
      error_plus(0, errno, "usplash_write");
 
404
      error(0, errno, "usplash_write");
430
405
      status = EX_OSERR;
431
406
    }
432
407
    goto failure;
438
413
  
439
414
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
440
415
    if(errno != EINTR){
441
 
      error_plus(0, errno, "usplash_write");
 
416
      error(0, errno, "usplash_write");
442
417
      status = EX_OSERR;
443
418
    }
444
419
    goto failure;
456
431
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
457
432
  if(outfifo_fd == -1){
458
433
    if(errno != EINTR){
459
 
      error_plus(0, errno, "open");
 
434
      error(0, errno, "open");
460
435
      status = EX_OSERR;
461
436
    }
462
437
    goto failure;
475
450
      char *tmp = realloc(buf, buf_allocated + blocksize);
476
451
      if(tmp == NULL){
477
452
        if(errno != EINTR){
478
 
          error_plus(0, errno, "realloc");
 
453
          error(0, errno, "realloc");
479
454
          status = EX_OSERR;
480
455
        }
481
456
        goto failure;
487
462
                buf_allocated - buf_len);
488
463
    if(sret == -1){
489
464
      if(errno != EINTR){
490
 
        error_plus(0, errno, "read");
 
465
        error(0, errno, "read");
491
466
        status = EX_OSERR;
492
467
      }
493
468
      TEMP_FAILURE_RETRY(close(outfifo_fd));
502
477
  ret = close(outfifo_fd);
503
478
  if(ret == -1){
504
479
    if(errno != EINTR){
505
 
      error_plus(0, errno, "close");
 
480
      error(0, errno, "close");
506
481
      status = EX_OSERR;
507
482
    }
508
483
    goto failure;
515
490
  
516
491
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
517
492
    if(errno != EINTR){
518
 
      error_plus(0, errno, "usplash_write");
 
493
      error(0, errno, "usplash_write");
519
494
      status = EX_OSERR;
520
495
    }
521
496
    goto failure;
528
503
  ret = close(fifo_fd);
529
504
  if(ret == -1){
530
505
    if(errno != EINTR){
531
 
      error_plus(0, errno, "close");
 
506
      error(0, errno, "close");
532
507
      status = EX_OSERR;
533
508
    }
534
509
    goto failure;
542
517
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
543
518
      if(sret == -1){
544
519
        if(errno != EINTR){
545
 
          error_plus(0, errno, "write");
 
520
          error(0, errno, "write");
546
521
          status = EX_OSERR;
547
522
        }
548
523
        goto failure;
579
554
  if(fifo_fd != -1){
580
555
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
581
556
    if(ret == -1 and errno != EINTR){
582
 
      error_plus(0, errno, "close");
 
557
      error(0, errno, "close");
583
558
    }
584
559
    fifo_fd = -1;
585
560
  }
588
563
  if(outfifo_fd != -1){
589
564
    ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
590
565
    if(ret == -1){
591
 
      error_plus(0, errno, "close");
 
566
      error(0, errno, "close");
592
567
    }
593
568
  }
594
569
  
596
571
  char **cmdline_argv = malloc((argz_count(cmdline, cmdline_len) + 1)
597
572
                               * sizeof(char *)); /* Count args */
598
573
  if(cmdline_argv == NULL){
599
 
    error_plus(0, errno, "malloc");
 
574
    error(0, errno, "malloc");
600
575
    return status;
601
576
  }
602
577
  argz_extract(cmdline, cmdline_len, cmdline_argv); /* Create argv */
617
592
       the real user ID (_mandos) */
618
593
    ret = setuid(geteuid());
619
594
    if(ret == -1){
620
 
      error_plus(0, errno, "setuid");
 
595
      error(0, errno, "setuid");
621
596
    }
622
597
    
623
598
    setsid();
624
599
    ret = chdir("/");
625
600
    if(ret == -1){
626
 
      error_plus(0, errno, "chdir");
 
601
      error(0, errno, "chdir");
627
602
      _exit(EX_OSERR);
628
603
    }
629
604
/*     if(fork() != 0){ */
631
606
/*     } */
632
607
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
633
608
    if(ret == -1){
634
 
      error_plus(0, errno, "dup2");
 
609
      error(0, errno, "dup2");
635
610
      _exit(EX_OSERR);
636
611
    }
637
612
    
638
613
    execv(usplash_name, cmdline_argv);
639
614
    if(not interrupted_by_signal){
640
 
      error_plus(0, errno, "execv");
 
615
      error(0, errno, "execv");
641
616
    }
642
617
    free(cmdline);
643
618
    free(cmdline_argv);
648
623
  sleep(2);
649
624
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
650
625
    if(errno != EINTR){
651
 
      error_plus(0, errno, "usplash_write");
 
626
      error(0, errno, "usplash_write");
652
627
    }
653
628
  }
654
629
  
656
631
  if(fifo_fd != -1){
657
632
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
658
633
    if(ret == -1 and errno != EINTR){
659
 
      error_plus(0, errno, "close");
 
634
      error(0, errno, "close");
660
635
    }
661
636
    fifo_fd = -1;
662
637
  }
667
642
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
668
643
                                            &signal_action, NULL));
669
644
    if(ret == -1){
670
 
      error_plus(0, errno, "sigaction");
 
645
      error(0, errno, "sigaction");
671
646
    }
672
647
    do {
673
648
      ret = raise(signal_received);
674
649
    } while(ret != 0 and errno == EINTR);
675
650
    if(ret != 0){
676
 
      error_plus(0, errno, "raise");
 
651
      error(0, errno, "raise");
677
652
      abort();
678
653
    }
679
654
    TEMP_FAILURE_RETRY(pause());