/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: 2021-02-03 23:10:42 UTC
  • mto: This revision was merged to the branch mainline in revision 406.
  • Revision ID: teddy@recompile.se-20210203231042-2z3egrvpo1zt7nej
mandos-ctl: Fix bad test for command.Remove and related minor issues

The test for command.Remove removes all clients from the spy server,
and then loops over all clients, looking for the corresponding Remove
command as recorded by the spy server.  But since since there aren't
any clients left after they were removed, no assertions are made, and
the test therefore does nothing.  Fix this.

In tests for command.Approve and command.Deny, add checks that clients
were not somehow removed by the command (in which case, likewise, no
assertions are made).

Add related checks to TestPropertySetterCmd.runTest; i.e. test that a
sequence is not empty before looping over it and making assertions.

* mandos-ctl (TestBaseCommands.test_Remove): Save a copy of the
  original "clients" dict, and loop over those instead.  Add assertion
  that all clients were indeed removed.  Also fix the code which looks
  for the Remove command, which now needs to actually work.
  (TestBaseCommands.test_Approve, TestBaseCommands.test_Deny): Add
  assertion that there are still clients before looping over them.
  (TestPropertySetterCmd.runTest): Add assertion that the list of
  values to get is not empty before looping over them.  Also add check
  that there are still clients before looping over clients.

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-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
 
5
 * Copyright © 2008-2018, 2021 Teddy Hogeborn
 
6
 * Copyright © 2008-2018, 2021 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
 
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
26
 
#include <signal.h>             /* sig_atomic_t, struct sigaction,
27
 
                                   sigemptyset(), sigaddset(), SIGINT,
28
 
                                   SIGHUP, SIGTERM, sigaction(),
29
 
                                   SIG_IGN, kill(), SIGKILL */
 
26
#define _GNU_SOURCE             /* vasprintf(),
 
27
                                   program_invocation_short_name,
 
28
                                   asprintf(), TEMP_FAILURE_RETRY() */
 
29
#include <sys/types.h>          /* sig_atomic_t, pid_t, setuid(),
 
30
                                   geteuid(), setsid() */
 
31
#include <stdarg.h>             /* va_list, va_start(), vfprintf() */
 
32
#include <stdio.h>              /* vasprintf(), fprintf(), stderr,
 
33
                                   vfprintf(), asprintf() */
 
34
#include <errno.h>              /* program_invocation_short_name,
 
35
                                   errno, ENOENT, EINTR */
 
36
#include <string.h>             /* strerror(), strlen(), memcmp() */
 
37
#include <error.h>              /* error() */
 
38
#include <stdlib.h>             /* free(), getenv(), realloc(),
 
39
                                   EXIT_FAILURE, EXIT_SUCCESS,
 
40
                                   malloc(), abort() */
30
41
#include <stdbool.h>            /* bool, false, true */
31
42
#include <fcntl.h>              /* open(), O_WRONLY, O_RDONLY */
32
 
#include <iso646.h>             /* and, or, not*/
33
 
#include <errno.h>              /* errno, EINTR */
34
 
#include <error.h>
35
 
#include <sys/types.h>          /* size_t, ssize_t, pid_t, DIR, struct
36
 
                                   dirent */
37
 
#include <stddef.h>             /* NULL */
38
 
#include <string.h>             /* strlen(), memcmp() */
39
 
#include <stdio.h>              /* asprintf()*/
40
 
#include <unistd.h>             /* close(), write(), readlink(),
41
 
                                   read(), STDOUT_FILENO, sleep(),
42
 
                                   fork(), setuid(), geteuid(),
43
 
                                   setsid(), chdir(), dup2(),
44
 
                                   STDERR_FILENO, execv() */
45
 
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
46
 
                                   EXIT_SUCCESS, malloc(), _exit(),
47
 
                                   getenv() */
48
 
#include <dirent.h>             /* opendir(), readdir(), closedir() */
 
43
#include <stddef.h>             /* size_t, NULL */
 
44
#include <unistd.h>             /* close(), ssize_t, write(),
 
45
                                   readlink(), read(), STDOUT_FILENO,
 
46
                                   sleep(), fork(), setuid(),
 
47
                                   geteuid(), setsid(), chdir(),
 
48
                                   _exit(), dup2(), STDERR_FILENO,
 
49
                                   execv(), TEMP_FAILURE_RETRY(),
 
50
                                   pause() */
 
51
#include <dirent.h>             /* DIR, opendir(), struct dirent,
 
52
                                   readdir(), closedir() */
49
53
#include <inttypes.h>           /* intmax_t, strtoimax() */
50
 
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
 
54
#include <iso646.h>             /* or, not, and */
 
55
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK() */
51
56
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
 
