/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/mandos-client.c

  • Committer: Teddy Hogeborn
  • Date: 2015-05-23 20:18:34 UTC
  • mto: This revision was merged to the branch mainline in revision 756.
  • Revision ID: teddy@recompile.se-20150523201834-e89ex4ito93yni8x
mandos: Use multiprocessing module to run checkers.

For a long time, the Mandos server has occasionally logged the message
"ERROR: Child process vanished".  This was never a fatal error, but it
has been annoying and slightly worrying, since a definite cause was
not found.  One potential cause could be the "multiprocessing" and
"subprocess" modules conflicting w.r.t. SIGCHLD.  To avoid this,
change the running of checkers from using subprocess.Popen
asynchronously to instead first create a multiprocessing.Process()
(which is asynchronous) calling a function, and have that function
then call subprocess.call() (which is synchronous).  In this way, the
only thing using any asynchronous subprocesses is the multiprocessing
module.

This makes it necessary to change one small thing in the D-Bus API,
since the subprocesses.call() function does not expose the raw wait(2)
status value.

DBUS-API (CheckerCompleted): Change the second value provided by this
                             D-Bus signal from the raw wait(2) status
                             to the actual terminating signal number.
mandos (subprocess_call_pipe): New function to be called by
                               multiprocessing.Process (starting a
                               separate process).
(Client.last_checker signal): New attribute for signal which
                              terminated last checker.  Like
                              last_checker_status, only not accessible
                              via D-Bus.
(Client.checker_callback): Take new "connection" argument and use it
                           to get returncode; set last_checker_signal.
                           Return False so gobject does not call this
                           callback again.
(Client.start_checker): Start checker using a multiprocessing.Process
                        instead of a subprocess.Popen.
(ClientDBus.checker_callback): Take new "connection" argument.        Call
                               Client.checker_callback early to have
                               it set last_checker_status and
                               last_checker_signal; use those.  Change
                               second value provided to D-Bus signal
                               CheckerCompleted to use
                               last_checker_signal if checker was
                               terminated by signal.
mandos-monitor: Update to reflect DBus API change.
(MandosClientWidget.checker_completed): Take "signal" instead of
                                        "condition" argument.  Use it
                                        accordingly.  Remove dead code
                                        (os.WCOREDUMP case).

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,2009 Teddy Hogeborn
13
 
 * Copyright © 2008,2009 Björn Påhlsson
 
12
 * Copyright © 2008-2014 Teddy Hogeborn
 
13
 * Copyright © 2008-2014 Björn Påhlsson
14
14
 * 
15
15
 * This program is free software: you can redistribute it and/or
16
16
 * modify it under the terms of the GNU General Public License as
26
26
 * along with this program.  If not, see
27
27
 * <http://www.gnu.org/licenses/>.
28
28
 * 
29
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
29
 * Contact the authors at <mandos@recompile.se>.
30
30
 */
31
31
 
32
32
/* Needed by GPGME, specifically gpgme_data_seek() */
33
33
#ifndef _LARGEFILE_SOURCE
34
34
#define _LARGEFILE_SOURCE
35
 
#endif
 
35
#endif  /* not _LARGEFILE_SOURCE */
36
36
#ifndef _FILE_OFFSET_BITS
37
37
#define _FILE_OFFSET_BITS 64
38
 
#endif
 
38
#endif  /* not _FILE_OFFSET_BITS */
39
39
 
40
40
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
41
41
 
42
42
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
43
 
                                   stdout, ferror(), remove() */
44
 
#include <stdint.h>             /* uint16_t, uint32_t */
 
43
                                   stdout, ferror() */
 
44
#include <stdint.h>             /* uint16_t, uint32_t, intptr_t */
45
45
#include <stddef.h>             /* NULL, size_t, ssize_t */
46
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
47
47
                                   strtof(), abort() */
53
53
                                   sockaddr_in6, PF_INET6,
54
54
                                   SOCK_STREAM, uid_t, gid_t, open(),
55
55
                                   opendir(), DIR */
56
 
#include <sys/stat.h>           /* open() */
 
56
#include <sys/stat.h>           /* open(), S_ISREG */
57
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
58
 
                                   inet_pton(), connect() */
59
 
#include <fcntl.h>              /* open() */
 
58
                                   inet_pton(), connect(),
 
59
                                   getnameinfo() */
 
60
#include <fcntl.h>              /* open(), unlinkat() */
60
61
#include <dirent.h>             /* opendir(), struct dirent, readdir()
61
62
                                 */
62
63
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
63
64
                                   strtoimax() */
64
 
#include <assert.h>             /* assert() */
65
 
#include <errno.h>              /* perror(), errno */
66
 
#include <time.h>               /* nanosleep(), time() */
 
65
#include <errno.h>              /* perror(), errno,
 
66
                                   program_invocation_short_name */
 
67
#include <time.h>               /* nanosleep(), time(), sleep() */
67
68
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
68
69
                                   SIOCSIFFLAGS, if_indextoname(),
69
70
                                   if_nametoindex(), IF_NAMESIZE */
72
73
                                */
73
74
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
74
75
                                   getuid(), getgid(), seteuid(),
75
 
                                   setgid(), pause() */
76
 
#include <arpa/inet.h>          /* inet_pton(), htons */
 
76
                                   setgid(), pause(), _exit(),
 
77
                                   unlinkat() */
 
78
#include <arpa/inet.h>          /* inet_pton(), htons() */
77
79
#include <iso646.h>             /* not, or, and */
78
80
#include <argp.h>               /* struct argp_option, error_t, struct
79
81
                                   argp_state, struct argp,
84
86
                                   raise() */
85
87
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
86
88
                                   EX_NOHOST, EX_IOERR, EX_PROTOCOL */
 
89
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
 
90
                                   WEXITSTATUS(), WTERMSIG() */
 
91
#include <grp.h>                /* setgroups() */
 
92
#include <argz.h>               /* argz_add_sep(), argz_next(),
 
93
                                   argz_delete(), argz_append(),
 
94
                                   argz_stringify(), argz_add(),
 
95
                                   argz_count() */
 
96
#include <netdb.h>              /* getnameinfo(), NI_NUMERICHOST,
 
97
                                   EAI_SYSTEM, gai_strerror() */
87
98
 
88
99
#ifdef __linux__
89
100
#include <sys/klog.h>           /* klogctl() */
107
118
                                   init_gnutls_session(),
108
119
                                   GNUTLS_* */
109
120
#include <gnutls/openpgp.h>
110
 
                          /* gnutls_certificate_set_openpgp_key_file(),
111
 
                                   GNUTLS_OPENPGP_FMT_BASE64 */
 
121
                         /* gnutls_certificate_set_openpgp_key_file(),
 
122
                            GNUTLS_OPENPGP_FMT_BASE64 */
112
123
 
113
124
/* GPGME */
114
125
#include <gpgme.h>              /* All GPGME types, constants and
122
133
#define PATHDIR "/conf/conf.d/mandos"
123
134
#define SECKEY "seckey.txt"
124
135
#define PUBKEY "pubkey.txt"
 
136
#define HOOKDIR "/lib/mandos/network-hooks.d"
125
137
 
126
138
bool debug = false;
127
139
static const char mandos_protocol_version[] = "1";
128
140
const char *argp_program_version = "mandos-client " VERSION;
129
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
141
const char *argp_program_bug_address = "<mandos@recompile.se>";
 
142
static const char sys_class_net[] = "/sys/class/net";
 
143
char *connect_to = NULL;
 
144
const char *hookdir = HOOKDIR;
 
145
int hookdir_fd = -1;
 
146
uid_t uid = 65534;
 
147
gid_t gid = 65534;
 
148
 
 
149
/* Doubly linked list that need to be circularly linked when used */
 
150
typedef struct server{
 
151
  const char *ip;
 
152
  in_port_t port;
 
153
  AvahiIfIndex if_index;
 
154
  int af;
 
155
  struct timespec last_seen;
 
156
  struct server *next;
 
157
  struct server *prev;
 
158
} server;
130
159
 
131
160
/* Used for passing in values through the Avahi callback functions */
132
161
typedef struct {
133
 
  AvahiSimplePoll *simple_poll;
134
162
  AvahiServer *server;
135
163
  gnutls_certificate_credentials_t cred;
136
164
  unsigned int dh_bits;
137
165
  gnutls_dh_params_t dh_params;
138
166
  const char *priority;
139
167
  gpgme_ctx_t ctx;
 
168
  server *current_server;
 
169
  char *interfaces;
 
170
  size_t interfaces_size;
140
171
} mandos_context;
141
172
 
142
 
/* global context so signal handler can reach it*/
143
 
mandos_context mc = { .simple_poll = NULL, .server = NULL,
144
 
                      .dh_bits = 1024, .priority = "SECURE256"
145
 
                      ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
173
/* global so signal handler can reach it*/
 
174
AvahiSimplePoll *simple_poll;
146
175
 
147
176
sig_atomic_t quit_now = 0;
148
177
int signal_received = 0;
149
178
 
 
179
/* Function to use when printing errors */
 
180
void perror_plus(const char *print_text){
 
181
  int e = errno;
 
182
  fprintf(stderr, "Mandos plugin %s: ",
 
183
          program_invocation_short_name);
 
184
  errno = e;
 
185
  perror(print_text);
 
186
}
 
187
 
 
188
__attribute__((format (gnu_printf, 2, 3), nonnull))
 
189
int fprintf_plus(FILE *stream, const char *format, ...){
 
190
  va_list ap;
 
191
  va_start (ap, format);
 
192
  
 
193
  TEMP_FAILURE_RETRY(fprintf(stream, "Mandos plugin %s: ",
 
194
                             program_invocation_short_name));
 
195
  return (int)TEMP_FAILURE_RETRY(vfprintf(stream, format, ap));
 
196
}
 
197
 
150
198
/*
151
199
 * Make additional room in "buffer" for at least BUFFER_SIZE more
152
200
 * bytes. "buffer_capacity" is how much is currently allocated,
153
201
 * "buffer_length" is how much is already used.
154
202
 */
 
203
__attribute__((nonnull, warn_unused_result))
155
204
size_t incbuffer(char **buffer, size_t buffer_length,
156
 
                  size_t buffer_capacity){
 
205
                 size_t buffer_capacity){
157
206
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
158
 
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
159
 
    if(buffer == NULL){
 
207
    char *new_buf = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
 
208
    if(new_buf == NULL){
 
209
      int old_errno = errno;
 
210
      free(*buffer);
 
211
      errno = old_errno;
 
212
      *buffer = NULL;
160
213
      return 0;
161
214
    }
 
215
    *buffer = new_buf;
162
216
    buffer_capacity += BUFFER_SIZE;
163
217
  }
164
218
  return buffer_capacity;
165
219
}
166
220
 
 
221
/* Add server to set of servers to retry periodically */
 
222
__attribute__((nonnull, warn_unused_result))
 
223
bool add_server(const char *ip, in_port_t port, AvahiIfIndex if_index,
 
224
                int af, server **current_server){
 
225
  int ret;
 
226
  server *new_server = malloc(sizeof(server));
 
227
  if(new_server == NULL){
 
228
    perror_plus("malloc");
 
229
    return false;
 
230
  }
 
231
  *new_server = (server){ .ip = strdup(ip),
 
232
                          .port = port,
 
233
                          .if_index = if_index,
 
234
                          .af = af };
 
235
  if(new_server->ip == NULL){
 
236
    perror_plus("strdup");
 
237
    free(new_server);
 
238
    return false;
 
239
  }
 
240
  ret = clock_gettime(CLOCK_MONOTONIC, &(new_server->last_seen));
 
241
  if(ret == -1){
 
242
    perror_plus("clock_gettime");
 
243
#ifdef __GNUC__
 
244
#pragma GCC diagnostic push
 
245
#pragma GCC diagnostic ignored "-Wcast-qual"
 
246
#endif
 
247
    free((char *)(new_server->ip));
 
248
#ifdef __GNUC__
 
249
#pragma GCC diagnostic pop
 
250
#endif
 
251
    free(new_server);
 
252
    return false;
 
253
  }
 
254
  /* Special case of first server */
 
255
  if(*current_server == NULL){
 
256
    new_server->next = new_server;
 
257
    new_server->prev = new_server;
 
258
    *current_server = new_server;
 
259
  } else {
 
260
    /* Place the new server last in the list */
 
261
    new_server->next = *current_server;
 
262
    new_server->prev = (*current_server)->prev;
 
263
    new_server->prev->next = new_server;
 
264
    (*current_server)->prev = new_server;
 
265
  }
 
266
  return true;
 
267
}
 
268
 
167
269
/* 
168
270
 * Initialize GPGME.
169
271
 */
170
 
static bool init_gpgme(const char *seckey,
171
 
                       const char *pubkey, const char *tempdir){
 
272
__attribute__((nonnull, warn_unused_result))
 
273
static bool init_gpgme(const char * const seckey,
 
274
                       const char * const pubkey,
 
275
                       const char * const tempdir,
 
276
                       mandos_context *mc){
172
277
  gpgme_error_t rc;
173
278
  gpgme_engine_info_t engine_info;
174
279
  
175
 
  
176
280
  /*
177
281
   * Helper function to insert pub and seckey to the engine keyring.
178
282
   */
179
 
  bool import_key(const char *filename){
 
283
  bool import_key(const char * const filename){
180
284
    int ret;
181
285
    int fd;
182
286
    gpgme_data_t pgp_data;
183
287
    
184
288
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
185
289
    if(fd == -1){
186
 
      perror("open");
 
290
      perror_plus("open");
187
291
      return false;
188
292
    }
189
293
    
190
294
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
191
295
    if(rc != GPG_ERR_NO_ERROR){
192
 
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
193
 
              gpgme_strsource(rc), gpgme_strerror(rc));
 
296
      fprintf_plus(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
 
297
                   gpgme_strsource(rc), gpgme_strerror(rc));
194
298
      return false;
195
299
    }
196
300
    
197
 
    rc = gpgme_op_import(mc.ctx, pgp_data);
 
301
    rc = gpgme_op_import(mc->ctx, pgp_data);
198
302
    if(rc != GPG_ERR_NO_ERROR){
199
 
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
200
 
              gpgme_strsource(rc), gpgme_strerror(rc));
 
303
      fprintf_plus(stderr, "bad gpgme_op_import: %s: %s\n",
 
304
                   gpgme_strsource(rc), gpgme_strerror(rc));
201
305
      return false;
202
306
    }
203
307
    
204
308
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
205
309
    if(ret == -1){
206
 
      perror("close");
 
310
      perror_plus("close");
207
311
    }
208
312
    gpgme_data_release(pgp_data);
209
313
    return true;
210
314
  }
211
315
  
212
316
  if(debug){
213
 
    fprintf(stderr, "Initializing GPGME\n");
 
317
    fprintf_plus(stderr, "Initializing GPGME\n");
214
318
  }
215
319
  
216
320
  /* Init GPGME */
217
321
  gpgme_check_version(NULL);
218
322
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
219
323
  if(rc != GPG_ERR_NO_ERROR){
220
 
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
221
 
            gpgme_strsource(rc), gpgme_strerror(rc));
 
324
    fprintf_plus(stderr, "bad gpgme_engine_check_version: %s: %s\n",
 
325
                 gpgme_strsource(rc), gpgme_strerror(rc));
222
326
    return false;
223
327
  }
224
328
  
225
 
    /* Set GPGME home directory for the OpenPGP engine only */
 
329
  /* Set GPGME home directory for the OpenPGP engine only */
226
330
  rc = gpgme_get_engine_info(&engine_info);
227
331
  if(rc != GPG_ERR_NO_ERROR){
228
 
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
229
 
            gpgme_strsource(rc), gpgme_strerror(rc));
 
332
    fprintf_plus(stderr, "bad gpgme_get_engine_info: %s: %s\n",
 
333
                 gpgme_strsource(rc), gpgme_strerror(rc));
230
334
    return false;
231
335
  }
