/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/mandos-client.c

  • Committer: Teddy Hogeborn
  • Date: 2021-02-03 23:10:42 UTC
  • mto: This revision was merged to the branch mainline in revision 406.
  • 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:
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
11
 * Everything else is
12
 
 * Copyright © 2008-2016 Teddy Hogeborn
13
 
 * Copyright © 2008-2016 Björn Påhlsson
14
 
 * 
15
 
 * This program is free software: you can redistribute it and/or
16
 
 * modify it under the terms of the GNU General Public License as
17
 
 * published by the Free Software Foundation, either version 3 of the
18
 
 * License, or (at your option) any later version.
19
 
 * 
20
 
 * This program is distributed in the hope that it will be useful, but
 
12
 * Copyright © 2008-2021 Teddy Hogeborn
 
13
 * Copyright © 2008-2021 Björn Påhlsson
 
14
 * 
 
15
 * This file is part of Mandos.
 
16
 * 
 
17
 * Mandos is free software: you can redistribute it and/or modify it
 
18
 * under the terms of the GNU General Public License as published by
 
19
 * the Free Software Foundation, either version 3 of the License, or
 
20
 * (at your option) any later version.
 
21
 * 
 
22
 * Mandos is distributed in the hope that it will be useful, but
21
23
 * WITHOUT ANY WARRANTY; without even the implied warranty of
22
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23
25
 * General Public License for more details.
24
26
 * 
25
27
 * You should have received a copy of the GNU General Public License
26
 
 * along with this program.  If not, see
27
 
 * <http://www.gnu.org/licenses/>.
 
28
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
28
29
 * 
29
30
 * Contact the authors at <mandos@recompile.se>.
30
31
 */
37
38
#define _FILE_OFFSET_BITS 64
38
39
#endif  /* not _FILE_OFFSET_BITS */
39
40
 
40
 
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
41
 
 
42
 
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
43
 
                                   stdout, ferror() */
44
 
#include <stdint.h>             /* uint16_t, uint32_t, intptr_t */
45
 
#include <stddef.h>             /* NULL, size_t, ssize_t */
46
 
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
47
 
                                   strtof(), abort() */
 
41
#define _GNU_SOURCE             /* program_invocation_short_name,
 
42
                                   TEMP_FAILURE_RETRY(), O_CLOEXEC,
 
43
                                   scandirat(), asprintf() */
48
44
#include <stdbool.h>            /* bool, false, true */
49
 
#include <string.h>             /* strcmp(), strlen(), strerror(),
50
 
                                   asprintf(), strncpy() */
51
 
#include <sys/ioctl.h>          /* ioctl */
52
 
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
53
 
                                   sockaddr_in6, PF_INET6,
54
 
                                   SOCK_STREAM, uid_t, gid_t, open(),
55
 
                                   opendir(), DIR */
56
 
#include <sys/stat.h>           /* open(), S_ISREG */
57
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
58
 
                                   inet_pton(), connect(),
59
 
                                   getnameinfo() */
60
 
#include <fcntl.h>              /* open(), unlinkat(), AT_REMOVEDIR */
61
 
#include <dirent.h>             /* opendir(), struct dirent, readdir()
62
 
                                 */
63
 
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
64
 
                                   strtoimax() */
65
 
#include <errno.h>              /* perror(), errno, EINTR, EINVAL,
66
 
                                   EAI_SYSTEM, ENETUNREACH,
 
45
#include <argp.h>               /* argp_program_version,
 
46
                                   argp_program_bug_address,
 
47
                                   struct argp_option,
 
48
                                   struct argp_state, argp_error(),
 
49
                                   argp_state_help,
 
50
                                   ARGP_HELP_STD_HELP,
 
51
                                   ARGP_HELP_EXIT_ERR,
 
52
                                   ARGP_HELP_EXIT_OK, ARGP_HELP_USAGE,
 
53
                                   argp_err_exit_status,
 
54
                                   ARGP_ERR_UNKNOWN, struct argp,
 
55
                                   argp_parse(), ARGP_IN_ORDER,
 
56
                                   ARGP_NO_HELP */
 
57
#include <stddef.h>             /* NULL, size_t */
 
58
#include <sys/types.h>          /* uid_t, gid_t, sig_atomic_t,
 
59
                                   seteuid(), setuid(), pid_t,
 
60
                                   setgid(), getuid(), getgid() */
 
61
#include <unistd.h>             /* uid_t, gid_t, TEMP_FAILURE_RETRY(),
 
62
                                   seteuid(), setuid(), close(),
 
63
                                   ssize_t, read(), fork(), setgid(),
 
64
                                   _exit(), dup2(), STDIN_FILENO,
 
65
                                   STDERR_FILENO, STDOUT_FILENO,
 
66
                                   fexecve(), write(), getuid(),
 
67
                                   getgid(), fchown(), symlink(),
 
68
                                   sleep(), unlinkat(), pause() */
 
69
#include <netinet/in.h>         /* in_port_t, struct sockaddr_in6,
 
70
                                   sa_family_t, struct sockaddr_in,
 
71
                                   htons(), IN6_IS_ADDR_LINKLOCAL,
 
72
                                   INET_ADDRSTRLEN, INET6_ADDRSTRLEN,
 
73
                                   ntohl(), IPPROTO_IP */
 
74
#include <time.h>               /* struct timespec, clock_gettime(),
 
75
                                   CLOCK_MONOTONIC, time_t, struct tm,
 
76
                                   gmtime_r(), clock_settime(),
 
77
                                   CLOCK_REALTIME, nanosleep() */
 
78
#include <errno.h>              /* errno,
 
79
                                   program_invocation_short_name,
 
80
                                   EINTR, EINVAL, ENETUNREACH,
67
81
                                   EHOSTUNREACH, ECONNREFUSED, EPROTO,
68
 
                                   EIO, ENOENT, ENXIO, ENOMEM, EISDIR,
69
 
                                   ENOTEMPTY,
70
 
                                   program_invocation_short_name */
71
 
#include <time.h>               /* nanosleep(), time(), sleep() */
72
 
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
73
 
                                   SIOCSIFFLAGS, if_indextoname(),
74
 
                                   if_nametoindex(), IF_NAMESIZE */
75
 
#include <netinet/in.h>         /* IN6_IS_ADDR_LINKLOCAL,
76
 
                                   INET_ADDRSTRLEN, INET6_ADDRSTRLEN
