/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/splashy.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
 * Splashy - Read a password from splashy 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             /* TEMP_FAILURE_RETRY(), asprintf() */
26
 
#include <signal.h>             /* sig_atomic_t, struct sigaction,
27
 
                                   sigemptyset(), sigaddset(), SIGINT,
28
 
                                   SIGHUP, SIGTERM, sigaction,
29
 
                                   SIG_IGN, kill(), SIGKILL */
30
 
#include <stddef.h>             /* NULL */
31
 
#include <stdlib.h>             /* getenv() */
32
 
#include <stdio.h>              /* asprintf(), perror() */
33
 
#include <stdlib.h>             /* EXIT_FAILURE, free(),
34
 
                                   EXIT_SUCCESS */
35
 
#include <sys/types.h>          /* pid_t, DIR, struct dirent,
36
 
                                   ssize_t */
37
 
#include <dirent.h>             /* opendir(), readdir(), closedir() */
38
 
#include <inttypes.h>           /* intmax_t, strtoimax() */
39
 
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
40
 
#include <iso646.h>             /* not, or, and */
41
 
#include <unistd.h>             /* readlink(), fork(), execl(),
42
 
                                   sleep(), dup2() STDERR_FILENO,
43
 
                                   STDOUT_FILENO, _exit(),
44
 
                                   pause() */
45
 
#include <string.h>             /* memcmp() */
46
 
#include <errno.h>              /* errno, EACCES, ENOTDIR, ELOOP,
 
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, EACCES, ENOTDIR, ELOOP,
47
36
                                   ENOENT, ENAMETOOLONG, EMFILE,
48
37
                                   ENFILE, ENOMEM, ENOEXEC, EINVAL,
49
38
                                   E2BIG, EFAULT, EIO, ETXTBSY,
50
39
                                   EISDIR, ELIBBAD, EPERM, EINTR,
51
40
                                   ECHILD */
 
41
#include <string.h>             /* strerror(), memcmp() */
 
42
#include <error.h>              /* error() */
 
43
#include <stdlib.h>             /* free(), EXIT_FAILURE, getenv(),
 
44
                                   EXIT_SUCCESS, abort() */
 
45
#include <stddef.h>             /* NULL */
 
46
#include <dirent.h>             /* DIR, opendir(), struct dirent,
 
47
                                   readdir(), closedir() */
 
48
#include <sysexits.h>           /* EX_OSERR, EX_OSFILE,
 
49
                                   EX_UNAVAILABLE */
 
50
#include <inttypes.h>           /* intmax_t, strtoimax() */
 
51
#include <iso646.h>             /* or, not, and */
 
52
#include <unistd.h>             /* ssize_t, readlink(), fork(),
 
53
                                   execl(), _exit(),
 
54
                                   TEMP_FAILURE_RETRY(), sleep(),
 
55
                                   setuid(), geteuid(), setsid(),
 
56
                                   chdir(), dup2(), STDERR_FILENO,
 
57
                                   STDOUT_FILENO, pause() */
 
58
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK() */
 
59
#include <signal.h>             /* struct sigaction, sigemptyset(),
 
60
                                   sigaddset(), SIGINT, SIGHUP,
 
61
                                   SIGTERM, SIG_IGN, kill(), SIGKILL,
 
62
                                   SIG_DFL, raise() */
52
63
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
53
64
                                   WEXITSTATUS() */
54
 
#include <sysexits.h>           /* EX_OSERR, EX_OSFILE,
55
 
                                   EX_UNAVAILABLE */
56
65
 
57
66
sig_atomic_t interrupted_by_signal = 0;
58
67
int signal_received;
59
68
 
 
69
/* Function to use when printing errors */
 
70
__attribute__((format (gnu_printf, 3, 4)))
 
71
void error_plus(int status, int errnum, const char *formatstring,
 
72
                ...){
 
73
  va_list ap;
 
74
  char *text;
 
75
  int ret;
 
76
  
 
77
  va_start(ap, formatstring);
 
78
  ret = vasprintf(&text, formatstring, ap);
 
79
  if(ret == -1){
 
80
    fprintf(stderr, "Mandos plugin %s: ",
 
81
            program_invocation_short_name);
 
82
    vfprintf(stderr, formatstring, ap);
 
83
    fprintf(stderr, ": ");
 
84
    fprintf(stderr, "%s\n", strerror(errnum));
 
85
    error(status, errno, "vasprintf while printing error");
 
86
    return;
 
87
  }
 
88
  fprintf(stderr, "Mandos plugin ");
 
89
  error(status, errnum, "%s", text);
 
90
  free(text);
 
91
}
 
92
 
 
93
 
