/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: 2015-01-25 00:02:51 UTC
  • Revision ID: teddy@recompile.se-20150125000251-j2bw50gfq9smqyxe
mandos.xml (SEE ALSO): Update links.

Update link to GnuPG home page, change reference from TLS 1.1 to TLS
1.2, and change to latest RFC for using OpenPGP keys with TLS (and use
its correct title).

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,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 Björn Påhlsson
 
5
 * Copyright © 2008-2014 Teddy Hogeborn
 
6
 * Copyright © 2008-2014 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
19
19
 * along with this program.  If not, see
20
20
 * <http://www.gnu.org/licenses/>.
21
21
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
22
 * Contact the authors at <mandos@recompile.se>.
23
23
 */
24
24
 
25
25
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
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() */
39
 
#include <stdio.h>              /* asprintf()*/
 
38
#include <string.h>             /* strlen(), memcmp(), strerror() */
 
39
#include <stdio.h>              /* asprintf(), vasprintf(), vprintf(),
 
40
                                   fprintf() */
40
41
#include <unistd.h>             /* close(), write(), readlink(),
41
42
                                   read(), STDOUT_FILENO, sleep(),
42
43
                                   fork(), setuid(), geteuid(),
49
50
#include <inttypes.h>           /* intmax_t, strtoimax() */
50
51
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
51
52
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
 
53
#include <argz.h>               /* argz_count(), argz_extract() */
 
54
#include <stdarg.h>             /* va_list, va_start(), ... */
52
55
 
53
56
sig_atomic_t interrupted_by_signal = 0;
54
57
int signal_received;
55
58
const char usplash_name[] = "/sbin/usplash";
56
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
 
57
84
static void termination_handler(int signum){
58
85
  if(interrupted_by_signal){
59
86
    return;
154
181
  size_t cmdline_len = 0;
155
182
  DIR *proc_dir = opendir("/proc");
156
183
  if(proc_dir == NULL){
157
 
    error(0, errno, "opendir");
 
184
    error_plus(0, errno, "opendir");
158
185
    return -1;
159
186
  }
160
187
  errno = 0;
182
209
      char *exe_link;
183
210
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
184
211
      if(ret == -1){
185
 
        error(0, errno, "asprintf");
 
212
        error_plus(0, errno, "asprintf");
186
213
        goto fail_find_usplash;
187
214
      }
188
215
      
194
221
          free(exe_link);
195
222
          continue;
196
223
        }
197
 
        error(0, errno, "lstat");
 
224
        error_plus(0, errno, "lstat");
198
225
        free(exe_link);
199
226
        goto fail_find_usplash;
200
227
      }
225
252
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
226
253
                       proc_ent->d_name);
227
254
        if(ret == -1){
228
 
          error(0, errno, "asprintf");
 
255
          error_plus(0, errno, "asprintf");
229
256
          goto fail_find_usplash;
230
257
        }
231
258
        cl_fd = open(cmdline_filename, O_RDONLY);
232
259
        free(cmdline_filename);
233
260
        if(cl_fd == -1){
234
 
          error(0, errno, "open");
 
261
          error_plus(0, errno, "open");
235
262
          goto fail_find_usplash;
236
263
        }
237
264
      }
243
270
        if(cmdline_len + blocksize > cmdline_allocated){
244
271
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
245
272
          if(tmp == NULL){
246
 
            error(0, errno, "realloc");
 
273
            error_plus(0, errno, "realloc");
247
274
            close(cl_fd);
248
275
            goto fail_find_usplash;
249
276
          }
254
281
        sret = read(cl_fd, cmdline + cmdline_len,
255
282
                    cmdline_allocated - cmdline_len);
256
283
        if(sret == -1){
257
 
          error(0, errno, "read");
 
284
          error_plus(0, errno, "read");
258
285
          close(cl_fd);
259
286
          goto fail_find_usplash;
260
287
        }
262
289
      } while(sret != 0);
263
290
      ret = close(cl_fd);
264
291
      if(ret == -1){
265
 
        error(0, errno, "close");
 
292
        error_plus(0, errno, "close");
266
293
        goto fail_find_usplash;
267
294
      }
268
295
    }
269
296
    /* Close directory */
270
297
    ret = closedir(proc_dir);
271
298
    if(ret == -1){
272
 
      error(0, errno, "closedir");
 
299
      error_plus(0, errno, "closedir");
273
300
      goto fail_find_usplash;
274
301
    }
275
302
    /* Success */
324
351
    sigemptyset(&new_action.sa_mask);
325
352
    ret = sigaddset(&new_action.sa_mask, SIGINT);