77
 
                                */
78
 
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
79
 
                                   getuid(), getgid(), seteuid(),
80
 
                                   setgid(), pause(), _exit(),
81
 
                                   unlinkat() */
82
 
#include <arpa/inet.h>          /* inet_pton(), htons() */
83
 
#include <iso646.h>             /* not, or, and */
84
 
#include <argp.h>               /* struct argp_option, error_t, struct
85
 
                                   argp_state, struct argp,
86
 
                                   argp_parse(), ARGP_KEY_ARG,
87
 
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
88
 
#include <signal.h>             /* sigemptyset(), sigaddset(),
89
 
                                   sigaction(), SIGTERM, sig_atomic_t,
90
 
                                   raise() */
91
 
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
92
 
                                   EX_NOHOST, EX_IOERR, EX_PROTOCOL */
 
82
                                   EIO, ENOENT, ENXIO, error_t,
 
83
                                   ENOMEM, EISDIR, ENOTEMPTY */
 
84
#include <stdio.h>              /* fprintf(), stderr, perror(), FILE,
 
85
                                   vfprintf(), off_t, SEEK_SET,
 
86
                                   stdout, fwrite(), ferror(),
 
87
                                   fflush(), asprintf() */
 
88
#include <stdarg.h>             /* va_list, va_start(), vfprintf() */
 
89
#include <stdlib.h>             /* realloc(), free(), malloc(),
 
90
                                   getenv(), EXIT_FAILURE, setenv(),
 
91
                                   EXIT_SUCCESS, strtof(), strtod(),
 
92
                                   srand(), mkdtemp(), abort() */
 
93
#include <string.h>             /* strdup(), strcmp(), strlen(),
 
94
                                   strerror(), strncpy(), strspn(),
 
95
                                   memcpy(), strrchr(), strchr(),
 
96
                                   strsignal() */
 
97
#include <fcntl.h>              /* open(), O_RDONLY, O_DIRECTORY,
 
98
                                   O_PATH, O_CLOEXEC, openat(),
 
99
                                   O_NOFOLLOW, AT_REMOVEDIR */
 
100
#include <iso646.h>             /* or, and, not */
 
101
#include <sys/stat.h>           /* struct stat, fstat(), fstatat(),
 
102
                                   S_ISREG(), S_IXUSR, S_IXGRP,
 
103
                                   S_IXOTH, lstat() */
 
104
#include <net/if.h>             /* IF_NAMESIZE, if_indextoname(),
 
105
                                   if_nametoindex(), SIOCGIFFLAGS,
 
106
                                   IFF_LOOPBACK, IFF_POINTOPOINT,
 
107
                                   IFF_BROADCAST, IFF_NOARP, IFF_UP,
 
108
                                   IFF_RUNNING, SIOCSIFFLAGS */
 
109
#include <sysexits.h>           /* EX_NOPERM, EX_OSERR,
 
110
                                   EX_UNAVAILABLE, EX_USAGE */
 
111
#include <grp.h>                /* setgroups() */
93
112
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
94
 
                                   WEXITSTATUS(), WTERMSIG() */
95
 
#include <grp.h>                /* setgroups() */
96
 
#include <argz.h>               /* argz_add_sep(), argz_next(),
97
 
                                   argz_delete(), argz_append(),
98
 
                                   argz_stringify(), argz_add(),
99
 
                                   argz_count() */
 
113
                                   WEXITSTATUS(), WIFSIGNALED(),
 
114
                                   WTERMSIG() */
 
115
#include <signal.h>             /* kill(), SIGTERM, struct sigaction,
 
116
                                   SIG_DFL, sigemptyset(),
 
117
                                   sigaddset(), SIGINT, SIGHUP,
 
118
                                   SIG_IGN, raise() */
 
119
#include <sys/socket.h>         /* struct sockaddr_storage, AF_INET6,
 
120
                                   PF_INET6, AF_INET, PF_INET,
 
121
                                   socket(), SOCK_STREAM,
 
122
                                   SOCK_CLOEXEC, struct sockaddr,
 
123
                                   connect(), SOCK_DGRAM */
 
124
#include <argz.h>               /* argz_next(), argz_add_sep(),
 
125
                                   argz_delete(), argz_stringify(),
 
126
                                   argz_add(), argz_count() */
 
127
#include <inttypes.h>           /* PRIuMAX, uintmax_t, uint32_t,
 
128
                                   PRIdMAX, PRIu16, intmax_t,
 
129
                                   strtoimax() */
 
130
#include <arpa/inet.h>          /* inet_pton() */
 
131
#include <stdint.h>             /* uint32_t, intptr_t, uint16_t */
100
132
#include <netdb.h>              /* getnameinfo(), NI_NUMERICHOST,
101
133
                                   EAI_SYSTEM, gai_strerror() */
 
134
#include <sys/ioctl.h>          /* ioctl() */
 
135
#include <dirent.h>             /* struct dirent, scandirat(),
 
136
                                   alphasort(), scandir() */
 
137
#include <limits.h>             /* INT_MAX */
102
138
 
103
139
#ifdef __linux__
104
140
#include <sys/klog.h>           /* klogctl() */
117
153
 
118
154
/* GnuTLS */
119
155
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and
120
 
                                   functions:
121
 
                                   gnutls_*
122
 
                                   init_gnutls_session(),
123
 
                                   GNUTLS_* */
 
156
                                   functions: gnutls_*, GNUTLS_* */
 
157
#if GNUTLS_VERSION_NUMBER < 0x030600
124
158
#include <gnutls/openpgp.h>
125
159
                         /* gnutls_certificate_set_openpgp_key_file(),
126
160
                            GNUTLS_OPENPGP_FMT_BASE64 */
 
161
#elif GNUTLS_VERSION_NUMBER >= 0x030606
 
162
#include <gnutls/x509.h>        /* GNUTLS_PKCS_PLAIN,
 
163
                                   GNUTLS_PKCS_NULL_PASSWORD */
 
164
#endif
127
165
 
128
166
/* GPGME */
129
167
#include <gpgme.h>              /* All GPGME types, constants and
130
168
                                   functions:
131
 
                                   gpgme_*
132
 
                                   GPGME_PROTOCOL_OpenPGP,
133
 
                                   GPG_ERR_NO_* */
 