60
94
static void termination_handler(int signum){
61
95
  if(interrupted_by_signal){
62
96
    return;
109
143
    proc_dir = opendir("/proc");
110
144
    if(proc_dir == NULL){
111
145
      int e = errno;
112
 
      perror("opendir");
 
146
      error_plus(0, errno, "opendir");
113
147
      switch(e){
114
148
      case EACCES:
115
149
      case ENOTDIR:
151
185
        char *exe_link;
152
186
        ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
153
187
        if(ret == -1){
154
 
          perror("asprintf");
 
188
          error_plus(0, errno, "asprintf");
155
189
          exitstatus = EX_OSERR;
156
190
          goto failure;
157
191
        }
165
199
            continue;
166
200
          }
167
201
          int e = errno;
168
 
          perror("lstat");
 
202
          error_plus(0, errno, "lstat");
169
203
          free(exe_link);
170
204
          switch(e){
171
205
          case EACCES:
213
247
    sigemptyset(&new_action.sa_mask);
214
248
    ret = sigaddset(&new_action.sa_mask, SIGINT);
215
249
    if(ret == -1){
216
 
      perror("sigaddset");
 
250
      error_plus(0, errno, "sigaddset");
217
251
      exitstatus = EX_OSERR;
218
252
      goto failure;
219
253
    }
220
254
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
221
255
    if(ret == -1){
222
 
      perror("sigaddset");
 
256
      error_plus(0, errno, "sigaddset");
223
257
      exitstatus = EX_OSERR;
224
258
      goto failure;
225
259
    }
226
260
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
227
261
    if(ret == -1){
228
 
      perror("sigaddset");
 
262
      error_plus(0, errno, "sigaddset");
229
263
      exitstatus = EX_OSERR;
230
264
      goto failure;
231
265
    }
232
266
    ret = sigaction(SIGINT, NULL, &old_action);
233
267
    if(ret == -1){
234
 
      perror("sigaction");
 
268
      error_plus(0, errno, "sigaction");
235
269
      exitstatus = EX_OSERR;
236
270
      goto failure;
237
271
    }
238
272
    if(old_action.sa_handler != SIG_IGN){
239
273
      ret = sigaction(SIGINT, &new_action, NULL);
240
274
      if(ret == -1){
241
 
        perror("sigaction");
 
275
        error_plus(0, errno, "sigaction");
242
276
        exitstatus = EX_OSERR;
243
277
        goto failure;
244
278
      }
245
279
    }
246
280
    ret = sigaction(SIGHUP, NULL, &old_action);
247
281
    if(ret == -1){
248
 
      perror("sigaction");
 
282
      error_plus(0, errno, "sigaction");
249
283
      exitstatus = EX_OSERR;
250
284
      goto failure;
251
285
    }
252
286
    if(old_action.sa_handler != SIG_IGN){
253
287
      ret = sigaction(SIGHUP, &new_action, NULL);
254
288
      if(ret == -1){
255
 
        perror("sigaction");
 
289
        error_plus(0, errno, "sigaction");
256
290
        exitstatus = EX_OSERR;
257
291
        goto failure;
258
292
      }
259
293
    }
260
294
    ret = sigaction(SIGTERM, NULL, &old_action);
261
295
    if(ret == -1){
262
 
      perror("sigaction");
 
296
      error_plus(0, errno, "sigaction");
263
297
      exitstatus = EX_OSERR;
264
298
      goto failure;
265
299
    }
266
300
    if(old_action.sa_handler != SIG_IGN){
267
301
      ret = sigaction(SIGTERM, &new_action, NULL);
268
302
      if(ret == -1){
269
 
        perror("sigaction");
 
303
        error_plus(0, errno, "sigaction");
270
304
        exitstatus = EX_OSERR;
271
305
        goto failure;
272
306
      }
283
317
    goto failure;
284
318
  }
285
319
  if(splashy_command_pid == -1){
286
 
    perror("fork");
 
320
    error_plus(0, errno, "fork");
287
321
    exitstatus = EX_OSERR;
288
322
    goto failure;
289
323
  }
293
327
      const char splashy_command[] = "/sbin/splashy_update";
294
328
      execl(splashy_command, splashy_command, prompt, (char *)NULL);
295
329
      int e = errno;
296
 
      perror("execl");
 
330
      error_plus(0, errno, "execl");
297
331
      switch(e){
298
332
      case EACCES:
299
333
      case ENOENT:
313
347
      case ENOTDIR:
314
348
      case ELOOP:
315
349
      case EISDIR:
316
 
      case ELIBBAD:
 
350
#ifdef ELIBBAD
 
351
      case ELIBBAD:             /* Linux only */
 
352
#endif
317
353
      case EPERM:
318
354
        _exit(EX_OSFILE);
319
355
      }
341
377
      goto failure;
342
378
    }
343
379
    if(ret == -1){
344
 
      perror("waitpid");
 
380
      error_plus(0, errno, "waitpid");
345
381
      if(errno == ECHILD){
346
382
        splashy_command_pid = 0;
347
383
      }
379
415
         the real user ID (_mandos) */
380
416
      ret = setuid(geteuid());
381
417
      if(ret == -1){
382
 
        perror("setuid");
 
418
        error_plus(0, errno, "setuid");
383
419
      }
384
420
      
385
421
      setsid();
386
422
      ret = chdir("/");
387
423
      if(ret == -1){
388
 
        perror("chdir");
 
424
        error_plus(0, errno, "chdir");
389
425
      }
390
426
/*       if(fork() != 0){ */
391
427
/*      _exit(EXIT_SUCCESS); */
392
428
/*       } */
393
429
      ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace stdout */
394
430
      if(ret == -1){
395
 
        perror("dup2");
 
431
        error_plus(0, errno, "dup2");
396
432
        _exit(EX_OSERR);
397
433
      }
398
434
      
399
435
      execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
400
436
      {
401
437
        int e = errno;
402
 
        perror("execl");
 
438
        error_plus(0, errno, "execl");
403
439
        switch(e){
404
440
        case EACCES:
405
441
        case ENOENT:
425
461
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
426
462
                                            &signal_action, NULL));
427
463
    if(ret == -1){
428
 
      perror("sigaction");
 
464
      error_plus(0, errno, "sigaction");
429
465
    }
430
466
    do {
431
467
      ret = raise(signal_received);
432
468
    } while(ret != 0 and errno == EINTR);
433
469
    if(ret != 0){
434
 
      perror("raise");
 
470
      error_plus(0, errno, "raise");
435
471
      abort();
436
472
    }
437
473
    TEMP_FAILURE_RETRY(pause());