/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 (Standards-Version): Updated to "3.9.1".
* mandos-keygen: Use "set -e" as per Debian Policy section 10.4.

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-2017 Teddy Hogeborn
6
 
 * Copyright © 2008-2017 Björn Påhlsson
7
 
 * 
8
 
 * This file is part of Mandos.
9
 
 * 
10
 
 * Mandos is free software: you can redistribute it and/or modify it
11
 
 * under the terms of the GNU General Public License as published by
12
 
 * the Free Software Foundation, either version 3 of the License, or
13
 
 * (at your option) any later version.
14
 
 * 
15
 
 * Mandos is distributed in the hope that it will be useful, but
 
5
 * Copyright © 2008-2010 Teddy Hogeborn
 
6
 * Copyright © 2008-2010 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
16
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
17
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
16
 * General Public License for more details.
19
17
 * 
20
18
 * You should have received a copy of the GNU General Public License
21
 
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
 
19
 * along with this program.  If not, see
 
20
 * <http://www.gnu.org/licenses/>.
22
21
 * 
23
 
 * Contact the authors at <mandos@recompile.se>.
 
22
 * Contact the authors at <mandos@fukt.bsnet.se>.
24
23
 */
25
24
 
26
25
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
36
35
#include <sys/types.h>          /* size_t, ssize_t, pid_t, DIR, struct
37
36
                                   dirent */
38
37
#include <stddef.h>             /* NULL */
39
 
#include <string.h>             /* strlen(), memcmp(), strerror() */
40
 
#include <stdio.h>              /* asprintf(), vasprintf(), vprintf(),
41
 
                                   fprintf() */
 
38
#include <string.h>             /* strlen(), memcmp() */
 
39
#include <stdio.h>              /* asprintf()*/
42
40
#include <unistd.h>             /* close(), write(), readlink(),
43
41
                                   read(), STDOUT_FILENO, sleep(),
44
42
                                   fork(), setuid(), geteuid(),
52
50
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
53
51
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
54
52
#include <argz.h>               /* argz_count(), argz_extract() */
55
 
#include <stdarg.h>             /* va_list, va_start(), ... */
56
53
 
57
54
sig_atomic_t interrupted_by_signal = 0;
58
55
int signal_received;
59
56
const char usplash_name[] = "/sbin/usplash";
60
57
 
61
 
/* Function to use when printing errors */
62
 
__attribute__((format (gnu_printf, 3, 4)))
63
 
void error_plus(int status, int errnum, const char *formatstring,
64
 
                ...){
65
 
  va_list ap;
66
 
  char *text;
67
 
  int ret;
68
 
  
69
 
  va_start(ap, formatstring);
70
 
  ret = vasprintf(&text, formatstring, ap);
71
 
  if(ret == -1){
72
 
    fprintf(stderr, "Mandos plugin %s: ",
73
 
            program_invocation_short_name);
74
 
    vfprintf(stderr, formatstring, ap);
75
 
    fprintf(stderr, ": ");
76
 
    fprintf(stderr, "%s\n", strerror(errnum));
77
 
    error(status, errno, "vasprintf while printing error");
78
 
    return;
79
 
  }
80
 
  fprintf(stderr, "Mandos plugin ");
81
 
  error(status, errnum, "%s", text);
82
 
  free(text);
83
 
}
84
 
 
85
58
static void termination_handler(int signum){
86
59
  if(interrupted_by_signal){
87
60
    return;
118
91
      ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg);
119
92
      if(ret == -1){
120
93
        int e = errno;
121
 
        close(*fifo_fd_r);
 
94
        TEMP_FAILURE_RETRY(close(*fifo_fd_r));
122
95
        errno = e;
123
96
        return false;
124
97
      }
134
107
                 cmd_line_len - written);
