/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: 2019-08-02 22:16:53 UTC
  • Revision ID: teddy@recompile.se-20190802221653-ic1iko9hbefzwsk7
Fix bug in server Debian package: Fails to start on first install

There has been a very long-standing bug where installation of the
server (the "mandos" Debian package) would fail to start the server
properly right after installation.  It would work on manual (re)start
after installation, or after reboot, and even after package purge and
reinstall, it would then work the first time.  The problem, it turns
out, is when the new "_mandos" user (and corresponding group) is
created, the D-Bus server is not reloaded, and is therefore not aware
of that user, and does not recognize the user and group name in the
/etc/dbus-1/system.d/mandos.conf file.  The Mandos server, when it
tries to start and access the D-Bus, is then not permitted to connect
to its D-Bus bus name, and disables D-Bus use as a fallback measure;
i.e. the server works, but it is not controllable via D-Bus commands
(via mandos-ctl or mandos-monitor).  The next time the D-Bus daemon is
reloaded for any reason, the new user & group would become visible to
the D-Bus daemon and after that, any restart of the Mandos server
would succeed and it would bind to its D-Bus name properly, and
thereby be visible and controllable by mandos-ctl & mandos-monitor.
This was mostly invisible when using sysvinit, but systemd makes the
problem visible since the systemd service file for the Mandos server
is configured to not consider the Mandos server "started" until the
D-Bus name has been bound; this makes the starting of the service wait
for 90 seconds and then fail with a timeout error.

Fixing this should also make the Debian CI autopkgtest tests work.

* debian/mandos.postinst (configure): After creating (or renaming)
                                      user & group, reload D-Bus
                                      daemon (if present).

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 Teddy Hogeborn
 
6
 * Copyright © 2008-2018 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
26
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
29
30
                                   SIG_IGN, kill(), SIGKILL */
30
31
#include <stddef.h>             /* NULL */
31
32
#include <stdlib.h>             /* getenv() */
32
 
#include <stdio.h>              /* asprintf() */
 
33
#include <stdio.h>              /* asprintf(), vasprintf(), vprintf(),
 
34
                                   fprintf() */
33
35
#include <stdlib.h>             /* EXIT_FAILURE, free(),
34
36
                                   EXIT_SUCCESS */
35
37
#include <sys/types.h>          /* pid_t, DIR, struct dirent,
42
44
                                   sleep(), dup2() STDERR_FILENO,
43
45
                                   STDOUT_FILENO, _exit(),
44
46
                                   pause() */
45
 
#include <string.h>             /* memcmp() */
 
47
#include <string.h>             /* memcmp(), strerror() */
46
48
#include <errno.h>              /* errno, EACCES, ENOTDIR, ELOOP,
47
49
                                   ENOENT, ENAMETOOLONG, EMFILE,
48
50
                                   ENFILE, ENOMEM, ENOEXEC, EINVAL,
54
56
                                   WEXITSTATUS() */
55
57
#include <sysexits.h>           /* EX_OSERR, EX_OSFILE,
56
58
                                   EX_UNAVAILABLE */
 
59
#include <stdarg.h>             /* va_list, va_start(), ... */
57
60
 
58
61
sig_atomic_t interrupted_by_signal = 0;
59
62
int signal_received;
60
63
 
 
64
/* Function to use when printing errors */
 
65
__attribute__((format (gnu_printf, 3, 4)))
 
66
void error_plus(int status, int errnum, const char *formatstring,
 
67
                ...){
 
68
  va_list ap;
 
69
  char *text;
 
70
  int ret;
 
71
  
 
72
  va_start(ap, formatstring);
 
73
  ret = vasprintf(&text, formatstring, ap);
 
74
  if(ret == -1){
 
75
    fprintf(stderr, "Mandos plugin %s: ",
 
76
            program_invocation_short_name);
 
77
    vfprintf(stderr, formatstring, ap);
 
78
    fprintf(stderr, ": ");
 
79
    fprintf(stderr, "%s\n", strerror(errnum));
 
80
    error(status, errno, "vasprintf while printing error");
 
81
    return;
 
82
  }
 
83
  fprintf(stderr, "Mandos plugin ");
 
84
  error(status, errnum, "%s", text);
 
85
  free(text);
 
86
}
 
87
 
 
88
 
