/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

  • Committer: Teddy Hogeborn
  • Date: 2019-07-29 16:35:53 UTC
  • mto: This revision was merged to the branch mainline in revision 384.
  • Revision ID: teddy@recompile.se-20190729163553-1i442i2cbx64c537
Make tests and man page examples match

Make the tests test_manual_page_example[1-5] match exactly what is
written in the manual page, and add comments to manual page as
reminders to keep tests and manual page examples in sync.

* mandos-ctl (Test_commands_from_options.test_manual_page_example_1):
  Remove "--verbose" option, since the manual does not have it as the
  first example, and change assertion to match.
* mandos-ctl.xml (EXAMPLE): Add comments to all examples documenting
  which test function they correspond to.  Also remove unnecessary
  quotes from option arguments in fourth example, and clarify language
  slightly in fifth example.

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
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
 
5
 * Copyright © 2008-2018 Teddy Hogeborn
 
6
 * Copyright © 2008-2018 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
14
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
18
 * General Public License for more details.
17
19
 * 
18
20
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program.  If not, see
20
 
 * <http://www.gnu.org/licenses/>.
 
21
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
21
22
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
23
 * Contact the authors at <mandos@recompile.se>.
23
24
 */
24
25
 
25
26
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
31
32
#include <fcntl.h>              /* open(), O_WRONLY, O_RDONLY */
32
33
#include <iso646.h>             /* and, or, not*/
33
34
#include <errno.h>              /* errno, EINTR */
 
35
#include <error.h>
34
36
#include <sys/types.h>          /* size_t, ssize_t, pid_t, DIR, struct
35
37
                                   dirent */
36
38
#include <stddef.h>             /* NULL */
37
 
#include <string.h>             /* strlen(), memcmp() */
38
 
#include <stdio.h>              /* asprintf(), perror() */
 
39
#include <string.h>             /* strlen(), memcmp(), strerror() */
 
40
#include <stdio.h>              /* asprintf(), vasprintf(), vprintf(),
 
41
                                   fprintf() */
39
42
#include <unistd.h>             /* close(), write(), readlink(),
40
43
                                   read(), STDOUT_FILENO, sleep(),
41
44
                                   fork(), setuid(), geteuid(),
42
45
                                   setsid(), chdir(), dup2(),
43
46
                                   STDERR_FILENO, execv() */
44
47
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
45
 
                                   EXIT_SUCCESS, malloc(), _exit() */
46
 
#include <stdlib.h>             /* getenv() */
 
48
                                   EXIT_SUCCESS, malloc(), _exit(),
 
49
                                   getenv() */
47
50
#include <dirent.h>             /* opendir(), readdir(), closedir() */
48
51
#include <inttypes.h>           /* intmax_t, strtoimax() */
49
52
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
 
53
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
 
54
#include <argz.h>               /* argz_count(), argz_extract() */
 
55
#include <stdarg.h>             /* va_list, va_start(), ... */
50
56
 
51
57
sig_atomic_t interrupted_by_signal = 0;
52
58
int signal_received;
53
59
const char usplash_name[] = "/sbin/usplash";
54
60
 
 
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
 
55
85
static void termination_handler(int signum){
56
86
  if(interrupted_by_signal){
57
87
    return;
88
118
      ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg);
89
119
      if(ret == -1){
90
120
        int e = errno;
91
 
        TEMP_FAILURE_RETRY(close(*fifo_fd_r));
 
121
        close(*fifo_fd_r);
92
122
        errno = e;
93
123
        return false;
94
124
      }
104
134
                 cmd_line_len - written);
105
135
    if(sret == -1){
106
136
      int e = errno;
107
 
      TEMP_FAILURE_RETRY(close(*fifo_fd_r));
 
137
      close(*fifo_fd_r);
108
138
      free(cmd_line_alloc);
109
139
      errno = e;
110
140
      return false;
152
182
  size_t cmdline_len = 0;
153
183
  DIR *proc_dir = opendir("/proc");
154
184
  if(proc_dir == NULL){
155
 
    perror("opendir");
 
185
    error_plus(0, errno, "opendir");
156
186
    return -1;
157
187
  }
158
188
  errno = 0;
180
210
      char *exe_link;
181
211
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
182
212
      if(ret == -1){
183
 
        perror("asprintf");
 
213
        error_plus(0, errno, "asprintf");
184
214
        goto fail_find_usplash;
185
215
      }
186
216
      
192
222
          free(exe_link);
193
223
          continue;
194
224
        }
