/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: 2021-02-03 23:10:42 UTC
  • 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,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, 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 <sys/types.h>          /* size_t, ssize_t, pid_t, DIR, struct
35
 
                                   dirent */
36
 
#include <stddef.h>             /* NULL */
37
 
#include <string.h>             /* strlen(), memcmp() */
38
 
#include <stdio.h>              /* asprintf(), perror() */
39
 
#include <unistd.h>             /* close(), write(), readlink(),
40
 
                                   read(), STDOUT_FILENO, sleep(),
41
 
                                   fork(), setuid(), geteuid(),
42
 
                                   setsid(), chdir(), dup2(),
43
 
                                   STDERR_FILENO, execv() */
44
 
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
45
 
                                   EXIT_SUCCESS, malloc(), _exit(),
46
 
                                   getenv() */
47
 
#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() */
48
53
#include <inttypes.h>           /* intmax_t, strtoimax() */
49
 
#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() */
50
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() */
 
61
#include <argz.h>               /* argz_count(), argz_extract() */
51
62
 
52
63
sig_atomic_t interrupted_by_signal = 0;
53
64
int signal_received;
54
65
const char usplash_name[] = "/sbin/usplash";
55
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
 
56
91
static void termination_handler(int signum){
57
92
  if(interrupted_by_signal){
58
93
    return;
89
124
      ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg);
90
125
      if(ret == -1){
91
126
        int e = errno;
92
 
        TEMP_FAILURE_RETRY(close(*fifo_fd_r));
 
127
        close(*fifo_fd_r);
93
128
        errno = e;
94
129
        return false;
95
130
      }
105
140
                 cmd_line_len - written);
106
141
    if(sret == -1){
107
142
      int e = errno;
108
 
      TEMP_FAILURE_RETRY(close(*fifo_fd_r));
 
143
      close(*fifo_fd_r);
109
144
      free(cmd_line_alloc);
110
145
      errno = e;
111
146
      return false;
153
188
  size_t cmdline_len = 0;
154
189
  DIR *proc_dir = opendir("/proc");
155
190
  if(proc_dir == NULL){
156
 
    perror("opendir");
 
191
    error_plus(0, errno, "opendir");
157
192
    return -1;
158
193
  }
159
194
  errno = 0;
181
216
      char *exe_link;
182
217
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
183
218
      if(ret == -1){
184
 
        perror("asprintf");
 
219
        error_plus(0, errno, "asprintf");
185
220
        goto fail_find_usplash;
186
221
      }
187
222
      
193
228
          free(exe_link);
194
229
          continue;
195
230
        }
196
 
        perror("lstat");
 
231
        error_plus(0, errno, "lstat");
197
232
        free(exe_link);
198
233
        goto fail_find_usplash;
199
234
      }
224
259
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
225
260
                       proc_ent->d_name);
226
261
        if(ret == -1){
227
 
          perror("asprintf");
 
262
          error_plus(0, errno, "asprintf");
228
263
          goto fail_find_usplash;
229
264
        }
230
265
        cl_fd = open(cmdline_filename, O_RDONLY);
231
266
        free(cmdline_filename);
232
267
        if(cl_fd == -1){
233
 
          perror("open");
 
268
          error_plus(0, errno, "open");
234
269
          goto fail_find_usplash;
235
270
        }
236
271
      }
242
277
        if(cmdline_len + blocksize > cmdline_allocated){
243
278
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
244
279
          if(tmp == NULL){
245
 
            perror("realloc");
 
280
            error_plus(0, errno, "realloc");
246
281
            close(cl_fd);
247
282
            goto fail_find_usplash;
248
283
          }
253
288
        sret = read(cl_fd, cmdline + cmdline_len,
254
289
                    cmdline_allocated - cmdline_len);
255
290
        if(sret == -1){
256
 
          perror("read");
 
291
          error_plus(0, errno, "read");
257
292
          close(cl_fd);
258
293
          goto fail_find_usplash;
259
294
        }
261
296
      } while(sret != 0);
262
297
      ret = close(cl_fd);
263
298
      if(ret == -1){
264
 
        perror("close");
 
299
        error_plus(0, errno, "close");
265
300
        goto fail_find_usplash;
266
301
      }
267
302
    }
268
303
    /* Close directory */
269
304
    ret = closedir(proc_dir);
270
305
    if(ret == -1){
271
 
      perror("closedir");
 
306
      error_plus(0, errno, "closedir");
272
307
      goto fail_find_usplash;
273
308
    }
274
309
    /* Success */
323
358
    sigemptyset(&new_action.sa_mask);
324
359
    ret = sigaddset(&new_action.sa_mask, SIGINT);
325
360
    if(ret == -1){
326
 
      perror("sigaddset");
 
361
      error_plus(0, errno, "sigaddset");
327
362
      status = EX_OSERR;
328
363
      goto failure;
329
364
    }