61
89
static void termination_handler(int signum){
62
90
  if(interrupted_by_signal){
63
91
    return;
110
138
    proc_dir = opendir("/proc");
111
139
    if(proc_dir == NULL){
112
140
      int e = errno;
113
 
      error(0, errno, "opendir");
 
141
      error_plus(0, errno, "opendir");
114
142
      switch(e){
115
143
      case EACCES:
116
144
      case ENOTDIR:
152
180
        char *exe_link;
153
181
        ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
154
182
        if(ret == -1){
155
 
          error(0, errno, "asprintf");
 
183
          error_plus(0, errno, "asprintf");
156
184
          exitstatus = EX_OSERR;
157
185
          goto failure;
158
186
        }
166
194
            continue;
167
195
          }
168
196
          int e = errno;
169
 
          error(0, errno, "lstat");
 
197
          error_plus(0, errno, "lstat");
170
198
          free(exe_link);
171
199
          switch(e){
172
200
          case EACCES:
214
242
    sigemptyset(&new_action.sa_mask);
215
243
    ret = sigaddset(&new_action.sa_mask, SIGINT);
216
244
    if(ret == -1){
217
 
      error(0, errno, "sigaddset");
 
245
      error_plus(0, errno, "sigaddset");
218
246
      exitstatus = EX_OSERR;
219
247
      goto failure;
220
248
    }
221
249
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
222
250
    if(ret == -1){
223
 
      error(0, errno, "sigaddset");
 
251
      error_plus(0, errno, "sigaddset");
224
252
      exitstatus = EX_OSERR;
225
253
      goto failure;
226
254
    }
227
255
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
228
256
    if(ret == -1){
229
 
      error(0, errno, "sigaddset");
 
257
      error_plus(0, errno, "sigaddset");
230
258
      exitstatus = EX_OSERR;
231
259
      goto failure;
232
260
    }
233
261
    ret = sigaction(SIGINT, NULL, &old_action);
234
262
    if(ret == -1){
235
 
      error(0, errno, "sigaction");
 
263
      error_plus(0, errno, "sigaction");
236
264
      exitstatus = EX_OSERR;
237
265
      goto failure;
238
266
    }
239
267
    if(old_action.sa_handler != SIG_IGN){
240
268
      ret = sigaction(SIGINT, &new_action, NULL);
241
269
      if(ret == -1){
242
 
        error(0, errno, "sigaction");
 
270
        error_plus(0, errno, "sigaction");
243
271
        exitstatus = EX_OSERR;
244
272
        goto failure;
245
273
      }
246
274
    }
247
275
    ret = sigaction(SIGHUP, NULL, &old_action);
248
276
    if(ret == -1){
249
 
      error(0, errno, "sigaction");
 
277
      error_plus(0, errno, "sigaction");
250
278
      exitstatus = EX_OSERR;
251
279
      goto failure;
252
280
    }
253
281
    if(old_action.sa_handler != SIG_IGN){
254
282
      ret = sigaction(SIGHUP, &new_action, NULL);
255
283
      if(ret == -1){
256
 
        error(0, errno, "sigaction");
 
284
        error_plus(0, errno, "sigaction");
257
285
        exitstatus = EX_OSERR;
258
286
        goto failure;
259
287
      }
260
288
    }
261
289
    ret = sigaction(SIGTERM, NULL, &old_action);
262
290
    if(ret == -1){
263
 
      error(0, errno, "sigaction");
 
291
      error_plus(0, errno, "sigaction");
264
292
      exitstatus = EX_OSERR;
265
293
      goto failure;
266
294
    }
267
295
    if(old_action.sa_handler != SIG_IGN){
268
296
      ret = sigaction(SIGTERM, &new_action, NULL);
269
297
      if(ret == -1){
270
 
        error(0, errno, "sigaction");
 
298
        error_plus(0, errno, "sigaction");
271
299
        exitstatus = EX_OSERR;
272
300
        goto failure;
273
301
      }
284
312
    goto failure;
285
313
  }
286
314
  if(splashy_command_pid == -1){
287
 
    error(0, errno, "fork");
 
315
    error_plus(0, errno, "fork");
288
316
    exitstatus = EX_OSERR;
289
317
    goto failure;
290
318
  }
294
322
      const char splashy_command[] = "/sbin/splashy_update";
295
323
      execl(splashy_command, splashy_command, prompt, (char *)NULL);
296
324
      int e = errno;
297
 
      error(0, errno, "execl");
 
325
      error_plus(0, errno, "execl");
298
326
      switch(e){
299
327
      case EACCES:
300
328
      case ENOENT:
314
342
      case ENOTDIR:
315
343
      case ELOOP:
316
344
      case EISDIR:
317
 
      case ELIBBAD:
 
345
#ifdef ELIBBAD
 
346
      case ELIBBAD:             /* Linux only */
 
347
#endif
318
348
      case EPERM:
319
349
        _exit(EX_OSFILE);
320
350
      }
342
372
      goto failure;
343
373
    }
344
374
    if(ret == -1){
345
 
      error(0, errno, "waitpid");
 
375
      error_plus(0, errno, "waitpid");
346
376
      if(errno == ECHILD){
347
377
        splashy_command_pid = 0;
348
378
      }
380
410
         the real user ID (_mandos) */
381
411
      ret = setuid(geteuid());
382
412
      if(ret == -1){
383
 
        error(0, errno, "setuid");
 
413
        error_plus(0, errno, "setuid");
384
414
      }
385
415
      
386
416
      setsid();
387
417
      ret = chdir("/");
388
418
      if(ret == -1){
389
 
        error(0, errno, "chdir");
 
419
        error_plus(0, errno, "chdir");
390
420
      }
391
421
/*       if(fork() != 0){ */
392
422
/*      _exit(EXIT_SUCCESS); */
393
423
/*       } */
394
424
      ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace stdout */
395
425
      if(ret == -1){
396
 
        error(0, errno, "dup2");
 
426
        error_plus(0, errno, "dup2");
397
427
        _exit(EX_OSERR);
398
428
      }
399
429
      
400
430
      execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
401
431
      {
402
432
        int e = errno;
403
 
        error(0, errno, "execl");
 
433
        error_plus(0, errno, "execl");
404
434
        switch(e){
405
435
        case EACCES:
406
436
        case ENOENT:
426
456
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
427
457
                                            &signal_action, NULL));
428
458
    if(ret == -1){
429
 
      error(0, errno, "sigaction");
 
459
      error_plus(0, errno, "sigaction");
430
460
    }
431
461
    do {
432
462
      ret = raise(signal_received);
433
463
    } while(ret != 0 and errno == EINTR);
434
464
    if(ret != 0){
435
 
      error(0, errno, "raise");
 
465
      error_plus(0, errno, "raise");
436
466
      abort();
437
467
    }
438
468
    TEMP_FAILURE_RETRY(pause());