195
 
        perror("lstat");
 
225
        error_plus(0, errno, "lstat");
196
226
        free(exe_link);
197
227
        goto fail_find_usplash;
198
228
      }
223
253
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
224
254
                       proc_ent->d_name);
225
255
        if(ret == -1){
226
 
          perror("asprintf");
 
256
          error_plus(0, errno, "asprintf");
227
257
          goto fail_find_usplash;
228
258
        }
229
259
        cl_fd = open(cmdline_filename, O_RDONLY);
230
260
        free(cmdline_filename);
231
261
        if(cl_fd == -1){
232
 
          perror("open");
 
262
          error_plus(0, errno, "open");
233
263
          goto fail_find_usplash;
234
264
        }
235
265
      }
241
271
        if(cmdline_len + blocksize > cmdline_allocated){
242
272
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
243
273
          if(tmp == NULL){
244
 
            perror("realloc");
 
274
            error_plus(0, errno, "realloc");
245
275
            close(cl_fd);
246
276
            goto fail_find_usplash;
247
277
          }
252
282
        sret = read(cl_fd, cmdline + cmdline_len,
253
283
                    cmdline_allocated - cmdline_len);
254
284
        if(sret == -1){
255
 
          perror("read");
 
285
          error_plus(0, errno, "read");
256
286
          close(cl_fd);
257
287
          goto fail_find_usplash;
258
288
        }
260
290
      } while(sret != 0);
261
291
      ret = close(cl_fd);
262
292
      if(ret == -1){
263
 
        perror("close");
 
293
        error_plus(0, errno, "close");
264
294
        goto fail_find_usplash;
265
295
      }
266
296
    }
267
297
    /* Close directory */
268
298
    ret = closedir(proc_dir);
269
299
    if(ret == -1){
270
 
      perror("closedir");
 
300
      error_plus(0, errno, "closedir");
271
301
      goto fail_find_usplash;
272
302
    }
273
303
    /* Success */
297
327
  size_t buf_len = 0;
298
328
  pid_t usplash_pid = -1;
299
329
  bool usplash_accessed = false;
 
330
  int status = EXIT_FAILURE;    /* Default failure exit status */
300
331
  
301
332
  char *prompt = makeprompt();
302
333
  if(prompt == NULL){
 
334
    status = EX_OSERR;
303
335
    goto failure;
304
336
  }
305
337
  
308
340
  size_t cmdline_len = 0;
309
341
  usplash_pid = find_usplash(&cmdline, &cmdline_len);
310
342
  if(usplash_pid == 0){
 
343
    status = EX_UNAVAILABLE;
311
344
    goto failure;
312
345
  }
313
346
  
319
352
    sigemptyset(&new_action.sa_mask);
320
353
    ret = sigaddset(&new_action.sa_mask, SIGINT);
321
354
    if(ret == -1){
322
 
      perror("sigaddset");
 
355
      error_plus(0, errno, "sigaddset");
 
356
      status = EX_OSERR;
323
357
      goto failure;
324
358
    }
325
359
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
326
360
    if(ret == -1){
327
 
      perror("sigaddset");
 
361
      error_plus(0, errno, "sigaddset");
 
362
      status = EX_OSERR;
328
363
      goto failure;
329
364
    }
330
365
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
331
366
    if(ret == -1){
332
 
      perror("sigaddset");
 
367
      error_plus(0, errno, "sigaddset");
 
368
      status = EX_OSERR;
333
369
      goto failure;
334
370
    }
335
371
    ret = sigaction(SIGINT, NULL, &old_action);
336
372
    if(ret == -1){
337
373
      if(errno != EINTR){
338
 
        perror("sigaction");
 
374
        error_plus(0, errno, "sigaction");
 
375
        status = EX_OSERR;
339
376
      }
340
377
      goto failure;
341
378
    }
343
380
      ret = sigaction(SIGINT, &new_action, NULL);
344
381
      if(ret == -1){
345
382
        if(errno != EINTR){
346
 
          perror("sigaction");
 
383
          error_plus(0, errno, "sigaction");
 
384
          status = EX_OSERR;
347
385
        }
348
386
        goto failure;
349
387
      }