232
336
  while(engine_info != NULL){
238
342
    engine_info = engine_info->next;
239
343
  }
240
344
  if(engine_info == NULL){
241
 
    fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
 
345
    fprintf_plus(stderr, "Could not set GPGME home dir to %s\n",
 
346
                 tempdir);
242
347
    return false;
243
348
  }
244
349
  
245
350
  /* Create new GPGME "context" */
246
 
  rc = gpgme_new(&(mc.ctx));
 
351
  rc = gpgme_new(&(mc->ctx));
247
352
  if(rc != GPG_ERR_NO_ERROR){
248
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
249
 
            gpgme_strsource(rc), gpgme_strerror(rc));
 
353
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
 
354
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
 
355
                 gpgme_strerror(rc));
250
356
    return false;
251
357
  }
252
358
  
261
367
 * Decrypt OpenPGP data.
262
368
 * Returns -1 on error
263
369
 */
 
370
__attribute__((nonnull, warn_unused_result))
264
371
static ssize_t pgp_packet_decrypt(const char *cryptotext,
265
372
                                  size_t crypto_size,
266
 
                                  char **plaintext){
 
373
                                  char **plaintext,
 
374
                                  mandos_context *mc){
267
375
  gpgme_data_t dh_crypto, dh_plain;
268
376
  gpgme_error_t rc;
269
377
  ssize_t ret;
271
379
  ssize_t plaintext_length = 0;
272
380
  
273
381
  if(debug){
274
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
382
    fprintf_plus(stderr, "Trying to decrypt OpenPGP data\n");
275
383
  }
276
384
  
277
385
  /* Create new GPGME data buffer from memory cryptotext */
278
386
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
279
387
                               0);
280
388
  if(rc != GPG_ERR_NO_ERROR){
281
 
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
282
 
            gpgme_strsource(rc), gpgme_strerror(rc));
 
389
    fprintf_plus(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
 
390
                 gpgme_strsource(rc), gpgme_strerror(rc));
283
391
    return -1;
284
392
  }
285
393
  
286
394
  /* Create new empty GPGME data buffer for the plaintext */
287
395
  rc = gpgme_data_new(&dh_plain);
288
396
  if(rc != GPG_ERR_NO_ERROR){
289
 
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
290
 
            gpgme_strsource(rc), gpgme_strerror(rc));
 
397
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
 
398
                 "bad gpgme_data_new: %s: %s\n",
 
399
                 gpgme_strsource(rc), gpgme_strerror(rc));
291
400
    gpgme_data_release(dh_crypto);
292
401
    return -1;
293
402
  }
294
403
  
295
404
  /* Decrypt data from the cryptotext data buffer to the plaintext
296
405
     data buffer */
297
 
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
406
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
298
407
  if(rc != GPG_ERR_NO_ERROR){
299
 
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
300
 
            gpgme_strsource(rc), gpgme_strerror(rc));
 
408
    fprintf_plus(stderr, "bad gpgme_op_decrypt: %s: %s\n",
 
409
                 gpgme_strsource(rc), gpgme_strerror(rc));
301
410
    plaintext_length = -1;
302
411
    if(debug){
303
412
      gpgme_decrypt_result_t result;
304
 
      result = gpgme_op_decrypt_result(mc.ctx);
 
413
      result = gpgme_op_decrypt_result(mc->ctx);
305
414
      if(result == NULL){
306
 
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
415
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
307
416
      } else {
308
 
        fprintf(stderr, "Unsupported algorithm: %s\n",
309
 
                result->unsupported_algorithm);
310
 
        fprintf(stderr, "Wrong key usage: %u\n",
311
 
                result->wrong_key_usage);
 
417
        fprintf_plus(stderr, "Unsupported algorithm: %s\n",
 
418
                     result->unsupported_algorithm);
 
419
        fprintf_plus(stderr, "Wrong key usage: %u\n",
 
420
                     result->wrong_key_usage);
312
421
        if(result->file_name != NULL){
313
 
          fprintf(stderr, "File name: %s\n", result->file_name);
 
422
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
314
423
        }
315
424
        gpgme_recipient_t recipient;
316
425
        recipient = result->recipients;
317
426
        while(recipient != NULL){
318
 
          fprintf(stderr, "Public key algorithm: %s\n",
319
 
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
320
 
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
321
 
          fprintf(stderr, "Secret key available: %s\n",
322
 
                  recipient->status == GPG_ERR_NO_SECKEY
323
 
                  ? "No" : "Yes");
 
427
          fprintf_plus(stderr, "Public key algorithm: %s\n",
 
428
                       gpgme_pubkey_algo_name
 
429
                       (recipient->pubkey_algo));
 
430
          fprintf_plus(stderr, "Key ID: %s\n", recipient->keyid);
 
431
          fprintf_plus(stderr, "Secret key available: %s\n",
 
432
                       recipient->status == GPG_ERR_NO_SECKEY
 
433
                       ? "No" : "Yes");
324
434
          recipient = recipient->next;
325
435
        }
326
436
      }
329
439
  }
330
440
  
331
441
  if(debug){
332
 
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
 
442
    fprintf_plus(stderr, "Decryption of OpenPGP data succeeded\n");
333
443
  }
334
444
  
335
445
  /* Seek back to the beginning of the GPGME plaintext data buffer */
336
446
  if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
337
 
    perror("gpgme_data_seek");
 
447
    perror_plus("gpgme_data_seek");
338
448
    plaintext_length = -1;
339
449
    goto decrypt_end;
340
450
  }
342
452
  *plaintext = NULL;
343
453
  while(true){
344
454
    plaintext_capacity = incbuffer(plaintext,
345
 
                                      (size_t)plaintext_length,
346
 
                                      plaintext_capacity);
 
455
                                   (size_t)plaintext_length,
 
456
                                   plaintext_capacity);
347
457
    if(plaintext_capacity == 0){
348
 
        perror("incbuffer");
349
 
        plaintext_length = -1;
350
 
        goto decrypt_end;
 
458
      perror_plus("incbuffer");
 
459
      plaintext_length = -1;
 
460
      goto decrypt_end;
351
461
    }
352
462
    
353
463
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
358
468
      break;
359
469
    }
360
470
    if(ret < 0){
361
 
      perror("gpgme_data_read");
 
471
      perror_plus("gpgme_data_read");
362
472
      plaintext_length = -1;
363
473
      goto decrypt_end;
364
474
    }
366
476
  }
367
477
  
368
478
  if(debug){
369
 
    fprintf(stderr, "Decrypted password is: ");
 
479
    fprintf_plus(stderr, "Decrypted password is: ");
370
480
    for(ssize_t i = 0; i < plaintext_length; i++){
371
481
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
372
482
    }
383
493
  return plaintext_length;
384
494
}
385
495
 
386
 
static const char * safer_gnutls_strerror(int value){
387
 
  const char *ret = gnutls_strerror(value); /* Spurious warning from
388
 
                                               -Wunreachable-code */
389
 
  if(ret == NULL)
390
 
    ret = "(unknown)";
391
 
  return ret;
 
496
__attribute__((warn_unused_result, const))
 
497
static const char *safe_string(const char *str){
 
498
  if(str == NULL)
 
499
    return "(unknown)";
 
500
  return str;
 
501
}
 
502
 
 
503
__attribute__((warn_unused_result))
 
504
static const char *safer_gnutls_strerror(int value){
 
505
  const char *ret = gnutls_strerror(value);
 
506
  return safe_string(ret);
392
507
}
393
508
 
394
509
/* GnuTLS log function callback */
 
510
__attribute__((nonnull))
395
511
static void debuggnutls(__attribute__((unused)) int level,
396
512
                        const char* string){
397
 
  fprintf(stderr, "GnuTLS: %s", string);
 
513
  fprintf_plus(stderr, "GnuTLS: %s", string);
398
514
}
399
515
 
 
516
__attribute__((nonnull, warn_unused_result))
400
517
static int init_gnutls_global(const char *pubkeyfilename,
401
 
                              const char *seckeyfilename){
 
518
                              const char *seckeyfilename,
 
519
                              mandos_context *mc){
402
520
  int ret;
 
521
  unsigned int uret;
403
522
  
404
523
  if(debug){
405
 
    fprintf(stderr, "Initializing GnuTLS\n");
 
524
    fprintf_plus(stderr, "Initializing GnuTLS\n");
406
525
  }
407
526
  
408
527
  ret = gnutls_global_init();
409
528
  if(ret != GNUTLS_E_SUCCESS){
410
 
    fprintf(stderr, "GnuTLS global_init: %s\n",
411
 
            safer_gnutls_strerror(ret));
 
529
    fprintf_plus(stderr, "GnuTLS global_init: %s\n",
 
530
                 safer_gnutls_strerror(ret));
412
531
    return -1;
413
532
  }
414
533
  
421
540
  }
422
541
  
423
542
  /* OpenPGP credentials */
424
 
  gnutls_certificate_allocate_credentials(&mc.cred);
 
543
  ret = gnutls_certificate_allocate_credentials(&mc->cred);
425
544
  if(ret != GNUTLS_E_SUCCESS){
426
 
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
427
 
                                                    from
428
 
                                                    -Wunreachable-code
429
 
                                                 */
430
 
            safer_gnutls_strerror(ret));
 
545
    fprintf_plus(stderr, "GnuTLS memory error: %s\n",
 
546
                 safer_gnutls_strerror(ret));
431
547
    gnutls_global_deinit();
432
548
    return -1;
433
549
  }
434
550
  
435
551
  if(debug){
436
 
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
437
 
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
438
 
            seckeyfilename);
 
552
    fprintf_plus(stderr, "Attempting to use OpenPGP public key %s and"
 
553
                 " secret key %s as GnuTLS credentials\n",
 
554
                 pubkeyfilename,
 
555
                 seckeyfilename);
439
556
  }
440
557
  
441
558
  ret = gnutls_certificate_set_openpgp_key_file
442
 
    (mc.cred, pubkeyfilename, seckeyfilename,
 
559
    (mc->cred, pubkeyfilename, seckeyfilename,
443
560
     GNUTLS_OPENPGP_FMT_BASE64);
444
561
  if(ret != GNUTLS_E_SUCCESS){
445
 
    fprintf(stderr,
446
 
            "Error[%d] while reading the OpenPGP key pair ('%s',"
447
 
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
448
 
    fprintf(stderr, "The GnuTLS error is: %s\n",
449
 
            safer_gnutls_strerror(ret));
 
562
    fprintf_plus(stderr,
 
563
                 "Error[%d] while reading the OpenPGP key pair ('%s',"
 
564
                 " '%s')\n", ret, pubkeyfilename, seckeyfilename);
 
565
    fprintf_plus(stderr, "The GnuTLS error is: %s\n",
 
566
                 safer_gnutls_strerror(ret));
450
567
    goto globalfail;
451
568
  }
452
569
  
453
570
  /* GnuTLS server initialization */
454
 
  ret = gnutls_dh_params_init(&mc.dh_params);
 
571
  ret = gnutls_dh_params_init(&mc->dh_params);
455
572
  if(ret != GNUTLS_E_SUCCESS){
456
 
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
457
 
            " %s\n", safer_gnutls_strerror(ret));
 
573
    fprintf_plus(stderr, "Error in GnuTLS DH parameter"
 
574
                 " initialization: %s\n",
 
575
                 safer_gnutls_strerror(ret));
458
576
    goto globalfail;
459
577
  }
460
 
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
578
  if(mc->dh_bits == 0){
 
579
    /* Find out the optimal number of DH bits */
 
580
    /* Try to read the private key file */
 
581
    gnutls_datum_t buffer = { .data = NULL, .size = 0 };
 
582
    {
 
583
      int secfile = open(seckeyfilename, O_RDONLY);
 
584
      size_t buffer_capacity = 0;
 
585
      while(true){
 
586
        buffer_capacity = incbuffer((char **)&buffer.data,
 
587
                                    (size_t)buffer.size,
 
588
                                    (size_t)buffer_capacity);
 
589
        if(buffer_capacity == 0){
 
590
          perror_plus("incbuffer");
 
591
          free(buffer.data);
 
592
          buffer.data = NULL;
 
593
          break;
 
594
        }
 
595
        ssize_t bytes_read = read(secfile, buffer.data + buffer.size,
 
596
                                  BUFFER_SIZE);
 
597
        /* EOF */
 
598
        if(bytes_read == 0){
 
599
          break;
 
600
        }
 
601
        /* check bytes_read for failure */
 
602
        if(bytes_read < 0){
 
603
          perror_plus("read");
 
604
          free(buffer.data);
 
605
          buffer.data = NULL;
 
606
          break;
 
607
        }
 
608
        buffer.size += (unsigned int)bytes_read;
 
609
      }
 
610
      close(secfile);
 
611
    }
 
612
    /* If successful, use buffer to parse private key */
 
613
    gnutls_sec_param_t sec_param = GNUTLS_SEC_PARAM_ULTRA;
 
614
    if(buffer.data != NULL){
 
615
      {
 
616
        gnutls_openpgp_privkey_t privkey = NULL;
 
617
        ret = gnutls_openpgp_privkey_init(&privkey);
 
618
        if(ret != GNUTLS_E_SUCCESS){
 
619
          fprintf_plus(stderr, "Error initializing OpenPGP key"
 
620
                       " structure: %s", safer_gnutls_strerror(ret));
 
621
          free(buffer.data);
 
622
          buffer.data = NULL;
 
623
        } else {
 
624
          ret = gnutls_openpgp_privkey_import(privkey, &buffer,
 
625
                                            GNUTLS_OPENPGP_FMT_BASE64,
 
626
                                              "", 0);
 
627
          if(ret != GNUTLS_E_SUCCESS){
 
628
            fprintf_plus(stderr, "Error importing OpenPGP key : %s",
 
629
                         safer_gnutls_strerror(ret));
 
630
            privkey = NULL;
 
631
          }
 
632
          free(buffer.data);
 
633
          buffer.data = NULL;
 
634
          if(privkey != NULL){
 
635
            /* Use private key to suggest an appropriate sec_param */
 
636
            sec_param = gnutls_openpgp_privkey_sec_param(privkey);
 
637
            gnutls_openpgp_privkey_deinit(privkey);
 
638
            if(debug){
 
639
              fprintf_plus(stderr, "This OpenPGP key implies using a"
 
640
                           " GnuTLS security parameter \"%s\".\n",
 
641
                           safe_string(gnutls_sec_param_get_name
 
642
                                       (sec_param)));
 
643
            }
 
644
          }
 
645
        }
 
646
      }
 
647
      if(sec_param == GNUTLS_SEC_PARAM_UNKNOWN){
 
648
        /* Err on the side of caution */
 
649
        sec_param = GNUTLS_SEC_PARAM_ULTRA;
 
650
        if(debug){
 
651
          fprintf_plus(stderr, "Falling back to security parameter"
 
652
                       " \"%s\"\n",
 
653
                       safe_string(gnutls_sec_param_get_name
 
654
                                   (sec_param)));
 
655
        }
 
656
      }
 
657
    }
 
658
    uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
 
659
    if(uret != 0){
 
660
      mc->dh_bits = uret;
 
661
      if(debug){
 
662
        fprintf_plus(stderr, "A \"%s\" GnuTLS security parameter"
 
663
                     " implies %u DH bits; using that.\n",
 
664
                     safe_string(gnutls_sec_param_get_name
 
665
                                 (sec_param)),
 
666
                     mc->dh_bits);
 
667
      }
 
668
    } else {
 
669
      fprintf_plus(stderr, "Failed to get implied number of DH"
 
670
                   " bits for security parameter \"%s\"): %s\n",
 
671
                   safe_string(gnutls_sec_param_get_name(sec_param)),
 
672
                   safer_gnutls_strerror(ret));
 
673
      goto globalfail;
 
674
    }
 
675
  } else if(debug){
 
676
    fprintf_plus(stderr, "DH bits explicitly set to %u\n",
 
677
                 mc->dh_bits);
 
678
  }
 
679
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
461
680
  if(ret != GNUTLS_E_SUCCESS){
462
 
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
463
 
            safer_gnutls_strerror(ret));
 
681
    fprintf_plus(stderr, "Error in GnuTLS prime generation (%u bits):"
 
682
                 " %s\n", mc->dh_bits, safer_gnutls_strerror(ret));
464
683
    goto globalfail;
465
684
  }
