/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-02-09 23:23:26 UTC
  • Revision ID: teddy@recompile.se-20190209232326-z1z2kzpgfixz7iaj
Add support for using raw public keys in TLS (RFC 7250)

Since GnuTLS removed support for OpenPGP keys in TLS (RFC 6091), and
no other library supports it, we have to change the protocol to use
something else.  We choose to use "raw public keys" (RFC 7250).  Since
we still use OpenPGP keys to decrypt the secret password, this means
that each client will have two keys: One OpenPGP key and one TLS
public/private key, and the key ID of the latter key is used to
identify clients instead of the fingerprint of the OpenPGP key.

Note that this code is still compatible with GnuTLS before version
3.6.0 (when OpenPGP key support was removed).  This commit merely adds
support for using raw pulic keys instead with GnuTLS 3.6.6. or later.

* DBUS-API (Signals/ClientNotFound): Change name of first parameter
                                     from "Fingerprint" to "KeyID".
  (Mandos Client Interface/Properties/KeyID): New.
* INSTALL: Document conflict with GnuTLS 3.6.0 (which removed OpenPGP
           key support) up until 3.6.6, when support for raw public
           keys was added.  Also document new dependency of client on
           "gnutls-bin" package (for certtool).
* Makefile (run-client): Depend on TLS key files, and also pass them
                         as arguments to client.
  (keydir/tls-privkey.pem, keydir/tls-pubkey.pem): New.
  (confdir/clients.conf): Add dependency on TLS public key.
  (purge-client): Add removal of TLS key files.
* clients.conf ([foo]/key_id, [bar]/key_id): New.
* debian/control (Source: mandos/Build-Depends): Also allow
                                                 libgnutls30 (>= 3.6.6)
  (Package: mandos/Depends): - '' -
  (Package: mandos/Description): Alter description to match new
                                 design.
  (Package: mandos-client/Description): - '' -
  (Package: mandos-client/Depends): Move "gnutls-bin | openssl" to
                                    here from "Recommends".
* debian/mandos-client.README.Debian: Add --tls-privkey and
                                      --tls-pubkey options to test
                                      command.
* debian/mandos-client.postinst (create_key): Renamed to "create_keys"
                                             (all callers changed),
                                             and also create TLS key.
* debian/mandos-client.postrm (purge): Also remove TLS key files.
* intro.xml (DESCRIPTION): Describe new dual-key design.
* mandos (GnuTLS): Define different functions depending on whether
                   support for raw public keys is detected.
  (Client.key_id): New attribute.
  (ClientDBus.KeyID_dbus_property): New method.
  (ProxyClient.__init__): Take new "key_id" parameter.
  (ClientHandler.handle): Use key IDs when using raw public keys and
                          use fingerprints when using OpenPGP keys.
  (ClientHandler.peer_certificate): Also handle raw public keys.
  (ClientHandler.key_id): New.
  (MandosServer.handle_ipc): Pass key ID over the pipe IPC.  Also
                             check for key ID matches when looking up
                             clients.
  (main): Default GnuTLS priority string depends on whether we are
          using raw public keys or not.  When unpickling clients, set
          key_id if not set in the pickle.
  (main/MandosDBusService.ClientNotFound): Change name of first
                                           parameter from
                                           "Fingerprint" to "KeyID".
* mandos-clients.conf.xml (OPTIONS): Document new "key_id" option.
  (OPTIONS/secret): Mention new key ID matchning.
  (EXPANSION/RUNTIME EXPANSION): Add new "key_id" option.
  (EXAMPLE): - '' -
* mandos-ctl (tablewords, main/keywords): Add new "KeyID" property.
* mandos-keygen: Create TLS key files.  New "--tls-keytype" (-T)
                 option.  Alter help text to be more clear about key
                 types.  When in password mode, also output "key_id"
                 option.
* mandos-keygen.xml (SYNOPSIS): Add new "--tls-keytype" (-T) option.
  (DESCRIPTION): Alter to match new dual-key design.
  (OVERVIEW): - '' -
  (FILES): Add TLS key files.