169
                                   gpgme_*, GPG_ERR_NO_*,
 
170
                                   GPGME_IMPORT_*
 
171
                                   GPGME_PROTOCOL_OpenPGP */
134
172
 
135
173
#define BUFFER_SIZE 256
136
174
 
137
175
#define PATHDIR "/conf/conf.d/mandos"
138
176
#define SECKEY "seckey.txt"
139
177
#define PUBKEY "pubkey.txt"
 
178
#define TLS_PRIVKEY "tls-privkey.pem"
 
179
#define TLS_PUBKEY "tls-pubkey.pem"
140
180
#define HOOKDIR "/lib/mandos/network-hooks.d"
141
181
 
142
182
bool debug = false;
270
310
  return true;
271
311
}
272
312
 
 
313
/* Set effective uid to 0, return errno */
 
314
__attribute__((warn_unused_result))
 
315
int raise_privileges(void){
 
316
  int old_errno = errno;
 
317
  int ret = 0;
 
318
  if(seteuid(0) == -1){
 
319
    ret = errno;
 
320
  }
 
321
  errno = old_errno;
 
322
  return ret;
 
323
}
 
324
 
 
325
/* Set effective and real user ID to 0.  Return errno. */
 
326
__attribute__((warn_unused_result))
 
327
int raise_privileges_permanently(void){
 
328
  int old_errno = errno;
 
329
  int ret = raise_privileges();
 
330
  if(ret != 0){
 
331
    errno = old_errno;
 
332
    return ret;
 
333
  }
 
334
  if(setuid(0) == -1){
 
335
    ret = errno;
 
336
  }
 
337
  errno = old_errno;
 
338
  return ret;
 
339
}
 
340
 
 
341
/* Set effective user ID to unprivileged saved user ID */
 
342
__attribute__((warn_unused_result))
 
343
int lower_privileges(void){
 
344
  int old_errno = errno;
 
345
  int ret = 0;
 
346
  if(seteuid(uid) == -1){
 
347
    ret = errno;
 
348
  }
 
349
  errno = old_errno;
 
350
  return ret;
 
351
}
 
352
 
 
353
/* Lower privileges permanently */
 
354
__attribute__((warn_unused_result))
 
355
int lower_privileges_permanently(void){
 
356
  int old_errno = errno;
 
357
  int ret = 0;
 
358
  if(setuid(uid) == -1){
 
359
    ret = errno;
 
360
  }
 
361
  errno = old_errno;
 
362
  return ret;
 
363
}
 
364
 
273
365
/* 
274
366
 * Initialize GPGME.
275
367
 */
295
387
      return false;
296
388
    }
297
389
    
 
390
    /* Workaround for systems without a real-time clock; see also
 
391
       Debian bug #894495: <https://bugs.debian.org/894495> */
 
392
    do {
 
393
      {
 
394
        time_t currtime = time(NULL);
 
395
        if(currtime != (time_t)-1){
 
396
          struct tm tm;
 
397
          if(gmtime_r(&currtime, &tm) == NULL) {
 
398
            perror_plus("gmtime_r");
 
399
            break;
 
400
          }
 
401
          if(tm.tm_year != 70 or tm.tm_mon != 0){
 
402
            break;
 
403
          }
 
404
          if(debug){
 
405
            fprintf_plus(stderr, "System clock is January 1970");
 
406
          }
 
407
        } else {
 
408
          if(debug){
 
409
            fprintf_plus(stderr, "System clock is invalid");
 
410
          }
 
411
        }
 
412
      }
 
413
      struct stat keystat;
 
414
      ret = fstat(fd, &keystat);
 
415
      if(ret != 0){
 
416
        perror_plus("fstat");
 
417
        break;
 
418
      }
 
419
      ret = raise_privileges();
 
420
      if(ret != 0){
 
421
        errno = ret;
 
422
        perror_plus("Failed to raise privileges");
 
423
        break;
 
424
      }
 
425
      if(debug){
 
426
        fprintf_plus(stderr,
 
427
                     "Setting system clock to key file mtime");
 
428
      }
 
429
      if(clock_settime(CLOCK_REALTIME, &keystat.st_mtim) != 0){
 
430
        perror_plus("clock_settime");
 
431
      }
 
432
      ret = lower_privileges();
 
433
      if(ret != 0){
 
434
        errno = ret;
 
435
        perror_plus("Failed to lower privileges");
 
436
      }
 
437
    } while(false);
 
438
 
298
439
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
299
440
    if(rc != GPG_ERR_NO_ERROR){
300
441
      fprintf_plus(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
308
449
                   gpgme_strsource(rc), gpgme_strerror(rc));
309
450
      return false;
310
451
    }
 