466
685
  
467
 
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
686
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
468
687
  
469
688
  return 0;
470
689
  
471
690
 globalfail:
472
691
  
473
 
  gnutls_certificate_free_credentials(mc.cred);
 
692
  gnutls_certificate_free_credentials(mc->cred);
474
693
  gnutls_global_deinit();
475
 
  gnutls_dh_params_deinit(mc.dh_params);
 
694
  gnutls_dh_params_deinit(mc->dh_params);
476
695
  return -1;
477
696
}
478
697
 
479
 
static int init_gnutls_session(gnutls_session_t *session){
 
698
__attribute__((nonnull, warn_unused_result))
 
699
static int init_gnutls_session(gnutls_session_t *session,
 
700
                               mandos_context *mc){
480
701
  int ret;
481
702
  /* GnuTLS session creation */
482
703
  do {
486
707
    }
487
708
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
488
709
  if(ret != GNUTLS_E_SUCCESS){
489
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
490
 
            safer_gnutls_strerror(ret));
 
710
    fprintf_plus(stderr,
 
711
                 "Error in GnuTLS session initialization: %s\n",
 
712
                 safer_gnutls_strerror(ret));
491
713
  }
492
714
  
493
715
  {
494
716
    const char *err;
495
717
    do {
496
 
      ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
718
      ret = gnutls_priority_set_direct(*session, mc->priority, &err);
497
719
      if(quit_now){
498
720
        gnutls_deinit(*session);
499
721
        return -1;
500
722
      }
501
723
    } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
502
724
    if(ret != GNUTLS_E_SUCCESS){
503
 
      fprintf(stderr, "Syntax error at: %s\n", err);
504
 
      fprintf(stderr, "GnuTLS error: %s\n",
505
 
              safer_gnutls_strerror(ret));
 
725
      fprintf_plus(stderr, "Syntax error at: %s\n", err);
 
726
      fprintf_plus(stderr, "GnuTLS error: %s\n",
 
727
                   safer_gnutls_strerror(ret));
506
728
      gnutls_deinit(*session);
507
729
      return -1;
508
730
    }
510
732
  
511
733
  do {
512
734
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
513
 
                                 mc.cred);
 
735
                                 mc->cred);
514
736
    if(quit_now){
515
737
      gnutls_deinit(*session);
516
738
      return -1;
517
739
    }
518
740
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
519
741
  if(ret != GNUTLS_E_SUCCESS){
520
 
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
521
 
            safer_gnutls_strerror(ret));
 
742
    fprintf_plus(stderr, "Error setting GnuTLS credentials: %s\n",
 
743
                 safer_gnutls_strerror(ret));
522
744
    gnutls_deinit(*session);
523
745
    return -1;
524
746
  }
526
748
  /* ignore client certificate if any. */
527
749
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
528
750
  
529
 
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
 
751
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
530
752
  
531
753
  return 0;
532
754
}
536
758
                      __attribute__((unused)) const char *txt){}
537
759
 
538
760
/* Called when a Mandos server is found */
539
 
static int start_mandos_communication(const char *ip, uint16_t port,
 
761
__attribute__((nonnull, warn_unused_result))
 
762
static int start_mandos_communication(const char *ip, in_port_t port,
540
763
                                      AvahiIfIndex if_index,
541
 
                                      int af){
 
764
                                      int af, mandos_context *mc){
542
765
  int ret, tcp_sd = -1;
543
766
  ssize_t sret;
544
 
  union {
545
 
    struct sockaddr_in in;
546
 
    struct sockaddr_in6 in6;
547
 
  } to;
 
767
  struct sockaddr_storage to;
548
768
  char *buffer = NULL;
549
769
  char *decrypted_buffer = NULL;
550
770
  size_t buffer_length = 0;
569
789
    pf = PF_INET;
570
790
    break;
571
791
  default:
572
 
    fprintf(stderr, "Bad address family: %d\n", af);
 
792
    fprintf_plus(stderr, "Bad address family: %d\n", af);
573
793
    errno = EINVAL;
574
794
    return -1;
575
795
  }
576
796
  
577
 
  ret = init_gnutls_session(&session);
 
797
  /* If the interface is specified and we have a list of interfaces */
 
798
  if(if_index != AVAHI_IF_UNSPEC and mc->interfaces != NULL){
 
799
    /* Check if the interface is one of the interfaces we are using */
 
800
    bool match = false;
 
801
    {
 
802
      char *interface = NULL;
 
803
      while((interface=argz_next(mc->interfaces, mc->interfaces_size,
 
804
                                 interface))){
 
805
        if(if_nametoindex(interface) == (unsigned int)if_index){
 
806
          match = true;
 
807
          break;
 
808
        }
 
809
      }
 
810
    }
 
811
    if(not match){
 
812
      /* This interface does not match any in the list, so we don't
 
813
         connect to the server */
 
814
      if(debug){
 
815
        char interface[IF_NAMESIZE];
 
816
        if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
817
          perror_plus("if_indextoname");
 
818
        } else {
 
819
          fprintf_plus(stderr, "Skipping server on non-used interface"
 
820
                       " \"%s\"\n",
 
821
                       if_indextoname((unsigned int)if_index,
 
822
                                      interface));
 
823
        }
 
824
      }
 
825
      return -1;
 
826
    }
 
827
  }
 
828
  
 
829
  ret = init_gnutls_session(&session, mc);
578
830
  if(ret != 0){
579
831
    return -1;
580
832
  }
581
833
  
582
834
  if(debug){
583
 
    fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
584
 
            "\n", ip, port);
 
835
    fprintf_plus(stderr, "Setting up a TCP connection to %s, port %"
 
836
                 PRIuMAX "\n", ip, (uintmax_t)port);
585
837
  }
586
838
  
587
839
  tcp_sd = socket(pf, SOCK_STREAM, 0);
588
840
  if(tcp_sd < 0){
589
841
    int e = errno;
590
 
    perror("socket");
 
842
    perror_plus("socket");
591
843
    errno = e;
592
844
    goto mandos_end;
593
845
  }
599
851
  
600
852
  memset(&to, 0, sizeof(to));
601
853
  if(af == AF_INET6){
602
 
    to.in6.sin6_family = (sa_family_t)af;
603
 
    ret = inet_pton(af, ip, &to.in6.sin6_addr);
 
854
    ((struct sockaddr_in6 *)&to)->sin6_family = (sa_family_t)af;
 
855
    ret = inet_pton(af, ip, &((struct sockaddr_in6 *)&to)->sin6_addr);
604
856
  } else {                      /* IPv4 */
605
 
    to.in.sin_family = (sa_family_t)af;
606
 
    ret = inet_pton(af, ip, &to.in.sin_addr);
 
857
    ((struct sockaddr_in *)&to)->sin_family = (sa_family_t)af;
 
858
    ret = inet_pton(af, ip, &((struct sockaddr_in *)&to)->sin_addr);
607
859
  }
608
860
  if(ret < 0 ){
609
861
    int e = errno;
610
 
    perror("inet_pton");
 
862
    perror_plus("inet_pton");
611
863
    errno = e;
612
864
    goto mandos_end;
613
865
  }
614
866
  if(ret == 0){
615
867
    int e = errno;
616
 
    fprintf(stderr, "Bad address: %s\n", ip);
 
868
    fprintf_plus(stderr, "Bad address: %s\n", ip);
617
869
    errno = e;
618
870
    goto mandos_end;
619
871
  }
620
872
  if(af == AF_INET6){
621
 
    to.in6.sin6_port = htons(port); /* Spurious warnings from
622
 
                                       -Wconversion and
623
 
                                       -Wunreachable-code */
624
 
    
625
 
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
626
 
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
627
 
                              -Wunreachable-code*/
 
873
    ((struct sockaddr_in6 *)&to)->sin6_port = htons(port);
 
874
    if(IN6_IS_ADDR_LINKLOCAL
 
875
       (&((struct sockaddr_in6 *)&to)->sin6_addr)){
628
876
      if(if_index == AVAHI_IF_UNSPEC){
629
 
        fprintf(stderr, "An IPv6 link-local address is incomplete"
630
 
                " without a network interface\n");
 
877
        fprintf_plus(stderr, "An IPv6 link-local address is"
 
878
                     " incomplete without a network interface\n");
631
879
        errno = EINVAL;
632
880
        goto mandos_end;
633
881
      }
634
882
      /* Set the network interface number as scope */
635
 
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
883
      ((struct sockaddr_in6 *)&to)->sin6_scope_id = (uint32_t)if_index;
636
884
    }
637
885
  } else {
638
 
    to.in.sin_port = htons(port); /* Spurious warnings from
639
 
                                     -Wconversion and
640
 
                                     -Wunreachable-code */
 
886
    ((struct sockaddr_in *)&to)->sin_port = htons(port);
641
887
  }
642
888
  
643
889
  if(quit_now){
649
895
    if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
650
896
      char interface[IF_NAMESIZE];
651
897
      if(if_indextoname((unsigned int)if_index, interface) == NULL){
652
 
        perror("if_indextoname");
 
898
        perror_plus("if_indextoname");
653
899
      } else {
654
 
        fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
655
 
                ip, interface, port);
 
900
        fprintf_plus(stderr, "Connection to: %s%%%s, port %" PRIuMAX
 
901
                     "\n", ip, interface, (uintmax_t)port);
656
902
      }
657
903
    } else {
658
 
      fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
659
 
              port);
 
904
      fprintf_plus(stderr, "Connection to: %s, port %" PRIuMAX "\n",
 
905
                   ip, (uintmax_t)port);
660
906
    }
661
907
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
662
908
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
663
 
    const char *pcret;
664
909
    if(af == AF_INET6){
665
 
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
666
 
                        sizeof(addrstr));
 
910
      ret = getnameinfo((struct sockaddr *)&to,
 
911
                        sizeof(struct sockaddr_in6),
 
912
                        addrstr, sizeof(addrstr), NULL, 0,
 
913
                        NI_NUMERICHOST);
667
914
    } else {
668
 
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
669
 
                        sizeof(addrstr));
 
915
      ret = getnameinfo((struct sockaddr *)&to,
 
916
                        sizeof(struct sockaddr_in),
 
917
                        addrstr, sizeof(addrstr), NULL, 0,
 
918
                        NI_NUMERICHOST);
670
919
    }
671
 
    if(pcret == NULL){
672
 
      perror("inet_ntop");
673
 
    } else {
674
 
      if(strcmp(addrstr, ip) != 0){
675
 
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
676
 
      }
 
920
    if(ret == EAI_SYSTEM){
 
921
      perror_plus("getnameinfo");
 
922
    } else if(ret != 0) {
 
923
      fprintf_plus(stderr, "getnameinfo: %s", gai_strerror(ret));
 
924
    } else if(strcmp(addrstr, ip) != 0){
 
925
      fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
677
926
    }
678
927
  }
679
928
  
683
932
  }
684
933
  
685
934
  if(af == AF_INET6){
686
 
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
935
    ret = connect(tcp_sd, (struct sockaddr *)&to,
 
936
                  sizeof(struct sockaddr_in6));
687
937
  } else {
688
 
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
938
    ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
939
                  sizeof(struct sockaddr_in));
689
940
  }
690
941
  if(ret < 0){
691
 
    int e = errno;
692
 
    perror("connect");
693
 
    errno = e;
 
942
    if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
943
      int e = errno;
 
944
      perror_plus("connect");
 
945
      errno = e;
 
946
    }
694
947
    goto mandos_end;
695
948
  }
696
949
  
704
957
  while(true){
705
958
    size_t out_size = strlen(out);
706
959
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
707
 
                                   out_size - written));
 
960
                                        out_size - written));
708
961
    if(ret == -1){
709
962
      int e = errno;
710
 
      perror("write");
 
963
      perror_plus("write");
711
964
      errno = e;
712
965
      goto mandos_end;
713
966
    }
730
983
  }
731
984
  
732
985
  if(debug){
733
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
986
    fprintf_plus(stderr, "Establishing TLS session with %s\n", ip);
734
987
  }
735
988
  
736
989
  if(quit_now){
738
991
    goto mandos_end;
739
992
  }
740
993
  
741
 
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
994
  /* This casting via intptr_t is to eliminate warning about casting
 
995
     an int to a pointer type.  This is exactly how the GnuTLS Guile
 
996
     function "set-session-transport-fd!" does it. */
 