* mandos-options.xml (priority): Document new default priority string
                                 when using raw public keys.
* mandos.xml (NETWORK PROTOCOL): Describe new protocol using key ID.
  (BUGS): Remove issue about checking expire times of OpenPGP keys,
          since TLS public keys do not have expiration times.
  (SECURITY/CLIENT): Alter description to match new design.
  (SEE ALSO/GnuTLS): - '' -
  (SEE ALSO): Add reference to RFC 7250, and alter description of when
              RFC 6091 is used.
* overview.xml: Alter text to match new design.
* plugin-runner.xml (EXAMPLE): Add --tls-pubkey and --tls-privkey
                               options to mandos-client options.
* plugins.d/mandos-client.c: Use raw public keys when compiling with
                             supporting GnuTLS versions. Add new
                             "--tls-pubkey" and "--tls-privkey"
                             options (which do nothing if GnuTLS
                             library does not support raw public
                             keys).  Alter text throughout to reflect
                             new design.  Only generate new DH
                             parameters (based on size of OpenPGP key)
                             when using OpenPGP in TLS.  Default
                             GnuTLS priority string depends on whether
                             we are using raw public keys or not.
* plugins.d/mandos-client.xml (SYNOPSIS): Add new "--tls-privkey" (-t)
                                          and "--tls-pubkey" (-T)
                                          options.
  (DESCRIPTION): Describe new dual-key design.
  (OPTIONS): Document new "--tls-privkey" (-t) and "--tls-pubkey" (-T)
             options.
  (OPTIONS/--dh-bits): No longer necessarily depends on OpenPGP key
                       size.
  (FILES): Add default locations for TLS public and private key files.
  (EXAMPLE): Use new --tls-pubkey and --tls-privkey options.
  (SECURITY): Alter wording slightly to reflect new dual-key design.
  (SEE ALSO/GnuTLS): Alter description to match new design.
  (SEE ALSO): Add reference to RFC 7250, and alter description of when
              RFC 6091 is used.

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-2011 Teddy Hogeborn
6
 
 * Copyright © 2008-2011 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:
344
372
      goto failure;
345
373
    }
346
374
    if(ret == -1){
347
 
      error(0, errno, "waitpid");
 
375
      error_plus(0, errno, "waitpid");
348
376
      if(errno == ECHILD){
349
377
        splashy_command_pid = 0;
350
378
      }
382
410
         the real user ID (_mandos) */
383
411
      ret = setuid(geteuid());
384
412
      if(ret == -1){
385
 
        error(0, errno, "setuid");
 
413
        error_plus(0, errno, "setuid");
386
414
      }
387
415
      
388
416
      setsid();
389
417
      ret = chdir("/");
390
418
      if(ret == -1){
391
 
        error(0, errno, "chdir");
 
419
        error_plus(0, errno, "chdir");
392
420
      }
393
421
/*       if(fork() != 0){ */
394
422
/*      _exit(EXIT_SUCCESS); */
395
423
/*       } */
396
424
      ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace stdout */
397
425
      if(ret == -1){
398
 
        error(0, errno, "dup2");
 
426
        error_plus(0, errno, "dup2");
399
427
        _exit(EX_OSERR);
400
428
      }
401
429
      
402
430
      execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
403
431
      {
404
432
        int e = errno;
405
 
        error(0, errno, "execl");
 
433
        error_plus(0, errno, "execl");
406
434
        switch(e){
407
435
        case EACCES:
408
436
        case ENOENT:
428
456
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
429
457
                                            &signal_action, NULL));
430
458
    if(ret == -1){
431
 
      error(0, errno, "sigaction");
 
459
      error_plus(0, errno, "sigaction");
432
460
    }
433
461
    do {
434
462
      ret = raise(signal_received);
435
463
    } while(ret != 0 and errno == EINTR);
436
464
    if(ret != 0){
437
 
      error(0, errno, "raise");
 
465
      error_plus(0, errno, "raise");
438
466
      abort();
439
467
    }
440
468
    TEMP_FAILURE_RETRY(pause());