452
    {
 
453
      gpgme_import_result_t import_result
 
454
        = gpgme_op_import_result(mc->ctx);
 
455
      if((import_result->imported < 1
 
456
          or import_result->not_imported > 0)
 
457
         and import_result->unchanged == 0){
 
458
        fprintf_plus(stderr, "bad gpgme_op_import_results:\n");
 
459
        fprintf_plus(stderr,
 
460
                     "The total number of considered keys: %d\n",
 
461
                     import_result->considered);
 
462
        fprintf_plus(stderr,
 
463
                     "The number of keys without user ID: %d\n",
 
464
                     import_result->no_user_id);
 
465
        fprintf_plus(stderr,
 
466
                     "The total number of imported keys: %d\n",
 
467
                     import_result->imported);
 
468
        fprintf_plus(stderr, "The number of imported RSA keys: %d\n",
 
469
                     import_result->imported_rsa);
 
470
        fprintf_plus(stderr, "The number of unchanged keys: %d\n",
 
471
                     import_result->unchanged);
 
472
        fprintf_plus(stderr, "The number of new user IDs: %d\n",
 
473
                     import_result->new_user_ids);
 
474
        fprintf_plus(stderr, "The number of new sub keys: %d\n",
 
475
                     import_result->new_sub_keys);
 
476
        fprintf_plus(stderr, "The number of new signatures: %d\n",
 
477
                     import_result->new_signatures);
 
478
        fprintf_plus(stderr, "The number of new revocations: %d\n",
 
479
                     import_result->new_revocations);
 
480
        fprintf_plus(stderr,
 
481
                     "The total number of secret keys read: %d\n",
 
482
                     import_result->secret_read);
 
483
        fprintf_plus(stderr,
 
484
                     "The number of imported secret keys: %d\n",
 
485
                     import_result->secret_imported);
 
486
        fprintf_plus(stderr,
 
487
                     "The number of unchanged secret keys: %d\n",
 
488
                     import_result->secret_unchanged);
 
489
        fprintf_plus(stderr, "The number of keys not imported: %d\n",
 
490
                     import_result->not_imported);
 
491
        for(gpgme_import_status_t import_status
 
492
              = import_result->imports;
 
493
            import_status != NULL;
 
494
            import_status = import_status->next){
 
495
          fprintf_plus(stderr, "Import status for key: %s\n",
 
496
                       import_status->fpr);
 
497
          if(import_status->result != GPG_ERR_NO_ERROR){
 
498
            fprintf_plus(stderr, "Import result: %s: %s\n",
 
499
                         gpgme_strsource(import_status->result),
 
500
                         gpgme_strerror(import_status->result));
 
501
          }
 
502
          fprintf_plus(stderr, "Key status:\n");
 
503
          fprintf_plus(stderr,
 
504
                       import_status->status & GPGME_IMPORT_NEW
 
505
                       ? "The key was new.\n"
 
506
                       : "The key was not new.\n");
 
507
          fprintf_plus(stderr,
 
508
                       import_status->status & GPGME_IMPORT_UID
 
509
                       ? "The key contained new user IDs.\n"
 
510
                       : "The key did not contain new user IDs.\n");
 
511
          fprintf_plus(stderr,
 
512
                       import_status->status & GPGME_IMPORT_SIG
 
513
                       ? "The key contained new signatures.\n"
 
514
                       : "The key did not contain new signatures.\n");
 
515
          fprintf_plus(stderr,
 
516
                       import_status->status & GPGME_IMPORT_SUBKEY
 
517
                       ? "The key contained new sub keys.\n"
 
518
                       : "The key did not contain new sub keys.\n");
 
519
          fprintf_plus(stderr,
 
520
                       import_status->status & GPGME_IMPORT_SECRET
 
521
                       ? "The key contained a secret key.\n"
 
522
                       : "The key did not contain a secret key.\n");
 
523
        }
 
524
        return false;
 
525
      }
 
526
    }
311
527
    
312
528
    ret = close(fd);
313
529
    if(ret == -1){
354
570
  /* Create new GPGME "context" */
355
571
  rc = gpgme_new(&(mc->ctx));
356
572
  if(rc != GPG_ERR_NO_ERROR){
357
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
358
 
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
359
 
                 gpgme_strerror(rc));
 
573
    fprintf_plus(stderr, "bad gpgme_new: %s: %s\n",
 
574
                 gpgme_strsource(rc), gpgme_strerror(rc));
360
575
    return false;
361
576
  }
362
577
  
398
613
  /* Create new empty GPGME data buffer for the plaintext */
399
614
  rc = gpgme_data_new(&dh_plain);
400
615
  if(rc != GPG_ERR_NO_ERROR){
401
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
402
 
                 "bad gpgme_data_new: %s: %s\n",
 
616
    fprintf_plus(stderr, "bad gpgme_data_new: %s: %s\n",
403
617
                 gpgme_strsource(rc), gpgme_strerror(rc));
404
618
    gpgme_data_release(dh_crypto);
405
619
    return -1;
418
632
      if(result == NULL){
419
633
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
420
634
      } else {
421
 
        fprintf_plus(stderr, "Unsupported algorithm: %s\n",
422
 
                     result->unsupported_algorithm);
423
 
        fprintf_plus(stderr, "Wrong key usage: %u\n",
424
 
                     result->wrong_key_usage);
 
635
        if(result->unsupported_algorithm != NULL) {
 
636
          fprintf_plus(stderr, "Unsupported algorithm: %s\n",
 
637
                       result->unsupported_algorithm);
 
638
        }
 
639
        fprintf_plus(stderr, "Wrong key usage: %s\n",
 
640
                     result->wrong_key_usage ? "Yes" : "No");
425
641
        if(result->file_name != NULL){
426
642
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
427
643
        }
428
 
        gpgme_recipient_t recipient;
429
 
        recipient = result->recipients;
430
 
        while(recipient != NULL){
 
644
 
 
645
        for(gpgme_recipient_t r = result->recipients; r != NULL;
 
646
            r = r->next){
431
647
          fprintf_plus(stderr, "Public key algorithm: %s\n",
432
 
                       gpgme_pubkey_algo_name
433
 
                       (recipient->pubkey_algo));
434
 
          fprintf_plus(stderr, "Key ID: %s\n", recipient->keyid);
 
648
                       gpgme_pubkey_algo_name(r->pubkey_algo));
 
649
          fprintf_plus(stderr, "Key ID: %s\n", r->keyid);
435
650
          fprintf_plus(stderr, "Secret key available: %s\n",
436
 
                       recipient->status == GPG_ERR_NO_SECKEY
437
 
                       ? "No" : "Yes");
438
 
          recipient = recipient->next;
 
651
                       r->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
439
652
        }
440
653
      }
441
654
    }
523
736
                              const char *dhparamsfilename,