997
  gnutls_transport_set_ptr(session,
 
998
                           (gnutls_transport_ptr_t)(intptr_t)tcp_sd);
742
999
  
743
1000
  if(quit_now){
744
1001
    errno = EINTR;
755
1012
  
756
1013
  if(ret != GNUTLS_E_SUCCESS){
757
1014
    if(debug){
758
 
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
1015
      fprintf_plus(stderr, "*** GnuTLS Handshake failed ***\n");
759
1016
      gnutls_perror(ret);
760
1017
    }
761
1018
    errno = EPROTO;
765
1022
  /* Read OpenPGP packet that contains the wanted password */
766
1023
  
767
1024
  if(debug){
768
 
    fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
769
 
            ip);
 
1025
    fprintf_plus(stderr, "Retrieving OpenPGP encrypted password from"
 
1026
                 " %s\n", ip);
770
1027
  }
771
1028
  
772
1029
  while(true){
777
1034
    }
778
1035
    
779
1036
    buffer_capacity = incbuffer(&buffer, buffer_length,
780
 
                                   buffer_capacity);
 
1037
                                buffer_capacity);
781
1038
    if(buffer_capacity == 0){
782
1039
      int e = errno;
783
 
      perror("incbuffer");
 
1040
      perror_plus("incbuffer");
784
1041
      errno = e;
785
1042
      goto mandos_end;
786
1043
    }
810
1067
          }
811
1068
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
812
1069
        if(ret < 0){
813
 
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
1070
          fprintf_plus(stderr, "*** GnuTLS Re-handshake failed "
 
1071
                       "***\n");
814
1072
          gnutls_perror(ret);
815
1073
          errno = EPROTO;
816
1074
          goto mandos_end;
817
1075
        }
818
1076
        break;
819
1077
      default:
820
 
        fprintf(stderr, "Unknown error while reading data from"
821
 
                " encrypted session with Mandos server\n");
 
1078
        fprintf_plus(stderr, "Unknown error while reading data from"
 
1079
                     " encrypted session with Mandos server\n");
822
1080
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
823
1081
        errno = EIO;
824
1082
        goto mandos_end;
829
1087
  }
830
1088
  
831
1089
  if(debug){
832
 
    fprintf(stderr, "Closing TLS session\n");
 
1090
    fprintf_plus(stderr, "Closing TLS session\n");
833
1091
  }
834
1092
  
835
1093
  if(quit_now){
847
1105
  
848
1106
  if(buffer_length > 0){
849
1107
    ssize_t decrypted_buffer_size;
850
 
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
851
 
                                               buffer_length,
852
 
                                               &decrypted_buffer);
 
1108
    decrypted_buffer_size = pgp_packet_decrypt(buffer, buffer_length,
 
1109
                                               &decrypted_buffer, mc);
853
1110
    if(decrypted_buffer_size >= 0){
854
1111
      
855
1112
      written = 0;
865
1122
        if(ret == 0 and ferror(stdout)){
866
1123
          int e = errno;
867
1124
          if(debug){
868
 
            fprintf(stderr, "Error writing encrypted data: %s\n",
869
 
                    strerror(errno));
 
1125
            fprintf_plus(stderr, "Error writing encrypted data: %s\n",
 
1126
                         strerror(errno));
870
1127
          }
871
1128
          errno = e;
872
1129
          goto mandos_end;
891
1148
      if(e == 0){
892
1149
        e = errno;
893
1150
      }
894
 
      perror("close");
 
1151
      perror_plus("close");
895
1152
    }
896
1153
    gnutls_deinit(session);
 
1154
    errno = e;
897
1155
    if(quit_now){
898
 
      e = EINTR;
 
1156
      errno = EINTR;
899
1157
      retval = -1;
900
1158
    }
901
 
    errno = e;
902
1159
  }
903
1160
  return retval;
904
1161
}
905
1162
 
 
1163
__attribute__((nonnull))
906
1164
static void resolve_callback(AvahiSServiceResolver *r,
907
1165
                             AvahiIfIndex interface,
908
1166
                             AvahiProtocol proto,
916
1174
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
917
1175
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
918
1176
                             flags,
919
 
                             AVAHI_GCC_UNUSED void* userdata){
920
 
  assert(r);
 
1177
                             void *mc){
 
1178
  if(r == NULL){
 
1179
    return;
 
1180
  }
921
1181
  
922
1182
  /* Called whenever a service has been resolved successfully or
923
1183
     timed out */
924
1184
  
925
1185
  if(quit_now){
 
1186
    avahi_s_service_resolver_free(r);
926
1187
    return;
927
1188
  }
928
1189
  
929
1190
  switch(event){
930
1191
  default:
931
1192
  case AVAHI_RESOLVER_FAILURE:
932
 
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
933
 
            " of type '%s' in domain '%s': %s\n", name, type, domain,
934
 
            avahi_strerror(avahi_server_errno(mc.server)));
 
1193
    fprintf_plus(stderr, "(Avahi Resolver) Failed to resolve service "
 
1194
                 "'%s' of type '%s' in domain '%s': %s\n", name, type,
 
1195
                 domain,
 
1196
                 avahi_strerror(avahi_server_errno
 
1197
                                (((mandos_context*)mc)->server)));
935
1198
    break;
936
1199
    
937
1200
  case AVAHI_RESOLVER_FOUND:
939
1202
      char ip[AVAHI_ADDRESS_STR_MAX];
940
1203
      avahi_address_snprint(ip, sizeof(ip), address);
941
1204
      if(debug){
942
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
943
 
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
944
 
                ip, (intmax_t)interface, port);
 
1205
        fprintf_plus(stderr, "Mandos server \"%s\" found on %s (%s, %"
 
1206
                     PRIdMAX ") on port %" PRIu16 "\n", name,
 
1207
                     host_name, ip, (intmax_t)interface, port);
945
1208
      }
946
 
      int ret = start_mandos_communication(ip, port, interface,
947
 
                                           avahi_proto_to_af(proto));
 
1209
      int ret = start_mandos_communication(ip, (in_port_t)port,
 
1210
                                           interface,
 
1211
                                           avahi_proto_to_af(proto),
 
1212
                                           mc);
948
1213
      if(ret == 0){
949
 
        avahi_simple_poll_quit(mc.simple_poll);
 
1214
        avahi_simple_poll_quit(simple_poll);
 
1215
      } else {
 
1216
        if(not add_server(ip, (in_port_t)port, interface,
 
1217
                          avahi_proto_to_af(proto),
 
1218
                          &((mandos_context*)mc)->current_server)){
 
1219
          fprintf_plus(stderr, "Failed to add server \"%s\" to server"
 
1220
                       " list\n", name);
 
1221
        }
950
1222
      }
951
1223
    }
952
1224
  }
962
1234
                            const char *domain,
963
1235
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
964
1236
                            flags,
965
 
                            AVAHI_GCC_UNUSED void* userdata){
966
 
  assert(b);
 
1237
                            void *mc){
 
1238
  if(b == NULL){
 
1239
    return;
 
1240
  }
967
1241
  
968
1242
  /* Called whenever a new services becomes available on the LAN or
969
1243
     is removed from the LAN */
976
1250
  default:
977
1251
  case AVAHI_BROWSER_FAILURE:
978
1252
    
979
 
    fprintf(stderr, "(Avahi browser) %s\n",
980
 
            avahi_strerror(avahi_server_errno(mc.server)));
981
 
    avahi_simple_poll_quit(mc.simple_poll);
 
1253
    fprintf_plus(stderr, "(Avahi browser) %s\n",
 
1254
                 avahi_strerror(avahi_server_errno
 
1255
                                (((mandos_context*)mc)->server)));
 
1256
    avahi_simple_poll_quit(simple_poll);
982
1257
    return;
983
1258
    
984
1259
  case AVAHI_BROWSER_NEW:
987
1262
       the callback function is called the Avahi server will free the
988
1263
       resolver for us. */
989
1264
    
990
 
    if(avahi_s_service_resolver_new(mc.server, interface, protocol,
991
 
                                    name, type, domain, protocol, 0,
992
 
                                    resolve_callback, NULL) == NULL)
993
 
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
994
 
              name, avahi_strerror(avahi_server_errno(mc.server)));
 
1265
    if(avahi_s_service_resolver_new(((mandos_context*)mc)->server,
 
1266
                                    interface, protocol, name, type,
 
1267
                                    domain, protocol, 0,
 
1268
                                    resolve_callback, mc) == NULL)
 
1269
      fprintf_plus(stderr, "Avahi: Failed to resolve service '%s':"
 
1270
                   " %s\n", name,
 
1271
                   avahi_strerror(avahi_server_errno
 
1272
                                  (((mandos_context*)mc)->server)));
995
1273
    break;
996
1274
    
997
1275
  case AVAHI_BROWSER_REMOVE:
1000
1278
  case AVAHI_BROWSER_ALL_FOR_NOW:
1001
1279
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
1002
1280
    if(debug){
1003
 
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
1281
      fprintf_plus(stderr, "No Mandos server found, still"
 
1282
                   " searching...\n");
1004
1283
    }
1005
1284
    break;
1006
1285
  }
1007
1286
}
1008
1287
 
1009
 
/* stop main loop after sigterm has been called */
 
1288
/* Signal handler that stops main loop after SIGTERM */
1010
1289
static void handle_sigterm(int sig){
1011
1290
  if(quit_now){
1012
1291
    return;
1014
1293
  quit_now = 1;
1015
1294
  signal_received = sig;
1016
1295
  int old_errno = errno;
1017
 
  if(mc.simple_poll != NULL){
1018
 
    avahi_simple_poll_quit(mc.simple_poll);
1019
 
  }
1020
 
  errno = old_errno;
 
1296
  /* set main loop to exit */
 
1297
  if(simple_poll != NULL){
 
1298
    avahi_simple_poll_quit(simple_poll);
 
1299
  }
 
1300
  errno = old_errno;
 
1301
}
 
1302
 
 
1303
__attribute__((nonnull, warn_unused_result))
 
1304
bool get_flags(const char *ifname, struct ifreq *ifr){
 
1305
  int ret;
 
1306
  error_t ret_errno;
 
1307
  
 
1308
  int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1309
  if(s < 0){
 
1310
    ret_errno = errno;
 
1311
    perror_plus("socket");
 
1312
    errno = ret_errno;
 
1313
    return false;
 
1314
  }
 
1315
  strcpy(ifr->ifr_name, ifname);
 
1316
  ret = ioctl(s, SIOCGIFFLAGS, ifr);
 
1317
  if(ret == -1){
 
1318
    if(debug){
 
1319
      ret_errno = errno;
 
1320
      perror_plus("ioctl SIOCGIFFLAGS");
 
1321
      errno = ret_errno;
 
1322
    }
 
1323
    return false;
 
1324
  }
 
1325
  return true;
 
1326
}
 
1327
 
 
1328
__attribute__((nonnull, warn_unused_result))
 
1329
bool good_flags(const char *ifname, const struct ifreq *ifr){
 
1330
  
 
1331
  /* Reject the loopback device */
 
1332
  if(ifr->ifr_flags & IFF_LOOPBACK){
 
1333
    if(debug){
 
1334
      fprintf_plus(stderr, "Rejecting loopback interface \"%s\"\n",
 
1335
                   ifname);
 
1336
    }
 
1337
    return false;
 
1338
  }
 
1339
  /* Accept point-to-point devices only if connect_to is specified */
 
1340
  if(connect_to != NULL and (ifr->ifr_flags & IFF_POINTOPOINT)){
 
1341
    if(debug){
 
1342
      fprintf_plus(stderr, "Accepting point-to-point interface"
 
1343
                   " \"%s\"\n", ifname);
 
1344
    }
 
1345
    return true;
 
1346
  }
 
1347
  /* Otherwise, reject non-broadcast-capable devices */
 
1348
  if(not (ifr->ifr_flags & IFF_BROADCAST)){
 
1349
    if(debug){
 
1350
      fprintf_plus(stderr, "Rejecting non-broadcast interface"
 
1351
                   " \"%s\"\n", ifname);
 
1352
    }
 
1353
    return false;
 
1354
  }
 
1355
  /* Reject non-ARP interfaces (including dummy interfaces) */
 
1356
  if(ifr->ifr_flags & IFF_NOARP){
 
1357
    if(debug){
 
1358
      fprintf_plus(stderr, "Rejecting non-ARP interface \"%s\"\n",
 
1359
                   ifname);
 
1360
    }
 
1361
    return false;
 
1362
  }
 
1363
  
 
1364
  /* Accept this device */
 
1365
  if(debug){
 
1366
    fprintf_plus(stderr, "Interface \"%s\" is good\n", ifname);
 
1367
  }
 
1368
  return true;
 
1369
}
 
1370
 
 
1371
/* 
 
1372
 * This function determines if a directory entry in /sys/class/net
 
1373
 * corresponds to an acceptable network device.
 
1374
 * (This function is passed to scandir(3) as a filter function.)
 
1375
 */
 
1376
__attribute__((nonnull, warn_unused_result))
 
1377
int good_interface(const struct dirent *if_entry){
 
1378
  if(if_entry->d_name[0] == '.'){
 
1379
    return 0;
 
1380
  }
 
1381
  
 
1382
  struct ifreq ifr;
 
1383
  if(not get_flags(if_entry->d_name, &ifr)){
 
1384
    if(debug){
 
1385
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1386
                   "\"%s\"\n", if_entry->d_name);
 
1387
    }
 
1388
    return 0;
 
1389
  }
 
1390
  
 
1391
  if(not good_flags(if_entry->d_name, &ifr)){
 
1392
    return 0;
 
1393
  }
 
1394
  return 1;
 
1395
}
 
1396
 
 
1397
/* 
 
1398
 * This function determines if a network interface is up.
 
1399
 */
 
1400
__attribute__((nonnull, warn_unused_result))
 
1401
bool interface_is_up(const char *interface){
 
1402
  struct ifreq ifr;
 
1403
  if(not get_flags(interface, &ifr)){
 
1404
    if(debug){
 
1405
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1406
                   "\"%s\"\n", interface);
 
1407
    }
 
1408
    return false;
 
1409
  }
 
1410
  
 
1411
  return (bool)(ifr.ifr_flags & IFF_UP);
 
1412
}
 
1413
 
 
1414
/* 
 
1415
 * This function determines if a network interface is running
 
1416
 */
 
1417
__attribute__((nonnull, warn_unused_result))
 
1418
bool interface_is_running(const char *interface){
 
1419
  struct ifreq ifr;
 
1420
  if(not get_flags(interface, &ifr)){
 
1421
    if(debug){
 
1422
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1423
                   "\"%s\"\n", interface);
 
1424
    }
 
1425
    return false;
 
1426
  }
 
1427
  
 
1428
  return (bool)(ifr.ifr_flags & IFF_RUNNING);
 
1429
}
 