326
353
    if(ret == -1){
327
 
      error(0, errno, "sigaddset");
 
354
      error_plus(0, errno, "sigaddset");
328
355
      status = EX_OSERR;
329
356
      goto failure;
330
357
    }
331
358
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
332
359
    if(ret == -1){
333
 
      error(0, errno, "sigaddset");
 
360
      error_plus(0, errno, "sigaddset");
334
361
      status = EX_OSERR;
335
362
      goto failure;
336
363
    }
337
364
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
338
365
    if(ret == -1){
339
 
      error(0, errno, "sigaddset");
 
366
      error_plus(0, errno, "sigaddset");
340
367
      status = EX_OSERR;
341
368
      goto failure;
342
369
    }
343
370
    ret = sigaction(SIGINT, NULL, &old_action);
344
371
    if(ret == -1){
345
372
      if(errno != EINTR){
346
 
        error(0, errno, "sigaction");
 
373
        error_plus(0, errno, "sigaction");
347
374
        status = EX_OSERR;
348
375
      }
349
376
      goto failure;
352
379
      ret = sigaction(SIGINT, &new_action, NULL);
353
380
      if(ret == -1){
354
381
        if(errno != EINTR){
355
 
          error(0, errno, "sigaction");
 
382
          error_plus(0, errno, "sigaction");
356
383
          status = EX_OSERR;
357
384
        }
358
385
        goto failure;
361
388
    ret = sigaction(SIGHUP, NULL, &old_action);
362
389
    if(ret == -1){
363
390
      if(errno != EINTR){
364
 
        error(0, errno, "sigaction");
 
391
        error_plus(0, errno, "sigaction");
365
392
        status = EX_OSERR;
366
393
      }
367
394
      goto failure;
370
397
      ret = sigaction(SIGHUP, &new_action, NULL);
371
398
      if(ret == -1){
372
399
        if(errno != EINTR){
373
 
          error(0, errno, "sigaction");
 
400
          error_plus(0, errno, "sigaction");
374
401
          status = EX_OSERR;
375
402
        }
376
403
        goto failure;
379
406
    ret = sigaction(SIGTERM, NULL, &old_action);
380
407
    if(ret == -1){
381
408
      if(errno != EINTR){
382
 
        error(0, errno, "sigaction");
 
409
        error_plus(0, errno, "sigaction");
383
410
        status = EX_OSERR;
384
411
      }
385
412
      goto failure;
388
415
      ret = sigaction(SIGTERM, &new_action, NULL);
389
416
      if(ret == -1){
390
417
        if(errno != EINTR){
391
 
          error(0, errno, "sigaction");
 
418
          error_plus(0, errno, "sigaction");
392
419
          status = EX_OSERR;
393
420
        }
394
421
        goto failure;
400
427
  /* Write command to FIFO */
401
428
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
402
429
    if(errno != EINTR){
403
 
      error(0, errno, "usplash_write");
 
430
      error_plus(0, errno, "usplash_write");
404
431
      status = EX_OSERR;
405
432
    }
406
433
    goto failure;
412
439
  
413
440
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
414
441
    if(errno != EINTR){
415
 
      error(0, errno, "usplash_write");
 
442
      error_plus(0, errno, "usplash_write");
416
443
      status = EX_OSERR;
417
444
    }
418
445
    goto failure;
430
457
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
431
458
  if(outfifo_fd == -1){
432
459
    if(errno != EINTR){
433
 
      error(0, errno, "open");
 
460
      error_plus(0, errno, "open");
434
461
      status = EX_OSERR;
435
462
    }
436
463
    goto failure;
449
476
      char *tmp = realloc(buf, buf_allocated + blocksize);
450
477
      if(tmp == NULL){
451
478
        if(errno != EINTR){
452
 
          error(0, errno, "realloc");
 
479
          error_plus(0, errno, "realloc");
453
480
          status = EX_OSERR;
454
481
        }
455
482
        goto failure;
461
488
                buf_allocated - buf_len);
462
489
    if(sret == -1){
463
490
      if(errno != EINTR){
464
 
        error(0, errno, "read");
 
491
        error_plus(0, errno, "read");
465
492
        status = EX_OSERR;
466
493
      }
467
494
      TEMP_FAILURE_RETRY(close(outfifo_fd));
476
503
  ret = close(outfifo_fd);
477
504
  if(ret == -1){
478
505
    if(errno != EINTR){
479
 
      error(0, errno, "close");
 
506
      error_plus(0, errno, "close");
480
507
      status = EX_OSERR;
481
508
    }
482
509
    goto failure;
489
516
  
490
517
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
491
518
    if(errno != EINTR){
492
 
      error(0, errno, "usplash_write");
 
519
      error_plus(0, errno, "usplash_write");
493
520
      status = EX_OSERR;
494
521
    }
495
522
    goto failure;
502
529
  ret = close(fifo_fd);
503
530
  if(ret == -1){
504
531
    if(errno != EINTR){
505
 
      error(0, errno, "close");
 
532
      error_plus(0, errno, "close");
506
533
      status = EX_OSERR;
507
534
    }
508
535
    goto failure;
516
543
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
517
544
      if(sret == -1){
518
545
        if(errno != EINTR){
519
 
          error(0, errno, "write");
 
546
          error_plus(0, errno, "write");
520
547
          status = EX_OSERR;
521
548
        }
522
549
        goto failure;
553
580
  if(fifo_fd != -1){
554
581
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
555
582
    if(ret == -1 and errno != EINTR){
556
 
      error(0, errno, "close");
 
583
      error_plus(0, errno, "close");
557
584
    }
558
585
    fifo_fd = -1;
559
586
  }
562
589
  if(outfifo_fd != -1){
563
590
    ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
564
591
    if(ret == -1){
565
 
      error(0, errno, "close");
566
 
    }
567
 
  }
568
 
  
569
 
  /* Create argc and argv for new usplash*/
570
 
  int cmdline_argc = 0;
571
 
  char **cmdline_argv = malloc(sizeof(char *));
572
 
  {
573
 
    size_t position = 0;
574
 
    while(position < cmdline_len){
575
 
      char **tmp = realloc(cmdline_argv,
576
 
                           (sizeof(char *)
577
 
                            * (size_t)(cmdline_argc + 2)));
578
 
      if(tmp == NULL){
579
 
        error(0, errno, "realloc");
580
 
        free(cmdline_argv);
581
 
        return status;
582
 
      }
583
 
      cmdline_argv = tmp;
584
 
      cmdline_argv[cmdline_argc] = cmdline + position;
585
 
      cmdline_argc++;
586
 
      position += strlen(cmdline + position) + 1;
587
 
    }
588
 
    cmdline_argv[cmdline_argc] = NULL;
589
 
  }
 
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
  
590
605
  /* Kill old usplash */
591
606
  kill(usplash_pid, SIGTERM);
592
607
  sleep(2);
603
618
       the real user ID (_mandos) */
604
619
    ret = setuid(geteuid());
605
620
    if(ret == -1){
606
 
      error(0, errno, "setuid");
 
621
      error_plus(0, errno, "setuid");
607
622
    }
608
623
    
609
624
    setsid();
610
625
    ret = chdir("/");
611
626
    if(ret == -1){
612
 
      error(0, errno, "chdir");
 
627
      error_plus(0, errno, "chdir");
613
628
      _exit(EX_OSERR);
614
629
    }
615
630
/*     if(fork() != 0){ */
617
632
/*     } */
618
633
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
619
634
    if(ret == -1){
620
 
      error(0, errno, "dup2");
 
635
      error_plus(0, errno, "dup2");
621
636
      _exit(EX_OSERR);
622
637
    }
623
638
    
624
639
    execv(usplash_name, cmdline_argv);
625
640
    if(not interrupted_by_signal){
626
 
      error(0, errno, "execv");
 
641
      error_plus(0, errno, "execv");
627
642
    }
628
643
    free(cmdline);
629
644
    free(cmdline_argv);
634
649
  sleep(2);
635
650
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
636
651
    if(errno != EINTR){
637
 
      error(0, errno, "usplash_write");
 
652
      error_plus(0, errno, "usplash_write");
638
653
    }
639
654
  }
640
655
  
642
657
  if(fifo_fd != -1){
643
658
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
644
659
    if(ret == -1 and errno != EINTR){
645
 
      error(0, errno, "close");
 
660
      error_plus(0, errno, "close");
646
661
    }
647
662
    fifo_fd = -1;
648
663
  }
653
668
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
654
669
                                            &signal_action, NULL));
655
670
    if(ret == -1){
656
 
      error(0, errno, "sigaction");
 
671
      error_plus(0, errno, "sigaction");
657
672
    }
658
673
    do {
659
674
      ret = raise(signal_received);
660
675
    } while(ret != 0 and errno == EINTR);
661
676
    if(ret != 0){
662
 
      error(0, errno, "raise");
 
677
      error_plus(0, errno, "raise");
663
678
      abort();
664
679
    }
665
680
    TEMP_FAILURE_RETRY(pause());