/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() */
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() */
52
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() */
53
63
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
54
64
                                   WEXITSTATUS() */
55
 
#include <sysexits.h>           /* EX_OSERR, EX_OSFILE,
56
 
                                   EX_UNAVAILABLE */
57
65
 
58
66
sig_atomic_t interrupted_by_signal = 0;
59
67
int signal_received;
60
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
 
61
94
static void termination_handler(int signum){
62
95
  if(interrupted_by_signal){
63
96
    return;
110
143
    proc_dir = opendir("/proc");
111
144
    if(proc_dir == NULL){
112
145
      int e = errno;
113
 
      error(0, errno, "opendir");
 
146
      error_plus(0, errno, "opendir");
114
147
      switch(e){
115
148
      case EACCES:
116
149
      case ENOTDIR:
152
185
        char *exe_link;
153
186
        ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
154
187
        if(ret == -1){
155
 
          error(0, errno, "asprintf");
 
188
          error_plus(0, errno, "asprintf");
156
189
          exitstatus = EX_OSERR;
157
190
          goto failure;
158
191
        }
166
199
            continue;
167
200
          }
168
201
          int e = errno;
169
 
          error(0, errno, "lstat");
 
202
          error_plus(0, errno, "lstat");
170
203
          free(exe_link);
171
204
          switch(e){
172
205
          case EACCES:
214
247
    sigemptyset(&new_action.sa_mask);
215
248
    ret = sigaddset(&new_action.sa_mask, SIGINT);
216
249
    if(ret == -1){
217
 
      error(0, errno, "sigaddset");
 
250
      error_plus(0, errno, "sigaddset");
218
251
      exitstatus = EX_OSERR;
219
252
      goto failure;
220
253
    }
221
254
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
222
255
    if(ret == -1){
223
 
      error(0, errno, "sigaddset");
 
256
      error_plus(0, errno, "sigaddset");
224
257
      exitstatus = EX_OSERR;
225
258
      goto failure;
226
259
    }
227
260
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
228
261
    if(ret == -1){
229
 
      error(0, errno, "sigaddset");
 
262
      error_plus(0, errno, "sigaddset");
230
263
      exitstatus = EX_OSERR;
231
264
      goto failure;
232
265
    }
233
266
    ret = sigaction(SIGINT, NULL, &old_action);
234
267
    if(ret == -1){
235
 
      error(0, errno, "sigaction");
 
268
      error_plus(0, errno, "sigaction");
236
269
      exitstatus = EX_OSERR;
237
270
      goto failure;
238
271
    }
239
272
    if(old_action.sa_handler != SIG_IGN){
240
273
      ret = sigaction(SIGINT, &new_action, NULL);
241
274
      if(ret == -1){
242
 
        error(0, errno, "sigaction");
 
275
        error_plus(0, errno, "sigaction");
243
276
        exitstatus = EX_OSERR;
244
277
        goto failure;
245
278
      }
246
279
    }
247
280
    ret = sigaction(SIGHUP, NULL, &old_action);
248
281
    if(ret == -1){
249
 
      error(0, errno, "sigaction");
 
282
      error_plus(0, errno, "sigaction");
250
283
      exitstatus = EX_OSERR;
251
284
      goto failure;
252
285
    }
253
286
    if(old_action.sa_handler != SIG_IGN){
254
287
      ret = sigaction(SIGHUP, &new_action, NULL);
255
288
      if(ret == -1){
256
 
        error(0, errno, "sigaction");
 
289
        error_plus(0, errno, "sigaction");
257
290
        exitstatus = EX_OSERR;
258
291
        goto failure;
259
292
      }
260
293
    }
261
294
    ret = sigaction(SIGTERM, NULL, &old_action);
262
295
    if(ret == -1){
263
 
      error(0, errno, "sigaction");
 
296
      error_plus(0, errno, "sigaction");
264
297
      exitstatus = EX_OSERR;
265
298
      goto failure;
266
299
    }
267
300
    if(old_action.sa_handler != SIG_IGN){
268
301
      ret = sigaction(SIGTERM, &new_action, NULL);
269
302
      if(ret == -1){
270
 
        error(0, errno, "sigaction");
 
303
        error_plus(0, errno, "sigaction");
271
304
        exitstatus = EX_OSERR;
272
305
        goto failure;
273
306
      }
284
317
    goto failure;
285
318
  }
286
319
  if(splashy_command_pid == -1){
287
 
    error(0, errno, "fork");
 
320
    error_plus(0, errno, "fork");
288
321
    exitstatus = EX_OSERR;
289
322
    goto failure;
290
323
  }
294
327
      const char splashy_command[] = "/sbin/splashy_update";
295
328
      execl(splashy_command, splashy_command, prompt, (char *)NULL);
296
329
      int e = errno;
297
 
      error(0, errno, "execl");
 
330
      error_plus(0, errno, "execl");
298
331
      switch(e){
299
332
      case EACCES:
300
333
      case ENOENT:
314
347
      case ENOTDIR:
315
348
      case ELOOP:
316
349
      case EISDIR:
317
 
      case ELIBBAD:
 
350
#ifdef ELIBBAD
 
351
      case ELIBBAD:             /* Linux only */
 
352
#endif
318
353
      case EPERM:
319
354
        _exit(EX_OSFILE);
320
355
      }
342
377
      goto failure;
343
378
    }
344
379
    if(ret == -1){
345
 
      error(0, errno, "waitpid");
 
380
      error_plus(0, errno, "waitpid");
346
381
      if(errno == ECHILD){
347
382
        splashy_command_pid = 0;
348
383
      }
380
415
         the real user ID (_mandos) */
381
416
      ret = setuid(geteuid());
382
417
      if(ret == -1){
383
 
        error(0, errno, "setuid");
 
418
        error_plus(0, errno, "setuid");
384
419
      }
385
420
      
386
421
      setsid();
387
422
      ret = chdir("/");
388
423
      if(ret == -1){
389
 
        error(0, errno, "chdir");
 
424
        error_plus(0, errno, "chdir");
390
425
      }
391
426
/*       if(fork() != 0){ */
392
427
/*      _exit(EXIT_SUCCESS); */
393
428
/*       } */
394
429
      ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace stdout */
395
430
      if(ret == -1){
396
 
        error(0, errno, "dup2");
 
431
        error_plus(0, errno, "dup2");
397
432
        _exit(EX_OSERR);
398
433
      }
399
434
      
400
435
      execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
401
436
      {
402
437
        int e = errno;
403
 
        error(0, errno, "execl");
 
438
        error_plus(0, errno, "execl");
404
439
        switch(e){
405
440
        case EACCES:
406
441
        case ENOENT:
426
461
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
427
462
                                            &signal_action, NULL));
428
463
    if(ret == -1){
429
 
      error(0, errno, "sigaction");
 
464
      error_plus(0, errno, "sigaction");
430
465
    }
431
466
    do {
432
467
      ret = raise(signal_received);
433
468
    } while(ret != 0 and errno == EINTR);
434
469
    if(ret != 0){
435
 
      error(0, errno, "raise");
 
470
      error_plus(0, errno, "raise");
436
471
      abort();
437
472
    }
438
473
    TEMP_FAILURE_RETRY(pause());