57
#include <signal.h>             /* struct sigaction, sigemptyset(),
 
58
                                   sigaddset(), SIGINT, SIGHUP,
 
59
                                   SIGTERM, SIG_IGN, kill(), SIGKILL,
 
60
                                   SIG_DFL, raise() */
52
61
#include <argz.h>               /* argz_count(), argz_extract() */
53
62
 
54
63
sig_atomic_t interrupted_by_signal = 0;
55
64
int signal_received;
56
65
const char usplash_name[] = "/sbin/usplash";
57
66
 
 
67
/* Function to use when printing errors */
 
68
__attribute__((format (gnu_printf, 3, 4)))
 
69
void error_plus(int status, int errnum, const char *formatstring,
 
70
                ...){
 
71
  va_list ap;
 
72
  char *text;
 
73
  int ret;
 
74
  
 
75
  va_start(ap, formatstring);
 
76
  ret = vasprintf(&text, formatstring, ap);
 
77
  if(ret == -1){
 
78
    fprintf(stderr, "Mandos plugin %s: ",
 
79
            program_invocation_short_name);
 
80
    vfprintf(stderr, formatstring, ap);
 
81
    fprintf(stderr, ": ");
 
82
    fprintf(stderr, "%s\n", strerror(errnum));
 
83
    error(status, errno, "vasprintf while printing error");
 
84
    return;
 
85
  }
 
86
  fprintf(stderr, "Mandos plugin ");
 
87
  error(status, errnum, "%s", text);
 
88
  free(text);
 
89
}
 
90
 
58
91
static void termination_handler(int signum){
59
92
  if(interrupted_by_signal){
60
93
    return;
91
124
      ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg);
92
125
      if(ret == -1){
93
126
        int e = errno;
94
 
        TEMP_FAILURE_RETRY(close(*fifo_fd_r));
 
127
        close(*fifo_fd_r);
95
128
        errno = e;
96
129
        return false;
97
130
      }
107
140
                 cmd_line_len - written);
108
141
    if(sret == -1){
109
142
      int e = errno;
110
 
      TEMP_FAILURE_RETRY(close(*fifo_fd_r));
 
143
      close(*fifo_fd_r);
111
144
      free(cmd_line_alloc);
112
145
      errno = e;
113
146
      return false;
155
188
  size_t cmdline_len = 0;
156
189
  DIR *proc_dir = opendir("/proc");
157
190
  if(proc_dir == NULL){
158
 
    error(0, errno, "opendir");
 
191
    error_plus(0, errno, "opendir");
159
192
    return -1;
160
193
  }
161
194
  errno = 0;
183
216
      char *exe_link;
184
217
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
185
218
      if(ret == -1){
186
 
        error(0, errno, "asprintf");
 
219
        error_plus(0, errno, "asprintf");
187
220
        goto fail_find_usplash;
188
221
      }
189
222
      
195
228
          free(exe_link);
196
229
          continue;
197
230
        }
198
 
        error(0, errno, "lstat");
 
231
        error_plus(0, errno, "lstat");
199
232
        free(exe_link);
200
233
        goto fail_find_usplash;
201
234
      }
226
259
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
227
260
                       proc_ent->d_name);
228
261
        if(ret == -1){
229
 
          error(0, errno, "asprintf");
 
262
          error_plus(0, errno, "asprintf");
230
263
          goto fail_find_usplash;
231
264
        }
232
265
        cl_fd = open(cmdline_filename, O_RDONLY);
233
266
        free(cmdline_filename);
234
267
        if(cl_fd == -1){
235
 
          error(0, errno, "open");
 
268
          error_plus(0, errno, "open");
236
269
          goto fail_find_usplash;
237
270
        }
238
271
      }
244
277
        if(cmdline_len + blocksize > cmdline_allocated){
245
278
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
246
279
          if(tmp == NULL){
247
 
            error(0, errno, "realloc");
 
280
            error_plus(0, errno, "realloc");
248
281
            close(cl_fd);
249
282
            goto fail_find_usplash;
250
283
          }
255
288
        sret = read(cl_fd, cmdline + cmdline_len,
256
289
                    cmdline_allocated - cmdline_len);
257
290
        if(sret == -1){
258
 
          error(0, errno, "read");
 
291
          error_plus(0, errno, "read");
259
292
          close(cl_fd);
260
293
          goto fail_find_usplash;
261
294
        }
263
296
      } while(sret != 0);
264
297
      ret = close(cl_fd);
265
298
      if(ret == -1){
266
 
        error(0, errno, "close");
 
299
        error_plus(0, errno, "close");
267
300
        goto fail_find_usplash;
268
301
      }
269
302
    }
270
303
    /* Close directory */
