/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

* debian/control (mandos-client): Conflict with correct version of
                                  dropbear.

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