524
737
                              mandos_context *mc){
525
738
  int ret;
526
 
  unsigned int uret;
527
739
  
528
740
  if(debug){
529
741
    fprintf_plus(stderr, "Initializing GnuTLS\n");
546
758
  }
547
759
  
548
760
  if(debug){
549
 
    fprintf_plus(stderr, "Attempting to use OpenPGP public key %s and"
550
 
                 " secret key %s as GnuTLS credentials\n",
 
761
    fprintf_plus(stderr, "Attempting to use public key %s and"
 
762
                 " private key %s as GnuTLS credentials\n",
551
763
                 pubkeyfilename,
552
764
                 seckeyfilename);
553
765
  }
554
766
  
 
767
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
768
  ret = gnutls_certificate_set_rawpk_key_file
 
769
    (mc->cred, pubkeyfilename, seckeyfilename,
 
770
     GNUTLS_X509_FMT_PEM,       /* format */
 
771
     NULL,                      /* pass */
 
772
     /* key_usage */
 
773
     GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 
774
     NULL,                      /* names */
 
775
     0,                         /* names_length */
 
776
     /* privkey_flags */
 
777
     GNUTLS_PKCS_PLAIN | GNUTLS_PKCS_NULL_PASSWORD,
 
778
     0);                        /* pkcs11_flags */
 
779
#elif GNUTLS_VERSION_NUMBER < 0x030600
555
780
  ret = gnutls_certificate_set_openpgp_key_file
556
781
    (mc->cred, pubkeyfilename, seckeyfilename,
557
782
     GNUTLS_OPENPGP_FMT_BASE64);
 
783
#else
 
784
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
785
#endif
558
786
  if(ret != GNUTLS_E_SUCCESS){
559
787
    fprintf_plus(stderr,
560
 
                 "Error[%d] while reading the OpenPGP key pair ('%s',"
 
788
                 "Error[%d] while reading the key pair ('%s',"
561
789
                 " '%s')\n", ret, pubkeyfilename, seckeyfilename);
562
790
    fprintf_plus(stderr, "The GnuTLS error is: %s\n",
563
791
                 safer_gnutls_strerror(ret));
611
839
        }
612
840
        params.size += (unsigned int)bytes_read;
613
841
      }
 
842
      ret = close(dhpfile);
 
843
      if(ret == -1){
 
844
        perror_plus("close");
 
845
      }
614
846
      if(params.data == NULL){
615
847
        dhparamsfilename = NULL;
616
848
      }
625
857
                     safer_gnutls_strerror(ret));
626
858
        dhparamsfilename = NULL;
627
859
      }
 
860
      free(params.data);
628
861
    } while(false);
629
862
  }
630
863
  if(dhparamsfilename == NULL){
631
864
    if(mc->dh_bits == 0){
 
865
#if GNUTLS_VERSION_NUMBER < 0x030600
632
866
      /* Find out the optimal number of DH bits */
633
867
      /* Try to read the private key file */
634
868
      gnutls_datum_t buffer = { .data = NULL, .size = 0 };
714
948
          }
715
949
        }
716
950
      }
717
 
      uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
 
951
      unsigned int uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
718
952
      if(uret != 0){
719
953
        mc->dh_bits = uret;
720
954
        if(debug){
732
966
                     safer_gnutls_strerror(ret));
733
967
        goto globalfail;
734
968
      }
735
 
    } else if(debug){
736
 
      fprintf_plus(stderr, "DH bits explicitly set to %u\n",
737
 
                   mc->dh_bits);
738
 
    }
739
 
    ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
740
 
    if(ret != GNUTLS_E_SUCCESS){
741
 
      fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
742
 
                   " bits): %s\n", mc->dh_bits,
743
 
                   safer_gnutls_strerror(ret));
744
 
      goto globalfail;
 
969
#endif
 
970
    } else {                    /* dh_bits != 0 */
 
971
      if(debug){
 
972
        fprintf_plus(stderr, "DH bits explicitly set to %u\n",
 
973
                     mc->dh_bits);
 
974
      }
 
975
      ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
976
      if(ret != GNUTLS_E_SUCCESS){
 
977
        fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
 
978
                     " bits): %s\n", mc->dh_bits,
 
979
                     safer_gnutls_strerror(ret));
 
980
        goto globalfail;
 
981
      }
 
982
      gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
745
983
    }
746
984
  }
747
 
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
748
985
  
749
986
  return 0;
750
987
  
761
998
  int ret;
762
999
  /* GnuTLS session creation */
763
1000
  do {
764
 
    ret = gnutls_init(session, GNUTLS_SERVER);
 
1001
    ret = gnutls_init(session, (GNUTLS_SERVER
 
1002
#if GNUTLS_VERSION_NUMBER >= 0x030506
 
1003
                                | GNUTLS_NO_TICKETS
 
1004
#endif
 
1005
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
1006
                                | GNUTLS_ENABLE_RAWPK
 
1007
#endif
 
1008
                                ));
765
1009
    if(quit_now){
766
1010
      return -1;
767
1011
    }
815
1059
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
816
1060
                      __attribute__((unused)) const char *txt){}
817
1061
 
818
 
/* Set effective uid to 0, return errno */
819
 
__attribute__((warn_unused_result))
820
 
error_t raise_privileges(void){
821
 
  error_t old_errno = errno;
822
 
  error_t ret_errno = 0;
823
 
  if(seteuid(0) == -1){
824
 
    ret_errno = errno;
825
 
  }
826
 
  errno = old_errno;
827
 
  return ret_errno;
828
 
}
829
 
 
830
 
/* Set effective and real user ID to 0.  Return errno. */
831
 
__attribute__((warn_unused_result))
832
 
error_t raise_privileges_permanently(void){
833
 
  error_t old_errno = errno;
834
 
  error_t ret_errno = raise_privileges();
835
 
  if(ret_errno != 0){
836
 
    errno = old_errno;
837
 
    return ret_errno;
838
 
  }
839
 
  if(setuid(0) == -1){
840
 
    ret_errno = errno;
841
 
  }
842
 
  errno = old_errno;
843
 
  return ret_errno;
844
 
}
845
 
 
846
 
/* Set effective user ID to unprivileged saved user ID */
847
 
__attribute__((warn_unused_result))
848
 
error_t lower_privileges(void){
849
 
  error_t old_errno = errno;
850
 
  error_t ret_errno = 0;
851
 
  if(seteuid(uid) == -1){
852
 
    ret_errno = errno;
853
 
  }
854
 
  errno = old_errno;
855
 
  return ret_errno;
856
 
}
857
 
 
858
 
/* Lower privileges permanently */
859
 
__attribute__((warn_unused_result))
860
 
error_t lower_privileges_permanently(void){
861
 
  error_t old_errno = errno;
862
 
  error_t ret_errno = 0;
863
 
  if(setuid(uid) == -1){
864
 
    ret_errno = errno;
865
 
  }
866
 
  errno = old_errno;
867
 
  return ret_errno;
868
 
}
869
 
 
870
1062
/* Helper function to add_local_route() and delete_local_route() */
871
1063
__attribute__((nonnull, warn_unused_result))
872
1064
static bool add_delete_local_route(const bool add,
911
1103
      ret = setgid(0);
912
1104
      if(ret == -1){
913
1105
        perror_plus("setgid");
 
1106
        close(devnull);
914
1107
        _exit(EX_NOPERM);
915
1108
      }
916
1109
      /* Reset supplementary groups */
918
1111
      ret = setgroups(0, NULL);
919
1112
      if(ret == -1){
920
1113
        perror_plus("setgroups");
 
1114
        close(devnull);
921
1115
        _exit(EX_NOPERM);
922
1116
      }
923
1117
    }
