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