1430
 
 
1431
__attribute__((nonnull, pure, warn_unused_result))
 
1432
int notdotentries(const struct dirent *direntry){
 
1433
  /* Skip "." and ".." */
 
1434
  if(direntry->d_name[0] == '.'
 
1435
     and (direntry->d_name[1] == '\0'
 
1436
          or (direntry->d_name[1] == '.'
 
1437
              and direntry->d_name[2] == '\0'))){
 
1438
    return 0;
 
1439
  }
 
1440
  return 1;
 
1441
}
 
1442
 
 
1443
/* Is this directory entry a runnable program? */
 
1444
__attribute__((nonnull, warn_unused_result))
 
1445
int runnable_hook(const struct dirent *direntry){
 
1446
  int ret;
 
1447
  size_t sret;
 
1448
  struct stat st;
 
1449
  
 
1450
  if((direntry->d_name)[0] == '\0'){
 
1451
    /* Empty name? */
 
1452
    return 0;
 
1453
  }
 
1454
  
 
1455
  sret = strspn(direntry->d_name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
1456
                "abcdefghijklmnopqrstuvwxyz"
 
1457
                "0123456789"
 
1458
                "_.-");
 
1459
  if((direntry->d_name)[sret] != '\0'){
 
1460
    /* Contains non-allowed characters */
 
1461
    if(debug){
 
1462
      fprintf_plus(stderr, "Ignoring hook \"%s\" with bad name\n",
 
1463
                   direntry->d_name);
 
1464
    }
 
1465
    return 0;
 
1466
  }
 
1467
  
 
1468
  ret = fstatat(hookdir_fd, direntry->d_name, &st, 0);
 
1469
  if(ret == -1){
 
1470
    if(debug){
 
1471
      perror_plus("Could not stat hook");
 
1472
    }
 
1473
    return 0;
 
1474
  }
 
1475
  if(not (S_ISREG(st.st_mode))){
 
1476
    /* Not a regular file */
 
1477
    if(debug){
 
1478
      fprintf_plus(stderr, "Ignoring hook \"%s\" - not a file\n",
 
1479
                   direntry->d_name);
 
1480
    }
 
1481
    return 0;
 
1482
  }
 
1483
  if(not (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))){
 
1484
    /* Not executable */
 
1485
    if(debug){
 
1486
      fprintf_plus(stderr, "Ignoring hook \"%s\" - not executable\n",
 
1487
                   direntry->d_name);
 
1488
    }
 
1489
    return 0;
 
1490
  }
 
1491
  if(debug){
 
1492
    fprintf_plus(stderr, "Hook \"%s\" is acceptable\n",
 
1493
                 direntry->d_name);
 
1494
  }
 
1495
  return 1;
 
1496
}
 
1497
 
 
1498
__attribute__((nonnull, warn_unused_result))
 
1499
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval,
 
1500
                            mandos_context *mc){
 
1501
  int ret;
 
1502
  struct timespec now;
 
1503
  struct timespec waited_time;
 
1504
  intmax_t block_time;
 
1505
  
 
1506
  while(true){
 
1507
    if(mc->current_server == NULL){
 
1508
      if(debug){
 
1509
        fprintf_plus(stderr, "Wait until first server is found."
 
1510
                     " No timeout!\n");
 
1511
      }
 
1512
      ret = avahi_simple_poll_iterate(s, -1);
 
1513
    } else {
 
1514
      if(debug){
 
1515
        fprintf_plus(stderr, "Check current_server if we should run"
 
1516
                     " it, or wait\n");
 
1517
      }
 
1518
      /* the current time */
 
1519
      ret = clock_gettime(CLOCK_MONOTONIC, &now);
 
1520
      if(ret == -1){
 
1521
        perror_plus("clock_gettime");
 
1522
        return -1;
 
1523
      }
 
1524
      /* Calculating in ms how long time between now and server
 
1525
         who we visted longest time ago. Now - last seen.  */
 
1526
      waited_time.tv_sec = (now.tv_sec
 
1527
                            - mc->current_server->last_seen.tv_sec);
 
1528
      waited_time.tv_nsec = (now.tv_nsec
 
1529
                             - mc->current_server->last_seen.tv_nsec);
 
1530
      /* total time is 10s/10,000ms.
 
1531
         Converting to s from ms by dividing by 1,000,
 
1532
         and ns to ms by dividing by 1,000,000. */
 
1533
      block_time = ((retry_interval
 
1534
                     - ((intmax_t)waited_time.tv_sec * 1000))
 
1535
                    - ((intmax_t)waited_time.tv_nsec / 1000000));
 
1536
      
 
1537
      if(debug){
 
1538
        fprintf_plus(stderr, "Blocking for %" PRIdMAX " ms\n",
 
1539
                     block_time);
 
1540
      }
 
1541
      
 
1542
      if(block_time <= 0){
 
1543
        ret = start_mandos_communication(mc->current_server->ip,
 
1544
                                         mc->current_server->port,
 
1545
                                         mc->current_server->if_index,
 
1546
                                         mc->current_server->af, mc);
 
1547
        if(ret == 0){
 
1548
          avahi_simple_poll_quit(s);
 
1549
          return 0;
 
1550
        }
 
1551
        ret = clock_gettime(CLOCK_MONOTONIC,
 
1552
                            &mc->current_server->last_seen);
 
1553
        if(ret == -1){
 
1554
          perror_plus("clock_gettime");
 
1555
          return -1;
 
1556
        }
 
1557
        mc->current_server = mc->current_server->next;
 
1558
        block_time = 0;         /* Call avahi to find new Mandos
 
1559
                                   servers, but don't block */
 
1560
      }
 
1561
      
 
1562
      ret = avahi_simple_poll_iterate(s, (int)block_time);
 
1563
    }
 
1564
    if(ret != 0){
 
1565
      if(ret > 0 or errno != EINTR){
 
1566
        return (ret != 1) ? ret : 0;
 
1567
      }
 
1568
    }
 
1569
  }
 
1570
}
 
1571
 
 
1572
/* Set effective uid to 0, return errno */
 
1573
__attribute__((warn_unused_result))
 
1574
error_t raise_privileges(void){
 
1575
  error_t old_errno = errno;
 
1576
  error_t ret_errno = 0;
 
1577
  if(seteuid(0) == -1){
 
1578
    ret_errno = errno;
 
1579
  }
 
1580
  errno = old_errno;
 
1581
  return ret_errno;
 
1582
}
 
1583
 
 
1584
/* Set effective and real user ID to 0.  Return errno. */
 
1585
__attribute__((warn_unused_result))
 
1586
error_t raise_privileges_permanently(void){
 
1587
  error_t old_errno = errno;
 
1588
  error_t ret_errno = raise_privileges();
 
1589
  if(ret_errno != 0){
 
1590
    errno = old_errno;
 
1591
    return ret_errno;
 
1592
  }
 
1593
  if(setuid(0) == -1){
 
1594
    ret_errno = errno;
 
1595
  }
 
1596
  errno = old_errno;
 
1597
  return ret_errno;
 
1598
}
 
1599
 
 
1600
/* Set effective user ID to unprivileged saved user ID */
 
1601
__attribute__((warn_unused_result))
 
1602
error_t lower_privileges(void){
 
1603
  error_t old_errno = errno;
 
1604
  error_t ret_errno = 0;
 
1605
  if(seteuid(uid) == -1){
 
1606
    ret_errno = errno;
 
1607
  }
 
1608
  errno = old_errno;
 
1609
  return ret_errno;
 
1610
}
 
1611
 
 
1612
/* Lower privileges permanently */
 
1613
__attribute__((warn_unused_result))
 
1614
error_t lower_privileges_permanently(void){
 
1615
  error_t old_errno = errno;
 
1616
  error_t ret_errno = 0;
 
1617
  if(setuid(uid) == -1){
 
1618
    ret_errno = errno;
 
1619
  }
 
1620
  errno = old_errno;
 
1621
  return ret_errno;
 
1622
}
 
1623
 
 
1624
__attribute__((nonnull))
 
1625
void run_network_hooks(const char *mode, const char *interface,
 
1626
                       const float delay){
 
1627
  struct dirent **direntries = NULL;
 
1628
  if(hookdir_fd == -1){
 
1629
    hookdir_fd = open(hookdir, O_RDONLY);
 
1630
    if(hookdir_fd == -1){
 
1631
      if(errno == ENOENT){
 
1632
        if(debug){
 
1633
          fprintf_plus(stderr, "Network hook directory \"%s\" not"
 
1634
                       " found\n", hookdir);
 
1635
        }
 
1636
      } else {
 
1637
        perror_plus("open");
 
1638
      }
 
1639
      return;
 
1640
    }
 
1641
  }
 
1642
#ifdef __GLIBC__
 
1643
#if __GLIBC_PREREQ(2, 15)
 
1644
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
 
1645
                           runnable_hook, alphasort);
 
1646
#else  /* not __GLIBC_PREREQ(2, 15) */
 
1647
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
 
1648
                         alphasort);
 
1649
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
1650
#else   /* not __GLIBC__ */
 
1651
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
 
1652
                         alphasort);
 
1653
#endif  /* not __GLIBC__ */
 
1654
  if(numhooks == -1){
 
1655
    perror_plus("scandir");
 
1656
    return;
 
1657
  }
 
1658
  struct dirent *direntry;
 
1659
  int ret;
 
1660
  int devnull = open("/dev/null", O_RDONLY);
 
1661
  for(int i = 0; i < numhooks; i++){
 
1662
    direntry = direntries[i];
 
1663
    if(debug){
 
1664
      fprintf_plus(stderr, "Running network hook \"%s\"\n",
 
1665
                   direntry->d_name);
 
1666
    }
 
1667
    pid_t hook_pid = fork();
 
1668
    if(hook_pid == 0){
 
1669
      /* Child */
 
1670
      /* Raise privileges */
 
1671
      errno = raise_privileges_permanently();
 
1672
      if(errno != 0){
 
1673
        perror_plus("Failed to raise privileges");
 
1674
        _exit(EX_NOPERM);
 
1675
      }
 
1676
      /* Set group */
 
1677
      errno = 0;
 
1678
      ret = setgid(0);
 
1679
      if(ret == -1){
 
1680
        perror_plus("setgid");
 
1681
        _exit(EX_NOPERM);
 
1682
      }
 
1683
      /* Reset supplementary groups */
 
1684
      errno = 0;
 
1685
      ret = setgroups(0, NULL);
 
1686
      if(ret == -1){
 
1687
        perror_plus("setgroups");
 
1688
        _exit(EX_NOPERM);
 
1689
      }
 
1690
      ret = dup2(devnull, STDIN_FILENO);
 
1691
      if(ret == -1){
 
1692
        perror_plus("dup2(devnull, STDIN_FILENO)");
 
1693
        _exit(EX_OSERR);
 
1694
      }
 
1695
      ret = close(devnull);
 
1696
      if(ret == -1){
 
1697
        perror_plus("close");
 
1698
        _exit(EX_OSERR);
 
1699
      }
 
1700
      ret = dup2(STDERR_FILENO, STDOUT_FILENO);
 
1701
      if(ret == -1){
 
1702
        perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
 
1703
        _exit(EX_OSERR);
 
1704
      }
 
1705
      ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
 
1706
      if(ret == -1){
 
1707
        perror_plus("setenv");
 
1708
        _exit(EX_OSERR);
 
1709
      }
 
1710
      ret = setenv("DEVICE", interface, 1);
 
1711
      if(ret == -1){
 
1712
        perror_plus("setenv");
 
1713
        _exit(EX_OSERR);
 
1714
      }
 
1715
      ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
 
1716
      if(ret == -1){
 
1717
        perror_plus("setenv");
 
1718
        _exit(EX_OSERR);
 
1719
      }
 
1720
      ret = setenv("MODE", mode, 1);
 
1721
      if(ret == -1){
 
1722
        perror_plus("setenv");
 
1723
        _exit(EX_OSERR);
 
1724
      }
 
1725
      char *delaystring;
 
1726
      ret = asprintf(&delaystring, "%f", (double)delay);
 
1727
      if(ret == -1){
 
1728
        perror_plus("asprintf");
 
1729
        _exit(EX_OSERR);
 
1730
      }
 
1731
      ret = setenv("DELAY", delaystring, 1);
 
1732
      if(ret == -1){
 
1733
        free(delaystring);
 
1734
        perror_plus("setenv");
 
1735
        _exit(EX_OSERR);
 
1736
      }
 
1737
      free(delaystring);
 
1738
      if(connect_to != NULL){
 
1739
        ret = setenv("CONNECT", connect_to, 1);
 
1740
        if(ret == -1){
 
1741
          perror_plus("setenv");
 
1742
          _exit(EX_OSERR);
 
1743
        }
 
1744
      }
 
1745
      int hook_fd = openat(hookdir_fd, direntry->d_name, O_RDONLY);
 
1746
      if(hook_fd == -1){
 
1747
        perror_plus("openat");
 
1748
        _exit(EXIT_FAILURE);
 
1749
      }
 
1750
      if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1751
        perror_plus("close");
 
1752
        _exit(EXIT_FAILURE);
 
1753
      }
 
1754
      if(fexecve(hook_fd, (char *const []){ direntry->d_name, NULL },
 
1755
                 environ) == -1){
 
1756
        perror_plus("fexecve");
 
1757
        _exit(EXIT_FAILURE);
 
1758
      }
 
1759
    } else {
 
1760
      if(hook_pid == -1){
 
1761
        perror_plus("fork");
 
1762
        free(direntry);
 
1763
        continue;
 
1764
      }
 
1765
      int status;
 
1766
      if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
 
1767
        perror_plus("waitpid");
 
1768
        free(direntry);
 
1769
        continue;
 
1770
      }
 
1771
      if(WIFEXITED(status)){
 
1772
        if(WEXITSTATUS(status) != 0){
 
1773
          fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
 
1774
                       " with status %d\n", direntry->d_name,
 
1775
                       WEXITSTATUS(status));
 
1776
          free(direntry);
 
1777
          continue;
 
1778
        }
 
1779
      } else if(WIFSIGNALED(status)){
 
1780
        fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
 
1781
                     " signal %d\n", direntry->d_name,
 
1782
                     WTERMSIG(status));
 
1783
        free(direntry);
 
1784
        continue;
 
1785
      } else {
 
1786
        fprintf_plus(stderr, "Warning: network hook \"%s\""
 
1787
                     " crashed\n", direntry->d_name);
 
1788
        free(direntry);
 
1789
        continue;
 
1790
      }
 
1791
    }
 
1792
    if(debug){
 
1793
      fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
 
1794
                   direntry->d_name);
 
1795
    }
 
1796
    free(direntry);
 
1797
  }
 
1798
  free(direntries);
 
1799
  if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1800
    perror_plus("close");
 
1801
  } else {
 
1802
    hookdir_fd = -1;
 
1803
  }
 
1804
  close(devnull);
 