924
1118
    ret = dup2(devnull, STDIN_FILENO);
925
1119
    if(ret == -1){
926
1120
      perror_plus("dup2(devnull, STDIN_FILENO)");
 
1121
      close(devnull);
927
1122
      _exit(EX_OSERR);
928
1123
    }
929
1124
    ret = close(devnull);
930
1125
    if(ret == -1){
931
1126
      perror_plus("close");
932
 
      _exit(EX_OSERR);
933
1127
    }
934
1128
    ret = dup2(STDERR_FILENO, STDOUT_FILENO);
935
1129
    if(ret == -1){
970
1164
  }
971
1165
  if(pid == -1){
972
1166
    perror_plus("fork");
 
1167
    close(devnull);
973
1168
    return false;
974
1169
  }
 
1170
  ret = close(devnull);
 
1171
  if(ret == -1){
 
1172
    perror_plus("close");
 
1173
  }
975
1174
  int status;
976
1175
  pid_t pret = -1;
977
1176
  errno = 0;
1077
1276
    bool match = false;
1078
1277
    {
1079
1278
      char *interface = NULL;
1080
 
      while((interface=argz_next(mc->interfaces, mc->interfaces_size,
1081
 
                                 interface))){
 
1279
      while((interface = argz_next(mc->interfaces,
 
1280
                                   mc->interfaces_size,
 
1281
                                   interface))){
1082
1282
        if(if_nametoindex(interface) == (unsigned int)if_index){
1083
1283
          match = true;
1084
1284
          break;
1237
1437
           with an explicit route added with the server's address.
1238
1438
           
1239
1439
           Avahi bug reference:
1240
 
           http://lists.freedesktop.org/archives/avahi/2010-February/001833.html
 
1440
           https://lists.freedesktop.org/archives/avahi/2010-February/001833.html
1241
1441
           https://bugs.debian.org/587961
1242
1442
        */
1243
1443
        if(debug){
1423
1623
                                               &decrypted_buffer, mc);
1424
1624
    if(decrypted_buffer_size >= 0){
1425
1625
      
 
1626
      clearerr(stdout);
1426
1627
      written = 0;
1427
1628
      while(written < (size_t) decrypted_buffer_size){
1428
1629
        if(quit_now){
1444
1645
        }
1445
1646
        written += (size_t)ret;
1446
1647
      }
 
1648
      ret = fflush(stdout);
 
1649
      if(ret != 0){
 
1650
        int e = errno;
 
1651
        if(debug){
 
1652
          fprintf_plus(stderr, "Error writing encrypted data: %s\n",
 
1653
                       strerror(errno));
 
1654
        }
 
1655
        errno = e;
 
1656
        goto mandos_end;
 
1657
      }
1447
1658
      retval = 0;
1448
1659
    }
1449
1660
  }
1480
1691
  return retval;
1481
1692
}
1482
1693
 
1483
 
__attribute__((nonnull))
1484
1694
static void resolve_callback(AvahiSServiceResolver *r,
1485
1695
                             AvahiIfIndex interface,
1486
1696
                             AvahiProtocol proto,
1623
1833
__attribute__((nonnull, warn_unused_result))
1624
1834
bool get_flags(const char *ifname, struct ifreq *ifr){
1625
1835
  int ret;
1626
 
  error_t ret_errno;
 
1836
  int old_errno;
1627
1837
  
1628
1838
  int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1629
1839
  if(s < 0){
1630
 
    ret_errno = errno;
 
1840
    old_errno = errno;
1631
1841
    perror_plus("socket");
1632
 
    errno = ret_errno;
 
1842
    errno = old_errno;
1633
1843
    return false;
1634
1844
  }
1635
1845
  strncpy(ifr->ifr_name, ifname, IF_NAMESIZE);
1637
1847
  ret = ioctl(s, SIOCGIFFLAGS, ifr);
1638
1848
  if(ret == -1){
1639
1849
    if(debug){
1640
 
      ret_errno = errno;
 
1850
      old_errno = errno;
1641
1851
      perror_plus("ioctl SIOCGIFFLAGS");
1642
 
      errno = ret_errno;
 
1852
      errno = old_errno;
 
1853
    }
 
1854
    if((close(s) == -1) and debug){
 
1855
      old_errno = errno;
 
1856
      perror_plus("close");
 
1857
      errno = old_errno;
1643
1858
    }
1644
1859
    return false;
1645
1860
  }
 
1861
  if((close(s) == -1) and debug){
 
1862
    old_errno = errno;
 
1863
    perror_plus("close");
 
1864
    errno = old_errno;
 
1865
  }
1646
1866
  return true;
1647
1867
}
1648
1868
 
1909
2129
      return;
1910
2130
    }
1911
2131
  }
 
2132
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
 
2133
  if(devnull == -1){
 
2134
    perror_plus("open(\"/dev/null\", O_RDONLY)");
 
2135
    return;
 
2136
  }
1912
2137
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
1913
2138
                           runnable_hook, alphasort);
1914
2139
  if(numhooks == -1){
1915
2140
    perror_plus("scandir");
 
2141
    close(devnull);
1916
2142
    return;
1917
2143
  }
1918
2144
  struct dirent *direntry;
1919
2145
  int ret;
1920
 
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
1921
 
  if(devnull == -1){
1922
 
    perror_plus("open(\"/dev/null\", O_RDONLY)");
1923
 
    return;
1924
 
  }