271
304
    ret = closedir(proc_dir);
272
305
    if(ret == -1){
273
 
      error(0, errno, "closedir");
 
306
      error_plus(0, errno, "closedir");
274
307
      goto fail_find_usplash;
275
308
    }
276
309
    /* Success */
325
358
    sigemptyset(&new_action.sa_mask);
326
359
    ret = sigaddset(&new_action.sa_mask, SIGINT);
327
360
    if(ret == -1){
328
 
      error(0, errno, "sigaddset");
 
361
      error_plus(0, errno, "sigaddset");
329
362
      status = EX_OSERR;
330
363
      goto failure;
331
364
    }
332
365
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
333
366
    if(ret == -1){
334
 
      error(0, errno, "sigaddset");
 
367
      error_plus(0, errno, "sigaddset");
335
368
      status = EX_OSERR;
336
369
      goto failure;
337
370
    }
338
371
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
339
372
    if(ret == -1){
340
 
      error(0, errno, "sigaddset");
 
373
      error_plus(0, errno, "sigaddset");
341
374
      status = EX_OSERR;
342
375
      goto failure;
343
376
    }
344
377
    ret = sigaction(SIGINT, NULL, &old_action);
345
378
    if(ret == -1){
346
379
      if(errno != EINTR){
347
 
        error(0, errno, "sigaction");
 
380
        error_plus(0, errno, "sigaction");
348
381
        status = EX_OSERR;
349
382
      }
350
383
      goto failure;
353
386
      ret = sigaction(SIGINT, &new_action, NULL);
354
387
      if(ret == -1){
355
388
        if(errno != EINTR){
356
 
          error(0, errno, "sigaction");
 
389
          error_plus(0, errno, "sigaction");
357
390
          status = EX_OSERR;
358
391
        }
359
392
        goto failure;
362
395
    ret = sigaction(SIGHUP, NULL, &old_action);
363
396
    if(ret == -1){
364
397
      if(errno != EINTR){
365
 
        error(0, errno, "sigaction");
 
398
        error_plus(0, errno, "sigaction");
366
399
        status = EX_OSERR;
367
400
      }
368
401
      goto failure;
371
404
      ret = sigaction(SIGHUP, &new_action, NULL);
372
405
      if(ret == -1){
373
406
        if(errno != EINTR){
374
 
          error(0, errno, "sigaction");
 
407
          error_plus(0, errno, "sigaction");
375
408
          status = EX_OSERR;
376
409
        }
377
410
        goto failure;
380
413
    ret = sigaction(SIGTERM, NULL, &old_action);
381
414
    if(ret == -1){
382
415
      if(errno != EINTR){
383
 
        error(0, errno, "sigaction");
 
416
        error_plus(0, errno, "sigaction");
384
417
        status = EX_OSERR;
385
418
      }
386
419
      goto failure;
389
422
      ret = sigaction(SIGTERM, &new_action, NULL);
390
423
      if(ret == -1){
391
424
        if(errno != EINTR){
392
 
          error(0, errno, "sigaction");
 
425
          error_plus(0, errno, "sigaction");
393
426
          status = EX_OSERR;
394
427
        }
395
428
        goto failure;
401
434
  /* Write command to FIFO */
402
435
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
403
436
    if(errno != EINTR){
404
 
      error(0, errno, "usplash_write");
 
437
      error_plus(0, errno, "usplash_write");
405
438
      status = EX_OSERR;
406
439
    }
407
440
    goto failure;
413
446
  
414
447
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
415
448
    if(errno != EINTR){
416
 
      error(0, errno, "usplash_write");
 
449
      error_plus(0, errno, "usplash_write");
417
450
      status = EX_OSERR;
418
451
    }
419
452
    goto failure;
431
464
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
432
465
  if(outfifo_fd == -1){
433
466
    if(errno != EINTR){
434
 
      error(0, errno, "open");
 
467
      error_plus(0, errno, "open");
435
468
      status = EX_OSERR;
436
469
    }
437
470
    goto failure;
450
483
      char *tmp = realloc(buf, buf_allocated + blocksize);
451
484
      if(tmp == NULL){
452
485
        if(errno != EINTR){
453
 
          error(0, errno, "realloc");
 
486
          error_plus(0, errno, "realloc");
454
487
          status = EX_OSERR;
455
488
        }
456
489
        goto failure;
462
495
                buf_allocated - buf_len);
463
496
    if(sret == -1){
464
497
      if(errno != EINTR){
465
 
        error(0, errno, "read");
 
498
        error_plus(0, errno, "read");
466
499
        status = EX_OSERR;
467
500
      }
468
 
      TEMP_FAILURE_RETRY(close(outfifo_fd));
 
501
      close(outfifo_fd);
469
502
      goto failure;
470
503
    }
471
504
    if(interrupted_by_signal){
477
510
  ret = close(outfifo_fd);
478
511
  if(ret == -1){
479
512
    if(errno != EINTR){
480
 
      error(0, errno, "close");
 
513
      error_plus(0, errno, "close");
481
514
      status = EX_OSERR;
482
515
    }
483
516
    goto failure;
490
523
  
491
524
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
492
525
    if(errno != EINTR){
493
 
      error(0, errno, "usplash_write");
 
526
      error_plus(0, errno, "usplash_write");
494
527
      status = EX_OSERR;
495
528
    }
496
529
    goto failure;
503
536
  ret = close(fifo_fd);
504
537
  if(ret == -1){
505
538
    if(errno != EINTR){
506
 
      error(0, errno, "close");
 
539
      error_plus(0, errno, "close");
507
540
      status = EX_OSERR;
508
541
    }
509
542
    goto failure;
517
550
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
518
551
      if(sret == -1){
519
552
        if(errno != EINTR){
520
 
          error(0, errno, "write");
 
553
          error_plus(0, errno, "write");
521
554
          status = EX_OSERR;
522
555
        }
523
556
        goto failure;
552
585
  
553
586
  /* Close FIFO */
554
587
  if(fifo_fd != -1){
555
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
 
588
    ret = close(fifo_fd);
556
589
    if(ret == -1 and errno != EINTR){
557
 
      error(0, errno, "close");
 
590
      error_plus(0, errno, "close");
558
591
    }
559
592
    fifo_fd = -1;
560
593
  }
561
594
  
562
595
  /* Close output FIFO */
563
596
  if(outfifo_fd != -1){
564
 
    ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
 
597
    ret = close(outfifo_fd);
565
598
    if(ret == -1){
566
 
      error(0, errno, "close");
 
599
      error_plus(0, errno, "close");
567
600
    }
568
601
  }
569
602
  
571
604
  char **cmdline_argv = malloc((argz_count(cmdline, cmdline_len) + 1)
572
605
                               * sizeof(char *)); /* Count args */
573
606
  if(cmdline_argv == NULL){
574
 
    error(0, errno, "malloc");
 
607
    error_plus(0, errno, "malloc");
575
608
    return status;
576
609
  }
577
610
  argz_extract(cmdline, cmdline_len, cmdline_argv); /* Create argv */
592
625
       the real user ID (_mandos) */
593
626
    ret = setuid(geteuid());
594
627
    if(ret == -1){
595
 
      error(0, errno, "setuid");
 
628
      error_plus(0, errno, "setuid");
596
629
    }
597
630
    
598
631
    setsid();
599
632
    ret = chdir("/");
600
633
    if(ret == -1){
601
 
      error(0, errno, "chdir");
 
634
      error_plus(0, errno, "chdir");
602
635
      _exit(EX_OSERR);
603
636
    }
604
637
/*     if(fork() != 0){ */
606
639
/*     } */
607
640
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
608
641
    if(ret == -1){
609
 
      error(0, errno, "dup2");
 
642
      error_plus(0, errno, "dup2");
610
643
      _exit(EX_OSERR);
611
644
    }
612
645
    
613
646
    execv(usplash_name, cmdline_argv);
614
647
    if(not interrupted_by_signal){
615
 
      error(0, errno, "execv");
 
648
      error_plus(0, errno, "execv");
616
649
    }
617
650
    free(cmdline);
618
651
    free(cmdline_argv);
623
656
  sleep(2);
624
657
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
625
658
    if(errno != EINTR){
626
 
      error(0, errno, "usplash_write");
 
659
      error_plus(0, errno, "usplash_write");
627
660
    }
628
661
  }
629
662
  
630
663
  /* Close FIFO (again) */
631
664
  if(fifo_fd != -1){
632
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
 
665
    ret = close(fifo_fd);
633
666
    if(ret == -1 and errno != EINTR){
634
 
      error(0, errno, "close");
 
667
      error_plus(0, errno, "close");
635
668
    }
636
669
    fifo_fd = -1;
637
670
  }
642
675
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
643
676
                                            &signal_action, NULL));
644
677
    if(ret == -1){
645
 
      error(0, errno, "sigaction");
 
678
      error_plus(0, errno, "sigaction");
646
679
    }
647
680
    do {
648
681
      ret = raise(signal_received);
649
682
    } while(ret != 0 and errno == EINTR);
650
683
    if(ret != 0){
651
 
      error(0, errno, "raise");
 
684
      error_plus(0, errno, "raise");
652
685
      abort();
653
686
    }
654
687
    TEMP_FAILURE_RETRY(pause());