1805
}
 
1806
 
 
1807
__attribute__((nonnull, warn_unused_result))
 
1808
error_t bring_up_interface(const char *const interface,
 
1809
                           const float delay){
 
1810
  error_t old_errno = errno;
 
1811
  int ret;
 
1812
  struct ifreq network;
 
1813
  unsigned int if_index = if_nametoindex(interface);
 
1814
  if(if_index == 0){
 
1815
    fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
 
1816
    errno = old_errno;
 
1817
    return ENXIO;
 
1818
  }
 
1819
  
 
1820
  if(quit_now){
 
1821
    errno = old_errno;
 
1822
    return EINTR;
 
1823
  }
 
1824
  
 
1825
  if(not interface_is_up(interface)){
 
1826
    error_t ret_errno = 0, ioctl_errno = 0;
 
1827
    if(not get_flags(interface, &network)){
 
1828
      ret_errno = errno;
 
1829
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1830
                   "\"%s\"\n", interface);
 
1831
      errno = old_errno;
 
1832
      return ret_errno;
 
1833
    }
 
1834
    network.ifr_flags |= IFF_UP; /* set flag */
 
1835
    
 
1836
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1837
    if(sd == -1){
 
1838
      ret_errno = errno;
 
1839
      perror_plus("socket");
 
1840
      errno = old_errno;
 
1841
      return ret_errno;
 
1842
    }
 
1843
    
 
1844
    if(quit_now){
 
1845
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1846
      if(ret == -1){
 
1847
        perror_plus("close");
 
1848
      }
 
1849
      errno = old_errno;
 
1850
      return EINTR;
 
1851
    }
 
1852
    
 
1853
    if(debug){
 
1854
      fprintf_plus(stderr, "Bringing up interface \"%s\"\n",
 
1855
                   interface);
 
1856
    }
 
1857
    
 
1858
    /* Raise privileges */
 
1859
    ret_errno = raise_privileges();
 
1860
    if(ret_errno != 0){
 
1861
      errno = ret_errno;
 
1862
      perror_plus("Failed to raise privileges");
 
1863
    }
 
1864
    
 
1865
#ifdef __linux__
 
1866
    int ret_linux;
 
1867
    bool restore_loglevel = false;
 
1868
    if(ret_errno == 0){
 
1869
      /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1870
         messages about the network interface to mess up the prompt */
 
1871
      ret_linux = klogctl(8, NULL, 5);
 
1872
      if(ret_linux == -1){
 
1873
        perror_plus("klogctl");
 
1874
      } else {
 
1875
        restore_loglevel = true;
 
1876
      }
 
1877
    }
 
1878
#endif  /* __linux__ */
 
1879
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1880
    ioctl_errno = errno;
 
1881
#ifdef __linux__
 
1882
    if(restore_loglevel){
 
1883
      ret_linux = klogctl(7, NULL, 0);
 
1884
      if(ret_linux == -1){
 
1885
        perror_plus("klogctl");
 
1886
      }
 
1887
    }
 
1888
#endif  /* __linux__ */
 
1889
    
 
1890
    /* If raise_privileges() succeeded above */
 
1891
    if(ret_errno == 0){
 
1892
      /* Lower privileges */
 
1893
      ret_errno = lower_privileges();
 
1894
      if(ret_errno != 0){
 
1895
        errno = ret_errno;
 
1896
        perror_plus("Failed to lower privileges");
 
1897
      }
 
1898
    }
 
1899
    
 
1900
    /* Close the socket */
 
1901
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1902
    if(ret == -1){
 
1903
      perror_plus("close");
 
1904
    }
 
1905
    
 
1906
    if(ret_setflags == -1){
 
1907
      errno = ioctl_errno;
 
1908
      perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
 
1909
      errno = old_errno;
 
1910
      return ioctl_errno;
 
1911
    }
 
1912
  } else if(debug){
 
1913
    fprintf_plus(stderr, "Interface \"%s\" is already up; good\n",
 
1914
                 interface);
 
1915
  }
 
1916
  
 
1917
  /* Sleep checking until interface is running.
 
1918
     Check every 0.25s, up to total time of delay */
 
1919
  for(int i=0; i < delay * 4; i++){
 
1920
    if(interface_is_running(interface)){
 
1921
      break;
 
1922
    }
 
1923
    struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1924
    ret = nanosleep(&sleeptime, NULL);
 
1925
    if(ret == -1 and errno != EINTR){
 
1926
      perror_plus("nanosleep");
 
1927
    }
 
1928
  }
 
1929
  
 
1930
  errno = old_errno;
 
1931
  return 0;
 
1932
}
 
1933
 
 
1934
__attribute__((nonnull, warn_unused_result))
 
1935
error_t take_down_interface(const char *const interface){
 
1936
  error_t old_errno = errno;
 
1937
  struct ifreq network;
 
1938
  unsigned int if_index = if_nametoindex(interface);
 
1939
  if(if_index == 0){
 
1940
    fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
 
1941
    errno = old_errno;
 
1942
    return ENXIO;
 
1943
  }
 
1944
  if(interface_is_up(interface)){
 
1945
    error_t ret_errno = 0, ioctl_errno = 0;
 
1946
    if(not get_flags(interface, &network) and debug){
 
1947
      ret_errno = errno;
 
1948
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1949
                   "\"%s\"\n", interface);
 
1950
      errno = old_errno;
 
1951
      return ret_errno;
 
1952
    }
 
1953
    network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
 
1954
    
 
1955
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1956
    if(sd == -1){
 
1957
      ret_errno = errno;
 
1958
      perror_plus("socket");
 
1959
      errno = old_errno;
 
1960
      return ret_errno;
 
1961
    }
 
1962
    
 
1963
    if(debug){
 
1964
      fprintf_plus(stderr, "Taking down interface \"%s\"\n",
 
1965
                   interface);
 
1966
    }
 
1967
    
 
1968
    /* Raise privileges */
 
1969
    ret_errno = raise_privileges();
 
1970
    if(ret_errno != 0){
 
1971
      errno = ret_errno;
 
1972
      perror_plus("Failed to raise privileges");
 
1973
    }
 
1974
    
 
1975
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1976
    ioctl_errno = errno;
 
1977
    
 
1978
    /* If raise_privileges() succeeded above */
 
1979
    if(ret_errno == 0){
 
1980
      /* Lower privileges */
 
1981
      ret_errno = lower_privileges();
 
1982
      if(ret_errno != 0){
 
1983
        errno = ret_errno;
 
1984
        perror_plus("Failed to lower privileges");
 
1985
      }
 
1986
    }
 
1987
    
 
1988
    /* Close the socket */
 
1989
    int ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1990
    if(ret == -1){
 
1991
      perror_plus("close");
 
1992
    }
 
1993
    
 
1994
    if(ret_setflags == -1){
 
1995
      errno = ioctl_errno;
 
1996
      perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
 
1997
      errno = old_errno;
 
1998
      return ioctl_errno;
 
1999
    }
 
2000
  } else if(debug){
 
2001
    fprintf_plus(stderr, "Interface \"%s\" is already down; odd\n",
 
2002
                 interface);
 
2003
  }
 
2004
  
 
2005
  errno = old_errno;
 
2006
  return 0;
1021
2007
}
1022
2008
 
1023
2009
int main(int argc, char *argv[]){
 
2010
  mandos_context mc = { .server = NULL, .dh_bits = 0,
 
2011
                        .priority = "SECURE256:!CTYPE-X.509:"
 
2012
                        "+CTYPE-OPENPGP:!RSA", .current_server = NULL,
 
2013
                        .interfaces = NULL, .interfaces_size = 0 };
1024
2014
  AvahiSServiceBrowser *sb = NULL;
1025
 
  int error;
 
2015
  error_t ret_errno;
1026
2016
  int ret;
1027
2017
  intmax_t tmpmax;
1028
2018
  char *tmp;
1029
2019
  int exitcode = EXIT_SUCCESS;
1030
 
  const char *interface = "eth0";
1031
 
  struct ifreq network;
1032
 
  int sd = -1;
1033
 
  bool take_down_interface = false;
1034
 
  uid_t uid;
1035
 
  gid_t gid;
1036
 
  char *connect_to = NULL;
1037
 
  char tempdir[] = "/tmp/mandosXXXXXX";
1038
 
  bool tempdir_created = false;
 
2020
  char *interfaces_to_take_down = NULL;
 
2021
  size_t interfaces_to_take_down_size = 0;
 
2022
  char run_tempdir[] = "/run/tmp/mandosXXXXXX";
 
2023
  char old_tempdir[] = "/tmp/mandosXXXXXX";
 
2024
  char *tempdir = NULL;
1039
2025
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1040
2026
  const char *seckey = PATHDIR "/" SECKEY;
1041
2027
  const char *pubkey = PATHDIR "/" PUBKEY;
 
2028
  char *interfaces_hooks = NULL;
1042
2029
  
1043
2030
  bool gnutls_initialized = false;
1044
2031
  bool gpgme_initialized = false;
1045
2032
  float delay = 2.5f;
 
2033
  double retry_interval = 10; /* 10s between trying a server and
 
2034
                                 retrying the same server again */
1046
2035
  
1047
2036
  struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1048
2037
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1054
2043
  errno = 0;
1055
2044
  ret = setgid(gid);
1056
2045
  if(ret == -1){
1057
 
    perror("setgid");
 
2046
    perror_plus("setgid");
1058
2047
  }
1059
2048
  
1060
2049
  /* Lower user privileges (temporarily) */
1061
2050
  errno = 0;
1062
2051
  ret = seteuid(uid);
1063
2052
  if(ret == -1){
1064
 
    perror("seteuid");
 
2053
    perror_plus("seteuid");
1065
2054
  }
1066
2055
  
1067
2056
  if(quit_now){
1102
2091
        .arg = "SECONDS",
1103
2092
        .doc = "Maximum delay to wait for interface startup",
1104
2093
        .group = 2 },
 
2094
      { .name = "retry", .key = 132,
 
2095
        .arg = "SECONDS",
 
2096
        .doc = "Retry interval used when denied by the Mandos server",
 
2097
        .group = 2 },
 
2098
      { .name = "network-hook-dir", .key = 133,
 
2099
        .arg = "DIR",
 
2100
        .doc = "Directory where network hooks are located",
 
2101
        .group = 2 },
1105
2102
      /*
1106
2103
       * These reproduce what we would get without ARGP_NO_HELP
1107
2104
       */
1125
2122
        connect_to = arg;
1126
2123
        break;
1127
2124
      case 'i':                 /* --interface */
1128
 
        interface = arg;
 
2125
        ret_errno = argz_add_sep(&mc.interfaces, &mc.interfaces_size,
 
2126
                                 arg, (int)',');
 
2127
        if(ret_errno != 0){
 
2128
          argp_error(state, "%s", strerror(ret_errno));
 
2129
        }
1129
2130
        break;
1130
2131
      case 's':                 /* --seckey */
1131
2132
        seckey = arg;
1151
2152
        if(errno != 0 or tmp == arg or *tmp != '\0'){
1152
2153
          argp_error(state, "Bad delay");
1153
2154
        }
 
2155
      case 132:                 /* --retry */
 
2156
        errno = 0;
 
2157
        retry_interval = strtod(arg, &tmp);
 
2158
        if(errno != 0 or tmp == arg or *tmp != '\0'
 
2159
           or (retry_interval * 1000) > INT_MAX
 
2160
           or retry_interval < 0){
 
2161
          argp_error(state, "Bad retry interval");
 
2162
        }
 
2163
        break;
 
2164
      case 133:                 /* --network-hook-dir */
 
2165
        hookdir = arg;
1154
2166
        break;
1155
2167
        /*
1156
2168
         * These reproduce what we would get without ARGP_NO_HELP
1163
2175
        argp_state_help(state, state->out_stream,
1164
2176
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1165
2177
      case 'V':                 /* --version */
1166
 
        fprintf(state->out_stream, "%s\n", argp_program_version);
 
2178
        fprintf_plus(state->out_stream, "%s\n", argp_program_version);
1167
2179
        exit(argp_err_exit_status);
1168
2180
        break;
1169
2181
      default:
1184
2196
    case ENOMEM:
1185
2197
    default:
1186
2198
      errno = ret;
1187
 
      perror("argp_parse");
 
2199
      perror_plus("argp_parse");
1188
2200
      exitcode = EX_OSERR;
1189
2201
      goto end;
1190
2202
    case EINVAL:
1192
2204
      goto end;
1193
2205
    }
1194
2206
  }
 
2207
    
 
2208
  {
 
2209
    /* Work around Debian bug #633582:
 
2210
       <http://bugs.debian.org/633582> */
 
2211
    
 
2212
    /* Re-raise privileges */
 
2213
    ret_errno = raise_privileges();
 
2214
    if(ret_errno != 0){
 
2215
      errno = ret_errno;
 
2216
      perror_plus("Failed to raise privileges");
 
2217
    } else {
 
2218
      struct stat st;
 
2219
      
 
2220
      if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
 
2221
        int seckey_fd = open(seckey, O_RDONLY);
 
2222
        if(seckey_fd == -1){
 
2223
          perror_plus("open");
 
2224
        } else {
 
2225
          ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
 
2226
          if(ret == -1){
 
2227
            perror_plus("fstat");
 
2228
          } else {
 
2229
            if(S_ISREG(st.st_mode)
 
2230
               and st.st_uid == 0 and st.st_gid == 0){
 
2231
              ret = fchown(seckey_fd, uid, gid);
 
2232
              if(ret == -1){
 
2233
                perror_plus("fchown");
 
2234
              }
 
2235
            }
 
2236
          }
 
2237
          TEMP_FAILURE_RETRY(close(seckey_fd));
 
2238
        }
 
2239
      }
 
2240
    
 
2241
      if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){
 
2242
        int pubkey_fd = open(pubkey, O_RDONLY);
 
2243
        if(pubkey_fd == -1){
 
2244
          perror_plus("open");
 
2245
        } else {
 
2246
          ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
 
2247
          if(ret == -1){
 
2248
            perror_plus("fstat");
 
2249
          } else {
 
2250
            if(S_ISREG(st.st_mode)
 
2251
               and st.st_uid == 0 and st.st_gid == 0){
 
2252
              ret = fchown(pubkey_fd, uid, gid);
 
2253
              if(ret == -1){
 
2254
                perror_plus("fchown");
 
2255
              }
 
2256
            }
 
2257
          }
 
2258
          TEMP_FAILURE_RETRY(close(pubkey_fd));
 
2259
        }
 
2260
      }
 
2261
    
 
2262
      /* Lower privileges */
 
2263
      ret_errno = lower_privileges();
 
2264
      if(ret_errno != 0){
 
2265
        errno = ret_errno;
 
2266
        perror_plus("Failed to lower privileges");
 
2267
      }
 
2268
    }
 
2269
  }
 