135
108
    if(sret == -1){
136
109
      int e = errno;
137
 
      close(*fifo_fd_r);
 
110
      TEMP_FAILURE_RETRY(close(*fifo_fd_r));
138
111
      free(cmd_line_alloc);
139
112
      errno = e;
140
113
      return false;
182
155
  size_t cmdline_len = 0;
183
156
  DIR *proc_dir = opendir("/proc");
184
157
  if(proc_dir == NULL){
185
 
    error_plus(0, errno, "opendir");
 
158
    error(0, errno, "opendir");
186
159
    return -1;
187
160
  }
188
161
  errno = 0;
210
183
      char *exe_link;
211
184
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
212
185
      if(ret == -1){
213
 
        error_plus(0, errno, "asprintf");
 
186
        error(0, errno, "asprintf");
214
187
        goto fail_find_usplash;
215
188
      }
216
189
      
222
195
          free(exe_link);
223
196
          continue;
224
197
        }
225
 
        error_plus(0, errno, "lstat");
 
198
        error(0, errno, "lstat");
226
199
        free(exe_link);
227
200
        goto fail_find_usplash;
228
201
      }
253
226
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
254
227
                       proc_ent->d_name);
255
228
        if(ret == -1){
256
 
          error_plus(0, errno, "asprintf");
 
229
          error(0, errno, "asprintf");
257
230
          goto fail_find_usplash;
258
231
        }
259
232
        cl_fd = open(cmdline_filename, O_RDONLY);
260
233
        free(cmdline_filename);
261
234
        if(cl_fd == -1){
262
 
          error_plus(0, errno, "open");
 
235
          error(0, errno, "open");
263
236
          goto fail_find_usplash;
264
237
        }
265
238
      }
271
244
        if(cmdline_len + blocksize > cmdline_allocated){
272
245
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
273
246
          if(tmp == NULL){
274
 
            error_plus(0, errno, "realloc");
 
247
            error(0, errno, "realloc");
275
248
            close(cl_fd);
276
249
            goto fail_find_usplash;
277
250
          }
282
255
        sret = read(cl_fd, cmdline + cmdline_len,
283
256
                    cmdline_allocated - cmdline_len);
284
257
        if(sret == -1){
285
 
          error_plus(0, errno, "read");
 
258
          error(0, errno, "read");
286
259
          close(cl_fd);
287
260
          goto fail_find_usplash;
288
261
        }
290
263
      } while(sret != 0);
291
264
      ret = close(cl_fd);
292
265
      if(ret == -1){
293
 
        error_plus(0, errno, "close");
 
266
        error(0, errno, "close");
294
267
        goto fail_find_usplash;
295
268
      }
296
269
    }
297
270
    /* Close directory */
298
271
    ret = closedir(proc_dir);
299
272
    if(ret == -1){
300
 
      error_plus(0, errno, "closedir");
 
273
      error(0, errno, "closedir");
301
274
      goto fail_find_usplash;
302
275
    }
303
276
    /* Success */
352
325
    sigemptyset(&new_action.sa_mask);
353
326
    ret = sigaddset(&new_action.sa_mask, SIGINT);
354
327
    if(ret == -1){
355
 
      error_plus(0, errno, "sigaddset");
 
328
      error(0, errno, "sigaddset");
356
329
      status = EX_OSERR;
357
330
      goto failure;
358
331
    }
359
332
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
360
333
    if(ret == -1){
361
 
      error_plus(0, errno, "sigaddset");
 
334
      error(0, errno, "sigaddset");
362
335
      status = EX_OSERR;
363
336
      goto failure;
364
337
    }
365
338
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
366
339
    if(ret == -1){
367
 
      error_plus(0, errno, "sigaddset");
 
340
      error(0, errno, "sigaddset");
368
341
      status = EX_OSERR;
369
342
      goto failure;
370
343
    }
371
344
    ret = sigaction(SIGINT, NULL, &old_action);