351
389
    ret = sigaction(SIGHUP, NULL, &old_action);
352
390
    if(ret == -1){
353
391
      if(errno != EINTR){
354
 
        perror("sigaction");
 
392
        error_plus(0, errno, "sigaction");
 
393
        status = EX_OSERR;
355
394
      }
356
395
      goto failure;
357
396
    }
359
398
      ret = sigaction(SIGHUP, &new_action, NULL);
360
399
      if(ret == -1){
361
400
        if(errno != EINTR){
362
 
          perror("sigaction");
 
401
          error_plus(0, errno, "sigaction");
 
402
          status = EX_OSERR;
363
403
        }
364
404
        goto failure;
365
405
      }
367
407
    ret = sigaction(SIGTERM, NULL, &old_action);
368
408
    if(ret == -1){
369
409
      if(errno != EINTR){
370
 
        perror("sigaction");
 
410
        error_plus(0, errno, "sigaction");
 
411
        status = EX_OSERR;
371
412
      }
372
413
      goto failure;
373
414
    }
375
416
      ret = sigaction(SIGTERM, &new_action, NULL);
376
417
      if(ret == -1){
377
418
        if(errno != EINTR){
378
 
          perror("sigaction");
 
419
          error_plus(0, errno, "sigaction");
 
420
          status = EX_OSERR;
379
421
        }
380
422
        goto failure;
381
423
      }
386
428
  /* Write command to FIFO */
387
429
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
388
430
    if(errno != EINTR){
389
 
      perror("usplash_write");
 
431
      error_plus(0, errno, "usplash_write");
 
432
      status = EX_OSERR;
390
433
    }
391
434
    goto failure;
392
435
  }
397
440
  
398
441
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
399
442
    if(errno != EINTR){
400
 
      perror("usplash_write");
 
443
      error_plus(0, errno, "usplash_write");
 
444
      status = EX_OSERR;
401
445
    }
402
446
    goto failure;
403
447
  }
414
458
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
415
459
  if(outfifo_fd == -1){
416
460
    if(errno != EINTR){
417
 
      perror("open");
 
461
      error_plus(0, errno, "open");
 
462
      status = EX_OSERR;
418
463
    }
419
464
    goto failure;
420
465
  }
432
477
      char *tmp = realloc(buf, buf_allocated + blocksize);
433
478
      if(tmp == NULL){
434
479
        if(errno != EINTR){
435
 
          perror("realloc");
 
480
          error_plus(0, errno, "realloc");
 
481
          status = EX_OSERR;
436
482
        }
437
483
        goto failure;
438
484
      }
443
489
                buf_allocated - buf_len);
444
490
    if(sret == -1){
445
491
      if(errno != EINTR){
446
 
        perror("read");
 
492
        error_plus(0, errno, "read");
 
493
        status = EX_OSERR;
447
494
      }
448
 
      TEMP_FAILURE_RETRY(close(outfifo_fd));
 
495
      close(outfifo_fd);
449
496
      goto failure;
450
497
    }
451
498
    if(interrupted_by_signal){
457
504
  ret = close(outfifo_fd);
458
505
  if(ret == -1){
459
506
    if(errno != EINTR){
460
 
      perror("close");
 
507
      error_plus(0, errno, "close");
 
508
      status = EX_OSERR;
461
509
    }
462
510
    goto failure;
463
511
  }
469
517
  
470
518
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
471
519
    if(errno != EINTR){
472
 
      perror("usplash_write");
 
520
      error_plus(0, errno, "usplash_write");
 
521
      status = EX_OSERR;
473
522
    }
474
523
    goto failure;
475
524
  }
481
530
  ret = close(fifo_fd);
482
531
  if(ret == -1){
483
532
    if(errno != EINTR){
484
 
      perror("close");
 
533
      error_plus(0, errno, "close");
 
534
      status = EX_OSERR;
485
535
    }
486
536
    goto failure;
487
537
  }
494
544
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
495
545
      if(sret == -1){
496
546
        if(errno != EINTR){
497
 
          perror("write");
 
547
          error_plus(0, errno, "write");
 
548
          status = EX_OSERR;
498
549
        }
499
550
        goto failure;
500
551
      }