2270
  
 
2271
  /* Remove invalid interface names (except "none") */
 
2272
  {
 
2273
    char *interface = NULL;
 
2274
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
 
2275
                                 interface))){
 
2276
      if(strcmp(interface, "none") != 0
 
2277
         and if_nametoindex(interface) == 0){
 
2278
        if(interface[0] != '\0'){
 
2279
          fprintf_plus(stderr, "Not using nonexisting interface"
 
2280
                       " \"%s\"\n", interface);
 
2281
        }
 
2282
        argz_delete(&mc.interfaces, &mc.interfaces_size, interface);
 
2283
        interface = NULL;
 
2284
      }
 
2285
    }
 
2286
  }
 
2287
  
 
2288
  /* Run network hooks */
 
2289
  {
 
2290
    if(mc.interfaces != NULL){
 
2291
      interfaces_hooks = malloc(mc.interfaces_size);
 
2292
      if(interfaces_hooks == NULL){
 
2293
        perror_plus("malloc");
 
2294
        goto end;
 
2295
      }
 
2296
      memcpy(interfaces_hooks, mc.interfaces, mc.interfaces_size);
 
2297
      argz_stringify(interfaces_hooks, mc.interfaces_size, (int)',');
 
2298
    }
 
2299
    run_network_hooks("start", interfaces_hooks != NULL ?
 
2300
                      interfaces_hooks : "", delay);
 
2301
  }
1195
2302
  
1196
2303
  if(not debug){
1197
2304
    avahi_set_log_function(empty_log);
1201
2308
     from the signal handler */
1202
2309
  /* Initialize the pseudo-RNG for Avahi */
1203
2310
  srand((unsigned int) time(NULL));
1204
 
  mc.simple_poll = avahi_simple_poll_new();
1205
 
  if(mc.simple_poll == NULL){
1206
 
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
 
2311
  simple_poll = avahi_simple_poll_new();
 
2312
  if(simple_poll == NULL){
 
2313
    fprintf_plus(stderr,
 
2314
                 "Avahi: Failed to create simple poll object.\n");
1207
2315
    exitcode = EX_UNAVAILABLE;
1208
2316
    goto end;
1209
2317
  }
1211
2319
  sigemptyset(&sigterm_action.sa_mask);
1212
2320
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1213
2321
  if(ret == -1){
1214
 
    perror("sigaddset");
 
2322
    perror_plus("sigaddset");
1215
2323
    exitcode = EX_OSERR;
1216
2324
    goto end;
1217
2325
  }
1218
2326
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1219
2327
  if(ret == -1){
1220
 
    perror("sigaddset");
 
2328
    perror_plus("sigaddset");
1221
2329
    exitcode = EX_OSERR;
1222
2330
    goto end;
1223
2331
  }
1224
2332
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1225
2333
  if(ret == -1){
1226
 
    perror("sigaddset");
 
2334
    perror_plus("sigaddset");
1227
2335
    exitcode = EX_OSERR;
1228
2336
    goto end;
1229
2337
  }
1233
2341
  */
1234
2342
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1235
2343
  if(ret == -1){
1236
 
    perror("sigaction");
 
2344
    perror_plus("sigaction");
1237
2345
    return EX_OSERR;
1238
2346
  }
1239
2347
  if(old_sigterm_action.sa_handler != SIG_IGN){
1240
2348
    ret = sigaction(SIGINT, &sigterm_action, NULL);
1241
2349
    if(ret == -1){
1242
 
      perror("sigaction");
 
2350
      perror_plus("sigaction");
1243
2351
      exitcode = EX_OSERR;
1244
2352
      goto end;
1245
2353
    }
1246
2354
  }
1247
2355
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1248
2356
  if(ret == -1){
1249
 
    perror("sigaction");
 
2357
    perror_plus("sigaction");
1250
2358
    return EX_OSERR;
1251
2359
  }
1252
2360
  if(old_sigterm_action.sa_handler != SIG_IGN){
1253
2361
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
1254
2362
    if(ret == -1){
1255
 
      perror("sigaction");
 
2363
      perror_plus("sigaction");
1256
2364
      exitcode = EX_OSERR;
1257
2365
      goto end;
1258
2366
    }
1259
2367
  }
1260
2368
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1261
2369
  if(ret == -1){
1262
 
    perror("sigaction");
 
2370
    perror_plus("sigaction");
1263
2371
    return EX_OSERR;
1264
2372
  }
1265
2373
  if(old_sigterm_action.sa_handler != SIG_IGN){
1266
2374
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
1267
2375
    if(ret == -1){
1268
 
      perror("sigaction");
1269
 
      exitcode = EX_OSERR;
1270
 
      goto end;
1271
 
    }
1272
 
  }
1273
 
  
1274
 
  /* If the interface is down, bring it up */
1275
 
  if(interface[0] != '\0'){
1276
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1277
 
    if(if_index == 0){
1278
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1279
 
      exitcode = EX_UNAVAILABLE;
1280
 
      goto end;
1281
 
    }
1282
 
    
1283
 
    if(quit_now){
1284
 
      goto end;
1285
 
    }
1286
 
    
1287
 
    /* Re-raise priviliges */
1288
 
    errno = 0;
1289
 
    ret = seteuid(0);
1290
 
    if(ret == -1){
1291
 
      perror("seteuid");
1292
 
    }
1293
 
    
1294
 
#ifdef __linux__
1295
 
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1296
 
       messages about the network interface to mess up the prompt */
1297
 
    ret = klogctl(8, NULL, 5);
1298
 
    bool restore_loglevel = true;
1299
 
    if(ret == -1){
1300
 
      restore_loglevel = false;
1301
 
      perror("klogctl");
1302
 
    }
1303
 
#endif  /* __linux__ */
1304
 
    
1305
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1306
 
    if(sd < 0){
1307
 
      perror("socket");
1308
 
      exitcode = EX_OSERR;
1309
 
#ifdef __linux__
1310
 
      if(restore_loglevel){
1311
 
        ret = klogctl(7, NULL, 0);
1312
 
        if(ret == -1){
1313
 
          perror("klogctl");
1314
 
        }
1315
 
      }
1316
 
#endif  /* __linux__ */
1317
 
      /* Lower privileges */
1318
 
      errno = 0;
1319
 
      ret = seteuid(uid);
1320
 
      if(ret == -1){
1321
 
        perror("seteuid");
1322
 
      }
1323
 
      goto end;
1324
 
    }
1325
 
    strcpy(network.ifr_name, interface);
1326
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
1327
 
    if(ret == -1){
1328
 
      perror("ioctl SIOCGIFFLAGS");
1329
 
#ifdef __linux__
1330
 
      if(restore_loglevel){
1331
 
        ret = klogctl(7, NULL, 0);
1332
 
        if(ret == -1){
1333
 
          perror("klogctl");
1334
 
        }
1335
 
      }
1336
 
#endif  /* __linux__ */
1337
 
      exitcode = EX_OSERR;
1338
 
      /* Lower privileges */
1339
 
      errno = 0;
1340
 
      ret = seteuid(uid);
1341
 
      if(ret == -1){
1342
 
        perror("seteuid");
1343
 
      }
1344
 
      goto end;
1345
 
    }
1346
 
    if((network.ifr_flags & IFF_UP) == 0){
1347
 
      network.ifr_flags |= IFF_UP;
1348
 
      take_down_interface = true;
1349
 
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
1350
 
      if(ret == -1){
1351
 
        take_down_interface = false;
1352
 
        perror("ioctl SIOCSIFFLAGS");
1353
 
        exitcode = EX_OSERR;
1354
 
#ifdef __linux__
1355
 
        if(restore_loglevel){
1356
 
          ret = klogctl(7, NULL, 0);
1357
 
          if(ret == -1){
1358
 
            perror("klogctl");
 
2376
      perror_plus("sigaction");
 
2377
      exitcode = EX_OSERR;
 
2378
      goto end;
 
2379
    }
 
2380
  }
 
2381
  
 
2382
  /* If no interfaces were specified, make a list */
 
2383
  if(mc.interfaces == NULL){
 
2384
    struct dirent **direntries = NULL;
 
2385
    /* Look for any good interfaces */
 
2386
    ret = scandir(sys_class_net, &direntries, good_interface,
 
2387
                  alphasort);
 
2388
    if(ret >= 1){
 
2389
      /* Add all found interfaces to interfaces list */
 
2390
      for(int i = 0; i < ret; ++i){
 
2391
        ret_errno = argz_add(&mc.interfaces, &mc.interfaces_size,
 
2392
                             direntries[i]->d_name);
 
2393
        if(ret_errno != 0){
 
2394
          errno = ret_errno;
 
2395
          perror_plus("argz_add");
 
2396
          free(direntries[i]);
 
2397
          continue;
 
2398
        }
 
2399
        if(debug){
 
2400
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
 
2401
                       direntries[i]->d_name);
 
2402
        }
 
2403
        free(direntries[i]);
 
2404
      }
 
2405
      free(direntries);
 
2406
    } else {
 
2407
      if(ret == 0){
 
2408
        free(direntries);
 
2409
      }
 
2410
      fprintf_plus(stderr, "Could not find a network interface\n");
 
2411
      exitcode = EXIT_FAILURE;
 
2412
      goto end;
 
2413
    }
 
2414
  }
 
2415
  
 
2416
  /* Bring up interfaces which are down, and remove any "none"s */
 
2417
  {
 
2418
    char *interface = NULL;
 
2419
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
 
2420
                                 interface))){
 
2421
      /* If interface name is "none", stop bringing up interfaces.
 
2422
         Also remove all instances of "none" from the list */
 
2423
      if(strcmp(interface, "none") == 0){
 
2424
        argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2425
                    interface);
 
2426
        interface = NULL;
 
2427
        while((interface = argz_next(mc.interfaces,
 
2428
                                     mc.interfaces_size, interface))){
 
2429
          if(strcmp(interface, "none") == 0){
 
2430
            argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2431
                        interface);
 
2432
            interface = NULL;
1359
2433
          }
1360
2434
        }
1361
 
#endif  /* __linux__ */
1362
 
        /* Lower privileges */
1363
 
        errno = 0;
1364
 
        ret = seteuid(uid);
1365
 
        if(ret == -1){
1366
 
          perror("seteuid");
1367
 
        }
1368
 
        goto end;
1369
 
      }
1370
 
    }
1371
 
    /* sleep checking until interface is running */
1372
 
    for(int i=0; i < delay * 4; i++){
1373
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1374
 
      if(ret == -1){
1375
 
        perror("ioctl SIOCGIFFLAGS");
1376
 
      } else if(network.ifr_flags & IFF_RUNNING){
1377
2435
        break;
1378
2436
      }
1379
 
      struct timespec sleeptime = { .tv_nsec = 250000000 };
1380
 
      ret = nanosleep(&sleeptime, NULL);
1381
 
      if(ret == -1 and errno != EINTR){
1382
 
        perror("nanosleep");
1383
 
      }
1384
 
    }
1385
 
    if(not take_down_interface){
1386
 
      /* We won't need the socket anymore */
1387
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1388
 
      if(ret == -1){
1389
 
        perror("close");
1390
 
      }
1391
 
    }
1392
 
#ifdef __linux__
1393
 
    if(restore_loglevel){
1394
 
      /* Restores kernel loglevel to default */
1395
 
      ret = klogctl(7, NULL, 0);
1396
 
      if(ret == -1){
1397
 
        perror("klogctl");
1398
 
      }
1399
 
    }
1400
 
#endif  /* __linux__ */
1401
 
    /* Lower privileges */
1402
 
    errno = 0;
1403
 
    if(take_down_interface){
1404
 
      /* Lower privileges */
1405
 
      ret = seteuid(uid);
1406
 
      if(ret == -1){
1407
 
        perror("seteuid");
1408
 
      }
1409
 
    } else {
1410
 
      /* Lower privileges permanently */
1411
 
      ret = setuid(uid);
1412
 
      if(ret == -1){
1413
 
        perror("setuid");
1414
 
      }
1415
 
    }
 
2437
      bool interface_was_up = interface_is_up(interface);
 
2438
      errno = bring_up_interface(interface, delay);
 
2439
      if(not interface_was_up){
 
2440
        if(errno != 0){
 
2441
          perror_plus("Failed to bring up interface");
 
2442
        } else {
 
2443
          errno = argz_add(&interfaces_to_take_down,
 
2444
                           &interfaces_to_take_down_size,
 
2445
                           interface);
 
2446
          if(errno != 0){
 
2447
            perror_plus("argz_add");
 
2448
          }
 
2449
        }
 
2450
      }
 
2451
    }
 
2452
    if(debug and (interfaces_to_take_down == NULL)){
 
2453
      fprintf_plus(stderr, "No interfaces were brought up\n");
 
2454
    }
 
2455
  }
 
2456
  
 
2457
  /* If we only got one interface, explicitly use only that one */
 
2458
  if(argz_count(mc.interfaces, mc.interfaces_size) == 1){
 
2459
    if(debug){
 
2460
      fprintf_plus(stderr, "Using only interface \"%s\"\n",
 
2461
                   mc.interfaces);
 
2462
    }
 
2463
    if_index = (AvahiIfIndex)if_nametoindex(mc.interfaces);
1416
2464
  }
1417
2465
  
1418
2466
  if(quit_now){
1419
2467
    goto end;
1420
2468
  }
1421
2469
  
1422
 
  ret = init_gnutls_global(pubkey, seckey);
 
2470
  ret = init_gnutls_global(pubkey, seckey, &mc);
1423
2471
  if(ret == -1){
1424
 
    fprintf(stderr, "init_gnutls_global failed\n");
 
2472
    fprintf_plus(stderr, "init_gnutls_global failed\n");
1425
2473
    exitcode = EX_UNAVAILABLE;
1426
2474
    goto end;
1427
2475
  } else {
1432
2480
    goto end;
1433
2481
  }
1434
2482
  
1435
 
  tempdir_created = true;
1436
 
  if(mkdtemp(tempdir) == NULL){
1437
 
    tempdir_created = false;
1438
 
    perror("mkdtemp");
 
2483
  /* Try /run/tmp before /tmp */
 
2484
  tempdir = mkdtemp(run_tempdir);
 
2485
  if(tempdir == NULL and errno == ENOENT){
 
2486
      if(debug){
 
2487
        fprintf_plus(stderr, "Tempdir %s did not work, trying %s\n",
 
2488
                     run_tempdir, old_tempdir);
 
2489
      }
 
2490
      tempdir = mkdtemp(old_tempdir);
 
2491
  }
 
2492
  if(tempdir == NULL){
 
2493
    perror_plus("mkdtemp");
1439
2494
    goto end;
1440
2495
  }
1441
2496
  
1443
2498
    goto end;
1444
2499
  }
1445
2500
  