1925
2146
  for(int i = 0; i < numhooks; i++){
1926
2147
    direntry = direntries[i];
1927
2148
    if(debug){
2071
2292
}
2072
2293
 
2073
2294
__attribute__((nonnull, warn_unused_result))
2074
 
error_t bring_up_interface(const char *const interface,
2075
 
                           const float delay){
2076
 
  error_t old_errno = errno;
 
2295
int bring_up_interface(const char *const interface,
 
2296
                       const float delay){
 
2297
  int old_errno = errno;
2077
2298
  int ret;
2078
2299
  struct ifreq network;
2079
2300
  unsigned int if_index = if_nametoindex(interface);
2089
2310
  }
2090
2311
  
2091
2312
  if(not interface_is_up(interface)){
2092
 
    error_t ret_errno = 0, ioctl_errno = 0;
 
2313
    int ret_errno = 0;
 
2314
    int ioctl_errno = 0;
2093
2315
    if(not get_flags(interface, &network)){
2094
2316
      ret_errno = errno;
2095
2317
      fprintf_plus(stderr, "Failed to get flags for interface "
2182
2404
  
2183
2405
  /* Sleep checking until interface is running.
2184
2406
     Check every 0.25s, up to total time of delay */
2185
 
  for(int i=0; i < delay * 4; i++){
 
2407
  for(int i = 0; i < delay * 4; i++){
2186
2408
    if(interface_is_running(interface)){
2187
2409
      break;
2188
2410
    }
2198
2420
}
2199
2421
 
2200
2422
__attribute__((nonnull, warn_unused_result))
2201
 
error_t take_down_interface(const char *const interface){
2202
 
  error_t old_errno = errno;
 
2423
int take_down_interface(const char *const interface){
 
2424
  int old_errno = errno;
2203
2425
  struct ifreq network;
2204
2426
  unsigned int if_index = if_nametoindex(interface);
2205
2427
  if(if_index == 0){
2208
2430
    return ENXIO;
2209
2431
  }
2210
2432
  if(interface_is_up(interface)){
2211
 
    error_t ret_errno = 0, ioctl_errno = 0;
 
2433
    int ret_errno = 0;
 
2434
    int ioctl_errno = 0;
2212
2435
    if(not get_flags(interface, &network) and debug){
2213
2436
      ret_errno = errno;
2214
2437
      fprintf_plus(stderr, "Failed to get flags for interface "
2274
2497
 
2275
2498
int main(int argc, char *argv[]){
2276
2499
  mandos_context mc = { .server = NULL, .dh_bits = 0,
 
2500
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2501
                        .priority = "SECURE128:!CTYPE-X.509"
 
2502
                        ":+CTYPE-RAWPK:!RSA:!VERS-ALL:+VERS-TLS1.3"
 
2503
                        ":%PROFILE_ULTRA",
 
2504
#elif GNUTLS_VERSION_NUMBER < 0x030600
2277
2505
                        .priority = "SECURE256:!CTYPE-X.509"
2278
2506
                        ":+CTYPE-OPENPGP:!RSA:+SIGN-DSA-SHA256",
 
2507
#else
 
2508
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
2509
#endif
2279
2510
                        .current_server = NULL, .interfaces = NULL,
2280
2511
                        .interfaces_size = 0 };
2281
2512
  AvahiSServiceBrowser *sb = NULL;
2292
2523
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
2293
2524
  const char *seckey = PATHDIR "/" SECKEY;
2294
2525
  const char *pubkey = PATHDIR "/" PUBKEY;
 
2526
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2527
  const char *tls_privkey = PATHDIR "/" TLS_PRIVKEY;
 
2528
  const char *tls_pubkey = PATHDIR "/" TLS_PUBKEY;
 
2529
#endif
2295
2530
  const char *dh_params_file = NULL;
2296
2531
  char *interfaces_hooks = NULL;
2297
2532
  
2345
2580
      { .name = "pubkey", .key = 'p',
2346
2581
        .arg = "FILE",
2347
2582
        .doc = "OpenPGP public key file base name",
2348
 
        .group = 2 },
 
2583
        .group = 1 },
 
2584
      { .name = "tls-privkey", .key = 't',
 
2585
        .arg = "FILE",
 
2586
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2587
        .doc = "TLS private key file base name",
 
2588
#else
 
2589
        .doc = "Dummy; ignored (requires GnuTLS 3.6.6)",
 
2590
#endif
 
2591
        .group = 1 },
 
2592
      { .name = "tls-pubkey", .key = 'T',
 
2593
        .arg = "FILE",
 
2594
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2595
        .doc = "TLS public key file base name",
 
2596
#else
 
2597
        .doc = "Dummy; ignored (requires GnuTLS 3.6.6)",
 
2598
#endif
 
2599
        .group = 1 },
2349
2600
      { .name = "dh-bits", .key = 129,
2350
2601
        .arg = "BITS",
2351
2602
        .doc = "Bit length of the prime number used in the"
2407
2658
      case 'p':                 /* --pubkey */
2408
2659
        pubkey = arg;
2409
2660
        break;
 
2661
      case 't':                 /* --tls-privkey */
 
2662
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2663
        tls_privkey = arg;
 
2664
#endif
 
2665
        break;
 
2666
      case 'T':                 /* --tls-pubkey */
 
2667
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2668
        tls_pubkey = arg;
 
2669
#endif
 
2670
        break;
2410
2671
      case 129:                 /* --dh-bits */
2411
2672
        errno = 0;
2412
2673
        tmpmax = strtoimax(arg, &tmp, 10);
2447
2708
        argp_state_help(state, state->out_stream,
2448
2709
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
2449
2710
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
2711
        __builtin_unreachable();
2450
2712
      case -3:                  /* --usage */
2451
2713
        argp_state_help(state, state->out_stream,
2452
2714
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
2715
        __builtin_unreachable();
2453
2716
      case 'V':                 /* --version */
2454
2717
        fprintf_plus(state->out_stream, "%s\n", argp_program_version);
2455
2718
        exit(argp_err_exit_status);
2464
2727
                         .args_doc = "",
2465
2728
                         .doc = "Mandos client -- Get and decrypt"
2466
2729
                         " passwords from a Mandos server" };
2467
 
    ret = argp_parse(&argp, argc, argv,
2468
 
                     ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
2469
 
    switch(ret){
 
2730
    ret_errno = argp_parse(&argp, argc, argv,
 
2731
                           ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
 
2732
    switch(ret_errno){
2470
2733
    case 0:
2471
2734
      break;
2472
2735
    case ENOMEM:
2473
2736
    default:
2474
 
      errno = ret;
 
2737
      errno = ret_errno;
2475
2738
      perror_plus("argp_parse");
2476
2739
      exitcode = EX_OSERR;
2477
2740
      goto end;
2482
2745
  }
2483
2746
  
2484
2747
  {
2485
 
    /* Work around Debian bug #633582:
2486
 
       <http://bugs.debian.org/633582> */
2487
 
    
2488
2748
    /* Re-raise privileges */
2489
 
    ret_errno = raise_privileges();
2490
 
    if(ret_errno != 0){
2491
 
      errno = ret_errno;
 
2749
    ret = raise_privileges();
 
2750
    if(ret != 0){
 
2751
      errno = ret;
2492
2752
      perror_plus("Failed to raise privileges");
2493
2753
    } else {
2494
2754
      struct stat st;
2495
2755
      
 
2756
      /* Work around Debian bug #633582:
 
2757
         <https://bugs.debian.org/633582> */
 
2758
 
2496
2759
      if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
2497
2760
        int seckey_fd = open(seckey, O_RDONLY);
2498
2761
        if(seckey_fd == -1){
2557
2820
        }
2558
2821
      }
2559
2822
      
 
2823
      /* Work around Debian bug #981302
 
2824
         <https://bugs.debian.org/981302> */
 
2825
      if(lstat("/dev/fd", &st) != 0 and errno == ENOENT){
 
2826
        ret = symlink("/proc/self/fd", "/dev/fd");
 
2827
        if(ret == -1){
 
2828
          perror_plus("Failed to create /dev/fd symlink");
 
2829
        }
 
2830
      }
 
2831
 
2560
2832
      /* Lower privileges */
2561
 
      ret_errno = lower_privileges();
2562
 
      if(ret_errno != 0){
2563
 
        errno = ret_errno;
 
2833
      ret = lower_privileges();
 
2834
      if(ret != 0){
 
2835
        errno = ret;
2564
2836
        perror_plus("Failed to lower privileges");
2565
2837
      }
2566
2838
    }
2766
3038
    goto end;
2767
3039
  }
2768
3040
  
 
3041
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
3042
  ret = init_gnutls_global(tls_pubkey, tls_privkey, dh_params_file, &mc);
 
3043
#elif GNUTLS_VERSION_NUMBER < 0x030600
2769
3044
  ret = init_gnutls_global(pubkey, seckey, dh_params_file, &mc);
 
3045
#else
 
3046
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
3047
#endif
2770
3048
  if(ret == -1){
2771
3049
    fprintf_plus(stderr, "init_gnutls_global failed\n");
2772
3050
    exitcode = EX_UNAVAILABLE;
2894
3172
    
2895
3173
    /* Allocate a new server */
2896
3174
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
2897
 
                                 &config, NULL, NULL, &ret_errno);
 
3175
                                 &config, NULL, NULL, &ret);
2898
3176
    
2899
3177
    /* Free the Avahi configuration data */
2900
3178
    avahi_server_config_free(&config);
2903
3181
  /* Check if creating the Avahi server object succeeded */
2904
3182
  if(mc.server == NULL){
2905
3183
    fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
2906
 
                 avahi_strerror(ret_errno));
 
3184
                 avahi_strerror(ret));
2907
3185
    exitcode = EX_UNAVAILABLE;
2908
3186
    goto end;
2909
3187
  }
2944
3222
 end:
2945
3223
  
2946
3224
  if(debug){
2947
 
    fprintf_plus(stderr, "%s exiting\n", argv[0]);
 
3225
    if(signal_received){
 
3226
      fprintf_plus(stderr, "%s exiting due to signal %d: %s\n",
 
3227
                   argv[0], signal_received,
 
3228
                   strsignal(signal_received));
 
3229
    } else {
 
3230
      fprintf_plus(stderr, "%s exiting\n", argv[0]);
 
3231
    }
2948
3232
  }
2949
3233
  
2950
3234
  /* Cleanup things */
2989
3273
  
2990
3274
  /* Re-raise privileges */
2991
3275
  {
2992
 
    ret_errno = raise_privileges();
2993
 
    if(ret_errno != 0){
2994
 
      errno = ret_errno;
 
3276
    ret = raise_privileges();
 
3277
    if(ret != 0){
 
3278
      errno = ret;
2995
3279
      perror_plus("Failed to raise privileges");
2996
3280
    } else {
2997
3281
      
3002
3286
      /* Take down the network interfaces which were brought up */
3003
3287
      {
3004
3288
        char *interface = NULL;
3005
 
        while((interface=argz_next(interfaces_to_take_down,
3006
 
                                   interfaces_to_take_down_size,
3007
 
                                   interface))){
3008
 
          ret_errno = take_down_interface(interface);
3009
 
          if(ret_errno != 0){
3010
 
            errno = ret_errno;
 
3289
        while((interface = argz_next(interfaces_to_take_down,
 
3290
                                     interfaces_to_take_down_size,
 
3291
                                     interface))){
 
3292
          ret = take_down_interface(interface);
 
3293
          if(ret != 0){
 
3294
            errno = ret;
3011
3295
            perror_plus("Failed to take down interface");
3012
3296
          }
3013
3297
        }
3018
3302
      }
3019
3303
    }
3020
3304
    
3021
 
    ret_errno = lower_privileges_permanently();
3022
 
    if(ret_errno != 0){
3023
 
      errno = ret_errno;
 
3305
    ret = lower_privileges_permanently();
 
3306
    if(ret != 0){
 
3307
      errno = ret;
3024
3308
      perror_plus("Failed to lower privileges permanently");
3025
3309
    }
3026
3310
  }
3039
3323
                                                | O_PATH));
3040
3324
    if(dir_fd == -1){
3041
3325
      perror_plus("open");
 
3326
      return;
3042
3327
    }
3043
3328
    int numentries = scandirat(dir_fd, ".", &direntries,
3044
3329
                               notdotentries, alphasort);
3061
3346
            clean_dir_at(dir_fd, direntries[i]->d_name, level+1);
3062
3347
            dret = 0;
3063
3348
          }
3064
 
          if(dret == -1){
 
3349
          if((dret == -1) and (errno != ENOENT)){
3065
3350
            fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
3066
3351
                         direntries[i]->d_name, strerror(errno));
3067
3352
          }
3071
3356
      
3072
3357
      /* need to clean even if 0 because man page doesn't specify */
3073
3358
      free(direntries);
3074
 
      if(numentries == -1){
3075
 
        perror_plus("scandirat");
3076
 
      }
3077
3359
      dret = unlinkat(base, dirname, AT_REMOVEDIR);
3078
3360
      if(dret == -1 and errno != ENOENT){
3079
3361
        perror_plus("rmdir");