372
345
    if(ret == -1){
373
346
      if(errno != EINTR){
374
 
        error_plus(0, errno, "sigaction");
 
347
        error(0, errno, "sigaction");
375
348
        status = EX_OSERR;
376
349
      }
377
350
      goto failure;
380
353
      ret = sigaction(SIGINT, &new_action, NULL);
381
354
      if(ret == -1){
382
355
        if(errno != EINTR){
383
 
          error_plus(0, errno, "sigaction");
 
356
          error(0, errno, "sigaction");
384
357
          status = EX_OSERR;
385
358
        }
386
359
        goto failure;
389
362
    ret = sigaction(SIGHUP, NULL, &old_action);
390
363
    if(ret == -1){
391
364
      if(errno != EINTR){
392
 
        error_plus(0, errno, "sigaction");
 
365
        error(0, errno, "sigaction");
393
366
        status = EX_OSERR;
394
367
      }
395
368
      goto failure;
398
371
      ret = sigaction(SIGHUP, &new_action, NULL);
399
372
      if(ret == -1){
400
373
        if(errno != EINTR){
401
 
          error_plus(0, errno, "sigaction");
 
374
          error(0, errno, "sigaction");
402
375
          status = EX_OSERR;
403
376
        }
404
377
        goto failure;
407
380
    ret = sigaction(SIGTERM, NULL, &old_action);
408
381
    if(ret == -1){
409
382
      if(errno != EINTR){
410
 
        error_plus(0, errno, "sigaction");
 
383
        error(0, errno, "sigaction");
411
384
        status = EX_OSERR;
412
385
      }
413
386
      goto failure;
416
389
      ret = sigaction(SIGTERM, &new_action, NULL);
417
390
      if(ret == -1){
418
391
        if(errno != EINTR){
419
 
          error_plus(0, errno, "sigaction");
 
392
          error(0, errno, "sigaction");
420
393
          status = EX_OSERR;
421
394
        }
422
395
        goto failure;
428
401
  /* Write command to FIFO */
429
402
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
430
403
    if(errno != EINTR){
431
 
      error_plus(0, errno, "usplash_write");
 
404
      error(0, errno, "usplash_write");
432
405
      status = EX_OSERR;
433
406
    }
434
407
    goto failure;
440
413
  
441
414
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
442
415
    if(errno != EINTR){
443
 
      error_plus(0, errno, "usplash_write");
 
416
      error(0, errno, "usplash_write");
444
417
      status = EX_OSERR;
445
418
    }
446
419
    goto failure;
458
431
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
459
432
  if(outfifo_fd == -1){
460
433
    if(errno != EINTR){
461
 
      error_plus(0, errno, "open");
 
434
      error(0, errno, "open");
462
435
      status = EX_OSERR;
463
436
    }
464
437
    goto failure;
477
450
      char *tmp = realloc(buf, buf_allocated + blocksize);
478
451
      if(tmp == NULL){
479
452
        if(errno != EINTR){
480
 
          error_plus(0, errno, "realloc");
 
453
          error(0, errno, "realloc");
481
454
          status = EX_OSERR;
482
455
        }
483
456
        goto failure;
489
462
                buf_allocated - buf_len);
490
463
    if(sret == -1){
491
464
      if(errno != EINTR){
492
 
        error_plus(0, errno, "read");
 
465
        error(0, errno, "read");
493
466
        status = EX_OSERR;
494
467
      }
495
 
      close(outfifo_fd);
 
468
      TEMP_FAILURE_RETRY(close(outfifo_fd));
496
469
      goto failure;
497
470
    }
498
471
    if(interrupted_by_signal){
504
477
  ret = close(outfifo_fd);
505
478
  if(ret == -1){
506
479
    if(errno != EINTR){
507
 
      error_plus(0, errno, "close");
 
480
      error(0, errno, "close");
508
481
      status = EX_OSERR;
509
482
    }
510
483
    goto failure;
517
490
  
518
491
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
519
492
    if(errno != EINTR){
520
 
      error_plus(0, errno, "usplash_write");
 
493
      error(0, errno, "usplash_write");
521
494
      status = EX_OSERR;
522
495
    }
523
496
    goto failure;
530
503
  ret = close(fifo_fd);
531
504
  if(ret == -1){
532
505
    if(errno != EINTR){
533
 
      error_plus(0, errno, "close");
 
506
      error(0, errno, "close");
534
507
      status = EX_OSERR;
535
508
    }
536
509
    goto failure;
544
517
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
545
518
      if(sret == -1){
546
519
        if(errno != EINTR){
547
 
          error_plus(0, errno, "write");
 
520
          error(0, errno, "write");
548
521
          status = EX_OSERR;
549
522
        }
550
523
        goto failure;
579
552
  
580
553
  /* Close FIFO */
581
554
  if(fifo_fd != -1){
582
 
    ret = close(fifo_fd);
 
555
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
583
556
    if(ret == -1 and errno != EINTR){
584
 
      error_plus(0, errno, "close");
 
557
      error(0, errno, "close");
585
558
    }
586
559
    fifo_fd = -1;
587
560
  }
588
561
  
589
562
  /* Close output FIFO */
590
563
  if(outfifo_fd != -1){
591
 
    ret = close(outfifo_fd);
 
564
    ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
592
565
    if(ret == -1){
593
 
      error_plus(0, errno, "close");
 
566
      error(0, errno, "close");
594
567
    }
595
568
  }
596
569
  
598
571
  char **cmdline_argv = malloc((argz_count(cmdline, cmdline_len) + 1)
599
572
                               * sizeof(char *)); /* Count args */
600
573
  if(cmdline_argv == NULL){
601
 
    error_plus(0, errno, "malloc");
 
574
    error(0, errno, "malloc");
602
575
    return status;
603
576
  }
604
577
  argz_extract(cmdline, cmdline_len, cmdline_argv); /* Create argv */
619
592
       the real user ID (_mandos) */
620
593
    ret = setuid(geteuid());
621
594
    if(ret == -1){
622
 
      error_plus(0, errno, "setuid");
 
595
      error(0, errno, "setuid");
623
596
    }
624
597
    
625
598
    setsid();
626
599
    ret = chdir("/");
627
600
    if(ret == -1){
628
 
      error_plus(0, errno, "chdir");
 
601
      error(0, errno, "chdir");
629
602
      _exit(EX_OSERR);
630
603
    }
631
604
/*     if(fork() != 0){ */
633
606
/*     } */
634
607
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
635
608
    if(ret == -1){
636
 
      error_plus(0, errno, "dup2");
 
609
      error(0, errno, "dup2");
637
610
      _exit(EX_OSERR);
638
611
    }
639
612
    
640
613
    execv(usplash_name, cmdline_argv);
641
614
    if(not interrupted_by_signal){
642
 
      error_plus(0, errno, "execv");
 
615
      error(0, errno, "execv");
643
616
    }
644
617
    free(cmdline);
645
618
    free(cmdline_argv);
650
623
  sleep(2);
651
624
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
652
625
    if(errno != EINTR){
653
 
      error_plus(0, errno, "usplash_write");
 
626
      error(0, errno, "usplash_write");
654
627
    }
655
628
  }
656
629
  
657
630
  /* Close FIFO (again) */
658
631
  if(fifo_fd != -1){
659
 
    ret = close(fifo_fd);
 
632
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
660
633
    if(ret == -1 and errno != EINTR){
661
 
      error_plus(0, errno, "close");
 
634
      error(0, errno, "close");
662
635
    }
663
636
    fifo_fd = -1;
664
637
  }
669
642
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
670
643
                                            &signal_action, NULL));
671
644
    if(ret == -1){
672
 
      error_plus(0, errno, "sigaction");
 
645
      error(0, errno, "sigaction");
673
646
    }
674
647
    do {
675
648
      ret = raise(signal_received);
676
649
    } while(ret != 0 and errno == EINTR);
677
650
    if(ret != 0){
678
 
      error_plus(0, errno, "raise");
 
651
      error(0, errno, "raise");
679
652
      abort();
680
653
    }
681
654
    TEMP_FAILURE_RETRY(pause());