1446
 
  if(not init_gpgme(pubkey, seckey, tempdir)){
1447
 
    fprintf(stderr, "init_gpgme failed\n");
 
2501
  if(not init_gpgme(pubkey, seckey, tempdir, &mc)){
 
2502
    fprintf_plus(stderr, "init_gpgme failed\n");
1448
2503
    exitcode = EX_UNAVAILABLE;
1449
2504
    goto end;
1450
2505
  } else {
1459
2514
    /* Connect directly, do not use Zeroconf */
1460
2515
    /* (Mainly meant for debugging) */
1461
2516
    char *address = strrchr(connect_to, ':');
 
2517
    
1462
2518
    if(address == NULL){
1463
 
      fprintf(stderr, "No colon in address\n");
 
2519
      fprintf_plus(stderr, "No colon in address\n");
1464
2520
      exitcode = EX_USAGE;
1465
2521
      goto end;
1466
2522
    }
1469
2525
      goto end;
1470
2526
    }
1471
2527
    
1472
 
    uint16_t port;
 
2528
    in_port_t port;
1473
2529
    errno = 0;
1474
2530
    tmpmax = strtoimax(address+1, &tmp, 10);
1475
2531
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
1476
 
       or tmpmax != (uint16_t)tmpmax){
1477
 
      fprintf(stderr, "Bad port number\n");
 
2532
       or tmpmax != (in_port_t)tmpmax){
 
2533
      fprintf_plus(stderr, "Bad port number\n");
1478
2534
      exitcode = EX_USAGE;
1479
2535
      goto end;
1480
2536
    }
1481
 
  
 
2537
    
1482
2538
    if(quit_now){
1483
2539
      goto end;
1484
2540
    }
1485
2541
    
1486
 
    port = (uint16_t)tmpmax;
 
2542
    port = (in_port_t)tmpmax;
1487
2543
    *address = '\0';
1488
 
    address = connect_to;
1489
2544
    /* Colon in address indicates IPv6 */
1490
2545
    int af;
1491
 
    if(strchr(address, ':') != NULL){
 
2546
    if(strchr(connect_to, ':') != NULL){
1492
2547
      af = AF_INET6;
 
2548
      /* Accept [] around IPv6 address - see RFC 5952 */
 
2549
      if(connect_to[0] == '[' and address[-1] == ']')
 
2550
        {
 
2551
          connect_to++;
 
2552
          address[-1] = '\0';
 
2553
        }
1493
2554
    } else {
1494
2555
      af = AF_INET;
1495
2556
    }
 
2557
    address = connect_to;
1496
2558
    
1497
2559
    if(quit_now){
1498
2560
      goto end;
1499
2561
    }
1500
2562
    
1501
 
    ret = start_mandos_communication(address, port, if_index, af);
1502
 
    if(ret < 0){
1503
 
      switch(errno){
1504
 
      case ENETUNREACH:
1505
 
      case EHOSTDOWN:
1506
 
      case EHOSTUNREACH:
1507
 
        exitcode = EX_NOHOST;
1508
 
        break;
1509
 
      case EINVAL:
1510
 
        exitcode = EX_USAGE;
1511
 
        break;
1512
 
      case EIO:
1513
 
        exitcode = EX_IOERR;
1514
 
        break;
1515
 
      case EPROTO:
1516
 
        exitcode = EX_PROTOCOL;
1517
 
        break;
1518
 
      default:
1519
 
        exitcode = EX_OSERR;
1520
 
        break;
1521
 
      }
1522
 
    } else {
 
2563
    while(not quit_now){
 
2564
      ret = start_mandos_communication(address, port, if_index, af,
 
2565
                                       &mc);
 
2566
      if(quit_now or ret == 0){
 
2567
        break;
 
2568
      }
 
2569
      if(debug){
 
2570
        fprintf_plus(stderr, "Retrying in %d seconds\n",
 
2571
                     (int)retry_interval);
 
2572
      }
 
2573
      sleep((unsigned int)retry_interval);
 
2574
    }
 
2575
    
 
2576
    if(not quit_now){
1523
2577
      exitcode = EXIT_SUCCESS;
1524
2578
    }
 
2579
    
1525
2580
    goto end;
1526
2581
  }
1527
2582
  
1539
2594
    config.publish_domain = 0;
1540
2595
    
1541
2596
    /* Allocate a new server */
1542
 
    mc.server = avahi_server_new(avahi_simple_poll_get
1543
 
                                 (mc.simple_poll), &config, NULL,
1544
 
                                 NULL, &error);
 
2597
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
2598
                                 &config, NULL, NULL, &ret_errno);
1545
2599
    
1546
2600
    /* Free the Avahi configuration data */
1547
2601
    avahi_server_config_free(&config);
1549
2603
  
1550
2604
  /* Check if creating the Avahi server object succeeded */
1551
2605
  if(mc.server == NULL){
1552
 
    fprintf(stderr, "Failed to create Avahi server: %s\n",
1553
 
            avahi_strerror(error));
 
2606
    fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
 
2607
                 avahi_strerror(ret_errno));
1554
2608
    exitcode = EX_UNAVAILABLE;
1555
2609
    goto end;
1556
2610
  }
1562
2616
  /* Create the Avahi service browser */
1563
2617
  sb = avahi_s_service_browser_new(mc.server, if_index,
1564
2618
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1565
 
                                   NULL, 0, browse_callback, NULL);
 
2619
                                   NULL, 0, browse_callback,
 
2620
                                   (void *)&mc);
1566
2621
  if(sb == NULL){
1567
 
    fprintf(stderr, "Failed to create service browser: %s\n",
1568
 
            avahi_strerror(avahi_server_errno(mc.server)));
 
2622
    fprintf_plus(stderr, "Failed to create service browser: %s\n",
 
2623
                 avahi_strerror(avahi_server_errno(mc.server)));
1569
2624
    exitcode = EX_UNAVAILABLE;
1570
2625
    goto end;
1571
2626
  }
1577
2632
  /* Run the main loop */
1578
2633
  
1579
2634
  if(debug){
1580
 
    fprintf(stderr, "Starting Avahi loop search\n");
 
2635
    fprintf_plus(stderr, "Starting Avahi loop search\n");
1581
2636
  }
1582
2637
  
1583
 
  avahi_simple_poll_loop(mc.simple_poll);
 
2638
  ret = avahi_loop_with_timeout(simple_poll,
 
2639
                                (int)(retry_interval * 1000), &mc);
 
2640
  if(debug){
 
2641
    fprintf_plus(stderr, "avahi_loop_with_timeout exited %s\n",
 
2642
                 (ret == 0) ? "successfully" : "with error");
 
2643
  }
1584
2644
  
1585
2645
 end:
1586
2646
  
1587
2647
  if(debug){
1588
 
    fprintf(stderr, "%s exiting\n", argv[0]);
 
2648
    fprintf_plus(stderr, "%s exiting\n", argv[0]);
1589
2649
  }
1590
2650
  
1591
2651
  /* Cleanup things */
 
2652
  free(mc.interfaces);
 
2653
  
1592
2654
  if(sb != NULL)
1593
2655
    avahi_s_service_browser_free(sb);
1594
2656
  
1595
2657
  if(mc.server != NULL)
1596
2658
    avahi_server_free(mc.server);
1597
2659
  
1598
 
  if(mc.simple_poll != NULL)
1599
 
    avahi_simple_poll_free(mc.simple_poll);
 
2660
  if(simple_poll != NULL)
 
2661
    avahi_simple_poll_free(simple_poll);
1600
2662
  
1601
2663
  if(gnutls_initialized){
1602
2664
    gnutls_certificate_free_credentials(mc.cred);
1608
2670
    gpgme_release(mc.ctx);
1609
2671
  }
1610
2672
  
1611
 
  /* Take down the network interface */
1612
 
  if(take_down_interface){
1613
 
    /* Re-raise priviliges */
1614
 
    errno = 0;
1615
 
    ret = seteuid(0);
1616
 
    if(ret == -1){
1617
 
      perror("seteuid");
1618
 
    }
1619
 
    if(geteuid() == 0){
1620
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1621
 
      if(ret == -1){
1622
 
        perror("ioctl SIOCGIFFLAGS");
1623
 
      } else if(network.ifr_flags & IFF_UP) {
1624
 
        network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1625
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
1626
 
        if(ret == -1){
1627
 
          perror("ioctl SIOCSIFFLAGS");
1628
 
        }
1629
 
      }
1630
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1631
 
      if(ret == -1){
1632
 
        perror("close");
1633
 
      }
1634
 
      /* Lower privileges permanently */
1635
 
      errno = 0;
1636
 
      ret = setuid(uid);
1637
 
      if(ret == -1){
1638
 
        perror("setuid");
1639
 
      }
1640
 
    }
1641
 
  }
1642
 
  
1643
 
  /* Removes the temp directory used by GPGME */
1644
 
  if(tempdir_created){
1645
 
    DIR *d;
1646
 
    struct dirent *direntry;
1647
 
    d = opendir(tempdir);
1648
 
    if(d == NULL){
1649
 
      if(errno != ENOENT){
1650
 
        perror("opendir");
1651
 
      }
1652
 
    } else {
1653
 
      while(true){
1654
 
        direntry = readdir(d);
1655
 
        if(direntry == NULL){
1656
 
          break;
1657
 
        }
1658
 
        /* Skip "." and ".." */
1659
 
        if(direntry->d_name[0] == '.'
1660
 
           and (direntry->d_name[1] == '\0'
1661
 
                or (direntry->d_name[1] == '.'
1662
 
                    and direntry->d_name[2] == '\0'))){
1663
 
          continue;
1664
 
        }
1665
 
        char *fullname = NULL;
1666
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
1667
 
                       direntry->d_name);
1668
 
        if(ret < 0){
1669
 
          perror("asprintf");
1670
 
          continue;
1671
 
        }
1672
 
        ret = remove(fullname);
1673
 
        if(ret == -1){
1674
 
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1675
 
                  strerror(errno));
1676
 
        }
1677
 
        free(fullname);
1678
 
      }
1679
 
      closedir(d);
1680
 
    }
1681
 
    ret = rmdir(tempdir);
1682
 
    if(ret == -1 and errno != ENOENT){
1683
 
      perror("rmdir");
 
2673
  /* Cleans up the circular linked list of Mandos servers the client
 
2674
     has seen */
 
2675
  if(mc.current_server != NULL){
 
2676
    mc.current_server->prev->next = NULL;
 
2677
    while(mc.current_server != NULL){
 
2678
      server *next = mc.current_server->next;
 
2679
#ifdef __GNUC__
 
2680
#pragma GCC diagnostic push
 
2681
#pragma GCC diagnostic ignored "-Wcast-qual"
 
2682
#endif
 
2683
      free((char *)(mc.current_server->ip));
 
2684
#ifdef __GNUC__
 
2685
#pragma GCC diagnostic pop
 
2686
#endif
 
2687
      free(mc.current_server);
 
2688
      mc.current_server = next;
 
2689
    }
 
2690
  }
 
2691
  
 
2692
  /* Re-raise privileges */
 
2693
  {
 
2694
    ret_errno = raise_privileges();
 
2695
    if(ret_errno != 0){
 
2696
      errno = ret_errno;
 
2697
      perror_plus("Failed to raise privileges");
 
2698
    } else {
 
2699
      
 
2700
      /* Run network hooks */
 
2701
      run_network_hooks("stop", interfaces_hooks != NULL ?
 
2702
                        interfaces_hooks : "", delay);
 
2703
      
 
2704
      /* Take down the network interfaces which were brought up */
 
2705
      {
 
2706
        char *interface = NULL;
 
2707
        while((interface=argz_next(interfaces_to_take_down,
 
2708
                                   interfaces_to_take_down_size,
 
2709
                                   interface))){
 
2710
          ret_errno = take_down_interface(interface);
 
2711
          if(ret_errno != 0){
 
2712
            errno = ret_errno;
 
2713
            perror_plus("Failed to take down interface");
 
2714
          }
 
2715
        }
 
2716
        if(debug and (interfaces_to_take_down == NULL)){
 
2717
          fprintf_plus(stderr, "No interfaces needed to be taken"
 
2718
                       " down\n");
 
2719
        }
 
2720
      }
 
2721
    }
 
2722
    
 
2723
    ret_errno = lower_privileges_permanently();
 
2724
    if(ret_errno != 0){
 
2725
      errno = ret_errno;
 
2726
      perror_plus("Failed to lower privileges permanently");
 
2727
    }
 
2728
  }
 
2729
  
 
2730
  free(interfaces_to_take_down);
 
2731
  free(interfaces_hooks);
 
2732
  
 
2733
  /* Removes the GPGME temp directory and all files inside */
 
2734
  if(tempdir != NULL){
 
2735
    struct dirent **direntries = NULL;
 
2736
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY |
 
2737
                                                  O_NOFOLLOW));
 
2738
    if(tempdir_fd == -1){
 
2739
      perror_plus("open");
 
2740
    } else {
 
2741
#ifdef __GLIBC__
 
2742
#if __GLIBC_PREREQ(2, 15)
 
2743
      int numentries = scandirat(tempdir_fd, ".", &direntries,
 
2744
                                 notdotentries, alphasort);
 
2745
#else  /* not __GLIBC_PREREQ(2, 15) */
 
2746
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2747
                               alphasort);
 
2748
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
2749
#else   /* not __GLIBC__ */
 
2750
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2751
                               alphasort);
 
2752
#endif  /* not __GLIBC__ */
 
2753
      if(numentries >= 0){
 
2754
        for(int i = 0; i < numentries; i++){
 
2755
          ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
 
2756
          if(ret == -1){
 
2757
            fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
 
2758
                         " \"%s\", 0): %s\n", tempdir,
 
2759
                         direntries[i]->d_name, strerror(errno));
 
2760
          }
 
2761
          free(direntries[i]);
 
2762
        }
 
2763
        
 
2764
        /* need to clean even if 0 because man page doesn't specify */
 
2765
        free(direntries);
 
2766
        if(numentries == -1){
 
2767
          perror_plus("scandir");
 
2768
        }
 
2769
        ret = rmdir(tempdir);
 
2770
        if(ret == -1 and errno != ENOENT){
 
2771
          perror_plus("rmdir");
 
2772
        }
 
2773
      }
 
2774
      TEMP_FAILURE_RETRY(close(tempdir_fd));
1684
2775
    }
1685
2776
  }
1686
2777
  
1691
2782
                                            &old_sigterm_action,
1692
2783
                                            NULL));
1693
2784
    if(ret == -1){
1694
 
      perror("sigaction");
 
2785
      perror_plus("sigaction");
1695
2786
    }
1696
2787
    do {
1697
2788
      ret = raise(signal_received);
1698
2789
    } while(ret != 0 and errno == EINTR);
1699
2790
    if(ret != 0){
1700
 
      perror("raise");
 
2791
      perror_plus("raise");
1701
2792
      abort();
1702
2793
    }
1703
2794
    TEMP_FAILURE_RETRY(pause());