330
365
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
331
366
    if(ret == -1){
332
 
      perror("sigaddset");
 
367
      error_plus(0, errno, "sigaddset");
333
368
      status = EX_OSERR;
334
369
      goto failure;
335
370
    }
336
371
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
337
372
    if(ret == -1){
338
 
      perror("sigaddset");
 
373
      error_plus(0, errno, "sigaddset");
339
374
      status = EX_OSERR;
340
375
      goto failure;
341
376
    }
342
377
    ret = sigaction(SIGINT, NULL, &old_action);
343
378
    if(ret == -1){
344
379
      if(errno != EINTR){
345
 
        perror("sigaction");
 
380
        error_plus(0, errno, "sigaction");
346
381
        status = EX_OSERR;
347
382
      }
348
383
      goto failure;
351
386
      ret = sigaction(SIGINT, &new_action, NULL);
352
387
      if(ret == -1){
353
388
        if(errno != EINTR){
354
 
          perror("sigaction");
 
389
          error_plus(0, errno, "sigaction");
355
390
          status = EX_OSERR;
356
391
        }
357
392
        goto failure;
360
395
    ret = sigaction(SIGHUP, NULL, &old_action);
361
396
    if(ret == -1){
362
397
      if(errno != EINTR){
363
 
        perror("sigaction");
 
398
        error_plus(0, errno, "sigaction");
364
399
        status = EX_OSERR;
365
400
      }
366
401
      goto failure;
369
404
      ret = sigaction(SIGHUP, &new_action, NULL);
370
405
      if(ret == -1){
371
406
        if(errno != EINTR){
372
 
          perror("sigaction");
 
407
          error_plus(0, errno, "sigaction");
373
408
          status = EX_OSERR;
374
409
        }
375
410
        goto failure;
378
413
    ret = sigaction(SIGTERM, NULL, &old_action);
379
414
    if(ret == -1){
380
415
      if(errno != EINTR){
381
 
        perror("sigaction");
 
416
        error_plus(0, errno, "sigaction");
382
417
        status = EX_OSERR;
383
418
      }
384
419
      goto failure;
387
422
      ret = sigaction(SIGTERM, &new_action, NULL);
388
423
      if(ret == -1){
389
424
        if(errno != EINTR){
390
 
          perror("sigaction");
 
425
          error_plus(0, errno, "sigaction");
391
426
          status = EX_OSERR;
392
427
        }
393
428
        goto failure;
399
434
  /* Write command to FIFO */
400
435
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
401
436
    if(errno != EINTR){
402
 
      perror("usplash_write");
 
437
      error_plus(0, errno, "usplash_write");
403
438
      status = EX_OSERR;
404
439
    }
405
440
    goto failure;
411
446
  
412
447
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
413
448
    if(errno != EINTR){
414
 
      perror("usplash_write");
 
449
      error_plus(0, errno, "usplash_write");
415
450
      status = EX_OSERR;
416
451
    }
417
452
    goto failure;
429
464
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
430
465
  if(outfifo_fd == -1){
431
466
    if(errno != EINTR){
432
 
      perror("open");
 
467
      error_plus(0, errno, "open");
433
468
      status = EX_OSERR;
434
469
    }
435
470
    goto failure;
448
483
      char *tmp = realloc(buf, buf_allocated + blocksize);
449
484
      if(tmp == NULL){
450
485
        if(errno != EINTR){
451
 
          perror("realloc");
 
486
          error_plus(0, errno, "realloc");
452
487
          status = EX_OSERR;
453
488
        }
454
489
        goto failure;
460
495
                buf_allocated - buf_len);
461
496
    if(sret == -1){
462
497
      if(errno != EINTR){
463
 
        perror("read");
 
498
        error_plus(0, errno, "read");
464
499
        status = EX_OSERR;
465
500
      }
466
 
      TEMP_FAILURE_RETRY(close(outfifo_fd));
 
501
      close(outfifo_fd);
467
502
      goto failure;
468
503
    }
469
504
    if(interrupted_by_signal){
475
510
  ret = close(outfifo_fd);
476
511
  if(ret == -1){
477
512
    if(errno != EINTR){
478
 
      perror("close");
 
513
      error_plus(0, errno, "close");
479
514
      status = EX_OSERR;
480
515
    }
481
516
    goto failure;
488
523
  
489
524
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
490
525
    if(errno != EINTR){
491
 
      perror("usplash_write");
 
526
      error_plus(0, errno, "usplash_write");
492
527
      status = EX_OSERR;
493
528
    }
494
529
    goto failure;
501
536
  ret = close(fifo_fd);
502
537
  if(ret == -1){
503
538
    if(errno != EINTR){
504
 
      perror("close");
 
539
      error_plus(0, errno, "close");
505
540
      status = EX_OSERR;
506
541
    }
507
542
    goto failure;
515
550
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
516
551
      if(sret == -1){
517
552
        if(errno != EINTR){
518
 
          perror("write");
 
553
          error_plus(0, errno, "write");
519
554
          status = EX_OSERR;
520
555
        }
521
556
        goto failure;
550
585
  
551
586
  /* Close FIFO */
552
587
  if(fifo_fd != -1){
553
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
 
588
    ret = close(fifo_fd);
554
589
    if(ret == -1 and errno != EINTR){
555
 
      perror("close");
 
590
      error_plus(0, errno, "close");
556
591
    }
557
592
    fifo_fd = -1;
558
593
  }
559
594
  
560
595
  /* Close output FIFO */
561
596
  if(outfifo_fd != -1){
562
 
    ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
 
597
    ret = close(outfifo_fd);
563
598
    if(ret == -1){
564
 
      perror("close");
565
 
    }
566
 
  }
567
 
  
568
 
  /* Create argc and argv for new usplash*/
569
 
  int cmdline_argc = 0;
570
 
  char **cmdline_argv = malloc(sizeof(char *));
571
 
  {
572
 
    size_t position = 0;
573
 
    while(position < cmdline_len){
574
 
      char **tmp = realloc(cmdline_argv,
575
 
                           (sizeof(char *)
576
 
                            * (size_t)(cmdline_argc + 2)));
577
 
      if(tmp == NULL){
578
 
        perror("realloc");
579
 
        free(cmdline_argv);
580
 
        return status;
581
 
      }
582
 
      cmdline_argv = tmp;
583
 
      cmdline_argv[cmdline_argc] = cmdline + position;
584
 
      cmdline_argc++;
585
 
      position += strlen(cmdline + position) + 1;
586
 
    }
587
 
    cmdline_argv[cmdline_argc] = NULL;
588
 
  }
 
599
      error_plus(0, errno, "close");
 
600
    }
 
601
  }
 
602
  
 
603
  /* Create argv for new usplash*/
 
604
  char **cmdline_argv = malloc((argz_count(cmdline, cmdline_len) + 1)
 
605
                               * sizeof(char *)); /* Count args */
 
606
  if(cmdline_argv == NULL){
 
607
    error_plus(0, errno, "malloc");
 
608
    return status;
 
609
  }
 
610
  argz_extract(cmdline, cmdline_len, cmdline_argv); /* Create argv */
 
611
  
589
612
  /* Kill old usplash */
590
613
  kill(usplash_pid, SIGTERM);
591
614
  sleep(2);
602
625
       the real user ID (_mandos) */
603
626
    ret = setuid(geteuid());
604
627
    if(ret == -1){
605
 
      perror("setuid");
 
628
      error_plus(0, errno, "setuid");
606
629
    }
607
630
    
608
631
    setsid();
609
632
    ret = chdir("/");
610
633
    if(ret == -1){
611
 
      perror("chdir");
 
634
      error_plus(0, errno, "chdir");
612
635
      _exit(EX_OSERR);
613
636
    }
614
637
/*     if(fork() != 0){ */
616
639
/*     } */
617
640
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
618
641
    if(ret == -1){
619
 
      perror("dup2");
 
642
      error_plus(0, errno, "dup2");
620
643
      _exit(EX_OSERR);
621
644
    }
622
645
    
623
646
    execv(usplash_name, cmdline_argv);
624
647
    if(not interrupted_by_signal){
625
 
      perror("execv");
 
648
      error_plus(0, errno, "execv");
626
649
    }
627
650
    free(cmdline);
628
651
    free(cmdline_argv);
633
656
  sleep(2);
634
657
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
635
658
    if(errno != EINTR){
636
 
      perror("usplash_write");
 
659
      error_plus(0, errno, "usplash_write");
637
660
    }
638
661
  }
639
662
  
640
663
  /* Close FIFO (again) */
641
664
  if(fifo_fd != -1){
642
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
 
665
    ret = close(fifo_fd);
643
666
    if(ret == -1 and errno != EINTR){
644
 
      perror("close");
 
667
      error_plus(0, errno, "close");
645
668
    }
646
669
    fifo_fd = -1;
647
670
  }
652
675
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
653
676
                                            &signal_action, NULL));
654
677
    if(ret == -1){
655
 
      perror("sigaction");
 
678
      error_plus(0, errno, "sigaction");
656
679
    }
657
680
    do {
658
681
      ret = raise(signal_received);
659
682
    } while(ret != 0 and errno == EINTR);
660
683
    if(ret != 0){
661
 
      perror("raise");
 
684
      error_plus(0, errno, "raise");
662
685
      abort();
663
686
    }
664
687
    TEMP_FAILURE_RETRY(pause());