523
574
  
524
575
  /* If usplash was never accessed, we can stop now */
525
576
  if(not usplash_accessed){
526
 
    return EXIT_FAILURE;
 
577
    return status;
527
578
  }
528
579
  
529
580
  /* Close FIFO */
530
581
  if(fifo_fd != -1){
531
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
 
582
    ret = close(fifo_fd);
532
583
    if(ret == -1 and errno != EINTR){
533
 
      perror("close");
 
584
      error_plus(0, errno, "close");
534
585
    }
535
586
    fifo_fd = -1;
536
587
  }
537
588
  
538
589
  /* Close output FIFO */
539
590
  if(outfifo_fd != -1){
540
 
    ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
 
591
    ret = close(outfifo_fd);
541
592
    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
 
  }
 
593
      error_plus(0, errno, "close");
 
594
    }
 
595
  }
 
596
  
 
597
  /* Create argv for new usplash*/
 
598
  char **cmdline_argv = malloc((argz_count(cmdline, cmdline_len) + 1)
 
599
                               * sizeof(char *)); /* Count args */
 
600
  if(cmdline_argv == NULL){
 
601
    error_plus(0, errno, "malloc");
 
602
    return status;
 
603
  }
 
604
  argz_extract(cmdline, cmdline_len, cmdline_argv); /* Create argv */
 
605
  
567
606
  /* Kill old usplash */
568
607
  kill(usplash_pid, SIGTERM);
569
608
  sleep(2);
580
619
       the real user ID (_mandos) */
581
620
    ret = setuid(geteuid());
582
621
    if(ret == -1){
583
 
      perror("setuid");
 
622
      error_plus(0, errno, "setuid");
584
623
    }
585
624
    
586
625
    setsid();
587
626
    ret = chdir("/");
 
627
    if(ret == -1){
 
628
      error_plus(0, errno, "chdir");
 
629
      _exit(EX_OSERR);
 
630
    }
588
631
/*     if(fork() != 0){ */
589
632
/*       _exit(EXIT_SUCCESS); */
590
633
/*     } */
591
634
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
592
635
    if(ret == -1){
593
 
      perror("dup2");
594
 
      _exit(EXIT_FAILURE);
 
636
      error_plus(0, errno, "dup2");
 
637
      _exit(EX_OSERR);
595
638
    }
596
639
    
597
640
    execv(usplash_name, cmdline_argv);
598
641
    if(not interrupted_by_signal){
599
 
      perror("execv");
 
642
      error_plus(0, errno, "execv");
600
643
    }
601
644
    free(cmdline);
602
645
    free(cmdline_argv);
603
 
    _exit(EXIT_FAILURE);
 
646
    _exit(EX_OSERR);
604
647
  }
605
648
  free(cmdline);
606
649
  free(cmdline_argv);
607
650
  sleep(2);
608
651
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
609
652
    if(errno != EINTR){
610
 
      perror("usplash_write");
 
653
      error_plus(0, errno, "usplash_write");
611
654
    }
612
655
  }
613
656
  
614
657
  /* Close FIFO (again) */
615
 
  ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
616
 
  if(ret == -1 and errno != EINTR){
617
 
    perror("close");
 
658
  if(fifo_fd != -1){
 
659
    ret = close(fifo_fd);
 
660
    if(ret == -1 and errno != EINTR){
 
661
      error_plus(0, errno, "close");
 
662
    }
 
663
    fifo_fd = -1;
618
664
  }
619
 
  fifo_fd = -1;
620
665
  
621
666
  if(interrupted_by_signal){
622
667
    struct sigaction signal_action = { .sa_handler = SIG_DFL };
624
669
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
625
670
                                            &signal_action, NULL));
626
671
    if(ret == -1){
627
 
      perror("sigaction");
 
672
      error_plus(0, errno, "sigaction");
628
673
    }
629
674
    do {
630
675
      ret = raise(signal_received);
631
676
    } while(ret != 0 and errno == EINTR);
632
677
    if(ret != 0){
633
 
      perror("raise");
 
678
      error_plus(0, errno, "raise");
634
679
      abort();
635
680
    }
636
681
    TEMP_FAILURE_RETRY(pause());
637
682
  }
638
683
  
639
 
  return EXIT_FAILURE;
 
684
  return status;
640
685
}