/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 */
 
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,
 
36
                                   ENOENT, ENAMETOOLONG, EMFILE,
 
37
                                   ENFILE, ENOMEM, ENOEXEC, EINVAL,
 
38
                                   E2BIG, EFAULT, EIO, ETXTBSY,
 
39
                                   EISDIR, ELIBBAD, EPERM, EINTR,
 
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() */
30
45
#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() */
 
46
#include <dirent.h>             /* DIR, opendir(), struct dirent,
 
47
                                   readdir(), closedir() */
 
48
#include <sysexits.h>           /* EX_OSERR, EX_OSFILE,
 
49
                                   EX_UNAVAILABLE */
38
50
#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 */
 
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() */
47
63
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
48
64
                                   WEXITSTATUS() */
49
65
 
50
 
#include <sysexits.h>           /* EX_OSERR, EX_OSFILE,
51
 
                                   EX_UNAVAILABLE */
52
 
 
53
66
sig_atomic_t interrupted_by_signal = 0;
54
67
int signal_received;
55
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
 
56
94
static void termination_handler(int signum){
57
95
  if(interrupted_by_signal){
58
96
    return;
105
143
    proc_dir = opendir("/proc");
106
144
    if(proc_dir == NULL){
107
145
      int e = errno;
108
 
      perror("opendir");
 
146
      error_plus(0, errno, "opendir");
109
147
      switch(e){
110
148
      case EACCES:
111
149
      case ENOTDIR:
147
185
        char *exe_link;
148
186
        ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
149
187
        if(ret == -1){
150
 
          perror("asprintf");
 
188
          error_plus(0, errno, "asprintf");
151
189
          exitstatus = EX_OSERR;
152
190
          goto failure;
153
191
        }
161
199
            continue;
162
200
          }
163
201
          int e = errno;
164
 
          perror("lstat");
 
202
          error_plus(0, errno, "lstat");
165
203
          free(exe_link);
166
204
          switch(e){
167
205
          case EACCES:
209
247
    sigemptyset(&new_action.sa_mask);
210
248
    ret = sigaddset(&new_action.sa_mask, SIGINT);
211
249
    if(ret == -1){
212
 
      perror("sigaddset");
 
250
      error_plus(0, errno, "sigaddset");
213
251
      exitstatus = EX_OSERR;
214
252
      goto failure;
215
253
    }
216
254
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
217
255
    if(ret == -1){
218
 
      perror("sigaddset");
 
256
      error_plus(0, errno, "sigaddset");
219
257
      exitstatus = EX_OSERR;
220
258
      goto failure;
221
259
    }
222
260
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
223
261
    if(ret == -1){
224
 
      perror("sigaddset");
 
262
      error_plus(0, errno, "sigaddset");
225
263
      exitstatus = EX_OSERR;
226
264
      goto failure;
227
265
    }
228
266
    ret = sigaction(SIGINT, NULL, &old_action);
229
267
    if(ret == -1){
230
 
      perror("sigaction");
 
268
      error_plus(0, errno, "sigaction");
231
269
      exitstatus = EX_OSERR;
232
270
      goto failure;
233
271
    }
234
272
    if(old_action.sa_handler != SIG_IGN){
235
273
      ret = sigaction(SIGINT, &new_action, NULL);
236
274
      if(ret == -1){
237
 
        perror("sigaction");
 
275
        error_plus(0, errno, "sigaction");
238
276
        exitstatus = EX_OSERR;
239
277
        goto failure;
240
278
      }
241
279
    }
242
280
    ret = sigaction(SIGHUP, NULL, &old_action);
243
281
    if(ret == -1){
244
 
      perror("sigaction");
 
282
      error_plus(0, errno, "sigaction");
245
283
      exitstatus = EX_OSERR;
246
284
      goto failure;
247
285
    }
248
286
    if(old_action.sa_handler != SIG_IGN){
249
287
      ret = sigaction(SIGHUP, &new_action, NULL);
250
288
      if(ret == -1){
251
 
        perror("sigaction");
 
289
        error_plus(0, errno, "sigaction");
252
290
        exitstatus = EX_OSERR;
253
291
        goto failure;
254
292
      }
255
293
    }
256
294
    ret = sigaction(SIGTERM, NULL, &old_action);
257
295
    if(ret == -1){
258
 
      perror("sigaction");
 
296
      error_plus(0, errno, "sigaction");
259
297
      exitstatus = EX_OSERR;
260
298
      goto failure;
261
299
    }
262
300
    if(old_action.sa_handler != SIG_IGN){
263
301
      ret = sigaction(SIGTERM, &new_action, NULL);
264
302
      if(ret == -1){
265
 
        perror("sigaction");
 
303
        error_plus(0, errno, "sigaction");
266
304
        exitstatus = EX_OSERR;
267
305
        goto failure;
268
306
      }
279
317
    goto failure;
280
318
  }
281
319
  if(splashy_command_pid == -1){
282
 
    perror("fork");
 
320
    error_plus(0, errno, "fork");
283
321
    exitstatus = EX_OSERR;
284
322
    goto failure;
285
323
  }
288
326
    if(not interrupted_by_signal){
289
327
      const char splashy_command[] = "/sbin/splashy_update";
290
328
      execl(splashy_command, splashy_command, prompt, (char *)NULL);
291
 
      perror("execl");
 
329
      int e = errno;
 
330
      error_plus(0, errno, "execl");
 
331
      switch(e){
 
332
      case EACCES:
 
333
      case ENOENT:
 
334
      case ENOEXEC:
 
335
      case EINVAL:
 
336
        _exit(EX_UNAVAILABLE);
 
337
      case ENAMETOOLONG:
 
338
      case E2BIG:
 
339
      case ENOMEM:
 
340
      case EFAULT:
 
341
      case EIO:
 
342
      case EMFILE:
 
343
      case ENFILE:
 
344
      case ETXTBSY:
 
345
      default:
 
346
        _exit(EX_OSERR);
 
347
      case ENOTDIR:
 
348
      case ELOOP:
 
349
      case EISDIR:
 
350
#ifdef ELIBBAD
 
351
      case ELIBBAD:             /* Linux only */
 
352
#endif
 
353
      case EPERM:
 
354
        _exit(EX_OSFILE);
 
355
      }
292
356
    }
293
357
    free(prompt);
294
358
    _exit(EXIT_FAILURE);
313
377
      goto failure;
314
378
    }
315
379
    if(ret == -1){
316
 
      perror("waitpid");
 
380
      error_plus(0, errno, "waitpid");
317
381
      if(errno == ECHILD){
318
382
        splashy_command_pid = 0;
319
383
      }
351
415
         the real user ID (_mandos) */
352
416
      ret = setuid(geteuid());
353
417
      if(ret == -1){
354
 
        perror("setuid");
 
418
        error_plus(0, errno, "setuid");
355
419
      }
356
420
      
357
421
      setsid();
358
422
      ret = chdir("/");
359
423
      if(ret == -1){
360
 
        perror("chdir");
 
424
        error_plus(0, errno, "chdir");
361
425
      }
362
426
/*       if(fork() != 0){ */
363
427
/*      _exit(EXIT_SUCCESS); */
364
428
/*       } */
365
429
      ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace stdout */
366
430
      if(ret == -1){
367
 
        perror("dup2");
 
431
        error_plus(0, errno, "dup2");
368
432
        _exit(EX_OSERR);
369
433
      }
370
434
      
371
435
      execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
372
436
      {
373
437
        int e = errno;
374
 
        perror("execl");
 
438
        error_plus(0, errno, "execl");
375
439
        switch(e){
376
440
        case EACCES:
377
441
        case ENOENT:
397
461
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
398
462
                                            &signal_action, NULL));
399
463
    if(ret == -1){
400
 
      perror("sigaction");
 
464
      error_plus(0, errno, "sigaction");
401
465
    }
402
466
    do {
403
467
      ret = raise(signal_received);
404
468
    } while(ret != 0 and errno == EINTR);
405
469
    if(ret != 0){
406
 
      perror("raise");
 
470
      error_plus(0, errno, "raise");
407
471
      abort();
408
472
    }
409
473
    TEMP_FAILURE_RETRY(pause());