/mandos/release

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

« back to all changes in this revision

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

  • Committer: Teddy Hogeborn
  • Date: 2015-03-10 18:03:38 UTC
  • mto: (237.7.304 trunk)
  • mto: This revision was merged to the branch mainline in revision 325.
  • Revision ID: teddy@recompile.se-20150310180338-pcxw6r2qmw9k6br9
Add ":!RSA" to GnuTLS priority string, to disallow non-DHE kx.

If Mandos was somehow made to use a non-ephemeral Diffie-Hellman key
exchange algorithm in the TLS handshake, any saved network traffic
could then be decrypted later if the Mandos client key was obtained.
By default, Mandos uses ephemeral DH key exchanges which does not have
this problem, but a non-ephemeral key exchange algorithm was still
enabled by default.  The simplest solution is to simply turn that off,
which ensures that Mandos will always use ephemeral DH key exchanges.

There is a "PFS" priority string specifier, but we can't use it because:

1. Security-wise, it is a mix between "NORMAL" and "SECURE128" - it
   enables a lot more algorithms than "SECURE256".

2. It is only available since GnuTLS 3.2.4.

Thanks to Andreas Fischer <af@bantuX.org> for reporting this issue.

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
 
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
47
 
                                   srand(), strtof(), abort() */
 
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
 
47
                                   strtof(), abort() */
48
48
#include <stdbool.h>            /* bool, false, true */
49
49
#include <string.h>             /* memset(), strcmp(), strlen(),
50
50
                                   strerror(), asprintf(), strcpy() */
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,
82
84
#include <signal.h>             /* sigemptyset(), sigaddset(),
83
85
                                   sigaction(), SIGTERM, sig_atomic_t,
84
86
                                   raise() */
 
87
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
 
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() */
85
98
 
86
99
#ifdef __linux__
87
100
#include <sys/klog.h>           /* klogctl() */
105
118
                                   init_gnutls_session(),
106
119
                                   GNUTLS_* */
107
120
#include <gnutls/openpgp.h>
108
 
                          /* gnutls_certificate_set_openpgp_key_file(),
109
 
                                   GNUTLS_OPENPGP_FMT_BASE64 */
 
121
                         /* gnutls_certificate_set_openpgp_key_file(),
 
122
                            GNUTLS_OPENPGP_FMT_BASE64 */
110
123
 
111
124
/* GPGME */
112
125
#include <gpgme.h>              /* All GPGME types, constants and
120
133
#define PATHDIR "/conf/conf.d/mandos"
121
134
#define SECKEY "seckey.txt"
122
135
#define PUBKEY "pubkey.txt"
 
136
#define HOOKDIR "/lib/mandos/network-hooks.d"
123
137
 
124
138
bool debug = false;
125
139
static const char mandos_protocol_version[] = "1";
126
140
const char *argp_program_version = "mandos-client " VERSION;
127
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
141
const char *argp_program_bug_address = "<mandos@recompile.se>";
128
142
static const char sys_class_net[] = "/sys/class/net";
129
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 */
 
496
__attribute__((warn_unused_result))
 
497
static const char *safer_gnutls_strerror(int value){
 
498
  const char *ret = gnutls_strerror(value);
389
499
  if(ret == NULL)
390
500
    ret = "(unknown)";
391
501
  return ret;
392
502
}
393
503
 
394
504
/* GnuTLS log function callback */
 
505
__attribute__((nonnull))
395
506
static void debuggnutls(__attribute__((unused)) int level,
396
507
                        const char* string){
397
 
  fprintf(stderr, "GnuTLS: %s", string);
 
508
  fprintf_plus(stderr, "GnuTLS: %s", string);
398
509
}
399
510
 
 
511
__attribute__((nonnull, warn_unused_result))
400
512
static int init_gnutls_global(const char *pubkeyfilename,
401
 
                              const char *seckeyfilename){
 
513
                              const char *seckeyfilename,
 
514
                              mandos_context *mc){
402
515
  int ret;
403
516
  
404
517
  if(debug){
405
 
    fprintf(stderr, "Initializing GnuTLS\n");
 
518
    fprintf_plus(stderr, "Initializing GnuTLS\n");
406
519
  }
407
520
  
408
521
  ret = gnutls_global_init();
409
522
  if(ret != GNUTLS_E_SUCCESS){
410
 
    fprintf(stderr, "GnuTLS global_init: %s\n",
411
 
            safer_gnutls_strerror(ret));
 
523
    fprintf_plus(stderr, "GnuTLS global_init: %s\n",
 
524
                 safer_gnutls_strerror(ret));
412
525
    return -1;
413
526
  }
414
527
  
421
534
  }
422
535
  
423
536
  /* OpenPGP credentials */
424
 
  gnutls_certificate_allocate_credentials(&mc.cred);
 
537
  ret = gnutls_certificate_allocate_credentials(&mc->cred);
425
538
  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));
 
539
    fprintf_plus(stderr, "GnuTLS memory error: %s\n",
 
540
                 safer_gnutls_strerror(ret));
431
541
    gnutls_global_deinit();
432
542
    return -1;
433
543
  }
434
544
  
435
545
  if(debug){
436
 
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
437
 
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
438
 
            seckeyfilename);
 
546
    fprintf_plus(stderr, "Attempting to use OpenPGP public key %s and"
 
547
                 " secret key %s as GnuTLS credentials\n",
 
548
                 pubkeyfilename,
 
549
                 seckeyfilename);
439
550
  }
440
551
  
441
552
  ret = gnutls_certificate_set_openpgp_key_file
442
 
    (mc.cred, pubkeyfilename, seckeyfilename,
 
553
    (mc->cred, pubkeyfilename, seckeyfilename,
443
554
     GNUTLS_OPENPGP_FMT_BASE64);
444
555
  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));
 
556
    fprintf_plus(stderr,
 
557
                 "Error[%d] while reading the OpenPGP key pair ('%s',"
 
558
                 " '%s')\n", ret, pubkeyfilename, seckeyfilename);
 
559
    fprintf_plus(stderr, "The GnuTLS error is: %s\n",
 
560
                 safer_gnutls_strerror(ret));
450
561
    goto globalfail;
451
562
  }
452
563
  
453
564
  /* GnuTLS server initialization */
454
 
  ret = gnutls_dh_params_init(&mc.dh_params);
 
565
  ret = gnutls_dh_params_init(&mc->dh_params);
455
566
  if(ret != GNUTLS_E_SUCCESS){
456
 
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
457
 
            " %s\n", safer_gnutls_strerror(ret));
 
567
    fprintf_plus(stderr, "Error in GnuTLS DH parameter"
 
568
                 " initialization: %s\n",
 
569
                 safer_gnutls_strerror(ret));
458
570
    goto globalfail;
459
571
  }
460
 
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
572
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
461
573
  if(ret != GNUTLS_E_SUCCESS){
462
 
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
463
 
            safer_gnutls_strerror(ret));
 
574
    fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
 
575
                 safer_gnutls_strerror(ret));
464
576
    goto globalfail;
465
577
  }
466
578
  
467
 
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
579
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
468
580
  
469
581
  return 0;
470
582
  
471
583
 globalfail:
472
584
  
473
 
  gnutls_certificate_free_credentials(mc.cred);
 
585
  gnutls_certificate_free_credentials(mc->cred);
474
586
  gnutls_global_deinit();
475
 
  gnutls_dh_params_deinit(mc.dh_params);
 
587
  gnutls_dh_params_deinit(mc->dh_params);
476
588
  return -1;
477
589
}
478
590
 
479
 
static int init_gnutls_session(gnutls_session_t *session){
 
591
__attribute__((nonnull, warn_unused_result))
 
592
static int init_gnutls_session(gnutls_session_t *session,
 
593
                               mandos_context *mc){
480
594
  int ret;
481
595
  /* GnuTLS session creation */
482
596
  do {
486
600
    }
487
601
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
488
602
  if(ret != GNUTLS_E_SUCCESS){
489
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
490
 
            safer_gnutls_strerror(ret));
 
603
    fprintf_plus(stderr,
 
604
                 "Error in GnuTLS session initialization: %s\n",
 
605
                 safer_gnutls_strerror(ret));
491
606
  }
492
607
  
493
608
  {
494
609
    const char *err;
495
610
    do {
496
 
      ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
611
      ret = gnutls_priority_set_direct(*session, mc->priority, &err);
497
612
      if(quit_now){
498
613
        gnutls_deinit(*session);
499
614
        return -1;
500
615
      }
501
616
    } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
502
617
    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));
 
618
      fprintf_plus(stderr, "Syntax error at: %s\n", err);
 
619
      fprintf_plus(stderr, "GnuTLS error: %s\n",
 
620
                   safer_gnutls_strerror(ret));
506
621
      gnutls_deinit(*session);
507
622
      return -1;
508
623
    }
510
625
  
511
626
  do {
512
627
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
513
 
                                 mc.cred);
 
628
                                 mc->cred);
514
629
    if(quit_now){
515
630
      gnutls_deinit(*session);
516
631
      return -1;
517
632
    }
518
633
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
519
634
  if(ret != GNUTLS_E_SUCCESS){
520
 
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
521
 
            safer_gnutls_strerror(ret));
 
635
    fprintf_plus(stderr, "Error setting GnuTLS credentials: %s\n",
 
636
                 safer_gnutls_strerror(ret));
522
637
    gnutls_deinit(*session);
523
638
    return -1;
524
639
  }
526
641
  /* ignore client certificate if any. */
527
642
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
528
643
  
529
 
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
 
644
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
530
645
  
531
646
  return 0;
532
647
}
536
651
                      __attribute__((unused)) const char *txt){}
537
652
 
538
653
/* Called when a Mandos server is found */
539
 
static int start_mandos_communication(const char *ip, uint16_t port,
 
654
__attribute__((nonnull, warn_unused_result))
 
655
static int start_mandos_communication(const char *ip, in_port_t port,
540
656
                                      AvahiIfIndex if_index,
541
 
                                      int af){
 
657
                                      int af, mandos_context *mc){
542
658
  int ret, tcp_sd = -1;
543
659
  ssize_t sret;
544
 
  union {
545
 
    struct sockaddr_in in;
546
 
    struct sockaddr_in6 in6;
547
 
  } to;
 
660
  struct sockaddr_storage to;
548
661
  char *buffer = NULL;
549
662
  char *decrypted_buffer = NULL;
550
663
  size_t buffer_length = 0;
554
667
  gnutls_session_t session;
555
668
  int pf;                       /* Protocol family */
556
669
  
 
670
  errno = 0;
 
671
  
557
672
  if(quit_now){
 
673
    errno = EINTR;
558
674
    return -1;
559
675
  }
560
676
  
566
682
    pf = PF_INET;
567
683
    break;
568
684
  default:
569
 
    fprintf(stderr, "Bad address family: %d\n", af);
 
685
    fprintf_plus(stderr, "Bad address family: %d\n", af);
 
686
    errno = EINVAL;
570
687
    return -1;
571
688
  }
572
689
  
573
 
  ret = init_gnutls_session(&session);
 
690
  /* If the interface is specified and we have a list of interfaces */
 
691
  if(if_index != AVAHI_IF_UNSPEC and mc->interfaces != NULL){
 
692
    /* Check if the interface is one of the interfaces we are using */
 
693
    bool match = false;
 
694
    {
 
695
      char *interface = NULL;
 
696
      while((interface=argz_next(mc->interfaces, mc->interfaces_size,
 
697
                                 interface))){
 
698
        if(if_nametoindex(interface) == (unsigned int)if_index){
 
699
          match = true;
 
700
          break;
 
701
        }
 
702
      }
 
703
    }
 
704
    if(not match){
 
705
      /* This interface does not match any in the list, so we don't
 
706
         connect to the server */
 
707
      if(debug){
 
708
        char interface[IF_NAMESIZE];
 
709
        if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
710
          perror_plus("if_indextoname");
 
711
        } else {
 
712
          fprintf_plus(stderr, "Skipping server on non-used interface"
 
713
                       " \"%s\"\n",
 
714
                       if_indextoname((unsigned int)if_index,
 
715
                                      interface));
 
716
        }
 
717
      }
 
718
      return -1;
 
719
    }
 
720
  }
 
721
  
 
722
  ret = init_gnutls_session(&session, mc);
574
723
  if(ret != 0){
575
724
    return -1;
576
725
  }
577
726
  
578
727
  if(debug){
579
 
    fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
580
 
            "\n", ip, port);
 
728
    fprintf_plus(stderr, "Setting up a TCP connection to %s, port %"
 
729
                 PRIuMAX "\n", ip, (uintmax_t)port);
581
730
  }
582
731
  
583
732
  tcp_sd = socket(pf, SOCK_STREAM, 0);
584
733
  if(tcp_sd < 0){
585
 
    perror("socket");
 
734
    int e = errno;
 
735
    perror_plus("socket");
 
736
    errno = e;
586
737
    goto mandos_end;
587
738
  }
588
739
  
589
740
  if(quit_now){
 
741
    errno = EINTR;
590
742
    goto mandos_end;
591
743
  }
592
744
  
593
745
  memset(&to, 0, sizeof(to));
594
746
  if(af == AF_INET6){
595
 
    to.in6.sin6_family = (sa_family_t)af;
596
 
    ret = inet_pton(af, ip, &to.in6.sin6_addr);
 
747
    ((struct sockaddr_in6 *)&to)->sin6_family = (sa_family_t)af;
 
748
    ret = inet_pton(af, ip, &((struct sockaddr_in6 *)&to)->sin6_addr);
597
749
  } else {                      /* IPv4 */
598
 
    to.in.sin_family = (sa_family_t)af;
599
 
    ret = inet_pton(af, ip, &to.in.sin_addr);
 
750
    ((struct sockaddr_in *)&to)->sin_family = (sa_family_t)af;
 
751
    ret = inet_pton(af, ip, &((struct sockaddr_in *)&to)->sin_addr);
600
752
  }
601
753
  if(ret < 0 ){
602
 
    perror("inet_pton");
 
754
    int e = errno;
 
755
    perror_plus("inet_pton");
 
756
    errno = e;
603
757
    goto mandos_end;
604
758
  }
605
759
  if(ret == 0){
606
 
    fprintf(stderr, "Bad address: %s\n", ip);
 
760
    int e = errno;
 
761
    fprintf_plus(stderr, "Bad address: %s\n", ip);
 
762
    errno = e;
607
763
    goto mandos_end;
608
764
  }
609
765
  if(af == AF_INET6){
610
 
    to.in6.sin6_port = htons(port); /* Spurious warnings from
611
 
                                       -Wconversion and
612
 
                                       -Wunreachable-code */
613
 
    
614
 
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
615
 
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
616
 
                              -Wunreachable-code*/
 
766
    ((struct sockaddr_in6 *)&to)->sin6_port = htons(port);
 
767
    if(IN6_IS_ADDR_LINKLOCAL
 
768
       (&((struct sockaddr_in6 *)&to)->sin6_addr)){
617
769
      if(if_index == AVAHI_IF_UNSPEC){
618
 
        fprintf(stderr, "An IPv6 link-local address is incomplete"
619
 
                " without a network interface\n");
 
770
        fprintf_plus(stderr, "An IPv6 link-local address is"
 
771
                     " incomplete without a network interface\n");
 
772
        errno = EINVAL;
620
773
        goto mandos_end;
621
774
      }
622
775
      /* Set the network interface number as scope */
623
 
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
776
      ((struct sockaddr_in6 *)&to)->sin6_scope_id = (uint32_t)if_index;
624
777
    }
625
778
  } else {
626
 
    to.in.sin_port = htons(port); /* Spurious warnings from
627
 
                                     -Wconversion and
628
 
                                     -Wunreachable-code */
 
779
    ((struct sockaddr_in *)&to)->sin_port = htons(port);
629
780
  }
630
781
  
631
782
  if(quit_now){
 
783
    errno = EINTR;
632
784
    goto mandos_end;
633
785
  }
634
786
  
636
788
    if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
637
789
      char interface[IF_NAMESIZE];
638
790
      if(if_indextoname((unsigned int)if_index, interface) == NULL){
639
 
        perror("if_indextoname");
 
791
        perror_plus("if_indextoname");
640
792
      } else {
641
 
        fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
642
 
                ip, interface, port);
 
793
        fprintf_plus(stderr, "Connection to: %s%%%s, port %" PRIuMAX
 
794
                     "\n", ip, interface, (uintmax_t)port);
643
795
      }
644
796
    } else {
645
 
      fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
646
 
              port);
 
797
      fprintf_plus(stderr, "Connection to: %s, port %" PRIuMAX "\n",
 
798
                   ip, (uintmax_t)port);
647
799
    }
648
800
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
649
801
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
650
 
    const char *pcret;
651
802
    if(af == AF_INET6){
652
 
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
653
 
                        sizeof(addrstr));
 
803
      ret = getnameinfo((struct sockaddr *)&to,
 
804
                        sizeof(struct sockaddr_in6),
 
805
                        addrstr, sizeof(addrstr), NULL, 0,
 
806
                        NI_NUMERICHOST);
654
807
    } else {
655
 
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
656
 
                        sizeof(addrstr));
 
808
      ret = getnameinfo((struct sockaddr *)&to,
 
809
                        sizeof(struct sockaddr_in),
 
810
                        addrstr, sizeof(addrstr), NULL, 0,
 
811
                        NI_NUMERICHOST);
657
812
    }
658
 
    if(pcret == NULL){
659
 
      perror("inet_ntop");
660
 
    } else {
661
 
      if(strcmp(addrstr, ip) != 0){
662
 
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
663
 
      }
 
813
    if(ret == EAI_SYSTEM){
 
814
      perror_plus("getnameinfo");
 
815
    } else if(ret != 0) {
 
816
      fprintf_plus(stderr, "getnameinfo: %s", gai_strerror(ret));
 
817
    } else if(strcmp(addrstr, ip) != 0){
 
818
      fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
664
819
    }
665
820
  }
666
821
  
667
822
  if(quit_now){
 
823
    errno = EINTR;
668
824
    goto mandos_end;
669
825
  }
670
826
  
671
827
  if(af == AF_INET6){
672
 
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
828
    ret = connect(tcp_sd, (struct sockaddr *)&to,
 
829
                  sizeof(struct sockaddr_in6));
673
830
  } else {
674
 
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
831
    ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
832
                  sizeof(struct sockaddr_in));
675
833
  }
676
834
  if(ret < 0){
677
 
    perror("connect");
 
835
    if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
836
      int e = errno;
 
837
      perror_plus("connect");
 
838
      errno = e;
 
839
    }
678
840
    goto mandos_end;
679
841
  }
680
842
  
681
843
  if(quit_now){
 
844
    errno = EINTR;
682
845
    goto mandos_end;
683
846
  }
684
847
  
687
850
  while(true){
688
851
    size_t out_size = strlen(out);
689
852
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
690
 
                                   out_size - written));
 
853
                                        out_size - written));
691
854
    if(ret == -1){
692
 
      perror("write");
 
855
      int e = errno;
 
856
      perror_plus("write");
 
857
      errno = e;
693
858
      goto mandos_end;
694
859
    }
695
860
    written += (size_t)ret;
705
870
    }
706
871
  
707
872
    if(quit_now){
 
873
      errno = EINTR;
708
874
      goto mandos_end;
709
875
    }
710
876
  }
711
877
  
712
878
  if(debug){
713
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
879
    fprintf_plus(stderr, "Establishing TLS session with %s\n", ip);
714
880
  }
715
881
  
716
882
  if(quit_now){
 
883
    errno = EINTR;
717
884
    goto mandos_end;
718
885
  }
719
886
  
720
 
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
887
  /* This casting via intptr_t is to eliminate warning about casting
 
888
     an int to a pointer type.  This is exactly how the GnuTLS Guile
 
889
     function "set-session-transport-fd!" does it. */
 
890
  gnutls_transport_set_ptr(session,
 
891
                           (gnutls_transport_ptr_t)(intptr_t)tcp_sd);
721
892
  
722
893
  if(quit_now){
 
894
    errno = EINTR;
723
895
    goto mandos_end;
724
896
  }
725
897
  
726
898
  do {
727
899
    ret = gnutls_handshake(session);
728
900
    if(quit_now){
 
901
      errno = EINTR;
729
902
      goto mandos_end;
730
903
    }
731
904
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
732
905
  
733
906
  if(ret != GNUTLS_E_SUCCESS){
734
907
    if(debug){
735
 
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
908
      fprintf_plus(stderr, "*** GnuTLS Handshake failed ***\n");
736
909
      gnutls_perror(ret);
737
910
    }
 
911
    errno = EPROTO;
738
912
    goto mandos_end;
739
913
  }
740
914
  
741
915
  /* Read OpenPGP packet that contains the wanted password */
742
916
  
743
917
  if(debug){
744
 
    fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
745
 
            ip);
 
918
    fprintf_plus(stderr, "Retrieving OpenPGP encrypted password from"
 
919
                 " %s\n", ip);
746
920
  }
747
921
  
748
922
  while(true){
749
923
    
750
924
    if(quit_now){
 
925
      errno = EINTR;
751
926
      goto mandos_end;
752
927
    }
753
928
    
754
929
    buffer_capacity = incbuffer(&buffer, buffer_length,
755
 
                                   buffer_capacity);
 
930
                                buffer_capacity);
756
931
    if(buffer_capacity == 0){
757
 
      perror("incbuffer");
 
932
      int e = errno;
 
933
      perror_plus("incbuffer");
 
934
      errno = e;
758
935
      goto mandos_end;
759
936
    }
760
937
    
761
938
    if(quit_now){
 
939
      errno = EINTR;
762
940
      goto mandos_end;
763
941
    }
764
942
    
777
955
          ret = gnutls_handshake(session);
778
956
          
779
957
          if(quit_now){
 
958
            errno = EINTR;
780
959
            goto mandos_end;
781
960
          }
782
961
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
783
962
        if(ret < 0){
784
 
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
963
          fprintf_plus(stderr, "*** GnuTLS Re-handshake failed "
 
964
                       "***\n");
785
965
          gnutls_perror(ret);
 
966
          errno = EPROTO;
786
967
          goto mandos_end;
787
968
        }
788
969
        break;
789
970
      default:
790
 
        fprintf(stderr, "Unknown error while reading data from"
791
 
                " encrypted session with Mandos server\n");
 
971
        fprintf_plus(stderr, "Unknown error while reading data from"
 
972
                     " encrypted session with Mandos server\n");
792
973
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
974
        errno = EIO;
793
975
        goto mandos_end;
794
976
      }
795
977
    } else {
798
980
  }
799
981
  
800
982
  if(debug){
801
 
    fprintf(stderr, "Closing TLS session\n");
 
983
    fprintf_plus(stderr, "Closing TLS session\n");
802
984
  }
803
985
  
804
986
  if(quit_now){
 
987
    errno = EINTR;
805
988
    goto mandos_end;
806
989
  }
807
990
  
808
991
  do {
809
992
    ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
810
993
    if(quit_now){
 
994
      errno = EINTR;
811
995
      goto mandos_end;
812
996
    }
813
997
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
814
998
  
815
999
  if(buffer_length > 0){
816
1000
    ssize_t decrypted_buffer_size;
817
 
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
818
 
                                               buffer_length,
819
 
                                               &decrypted_buffer);
 
1001
    decrypted_buffer_size = pgp_packet_decrypt(buffer, buffer_length,
 
1002
                                               &decrypted_buffer, mc);
820
1003
    if(decrypted_buffer_size >= 0){
821
1004
      
822
1005
      written = 0;
823
1006
      while(written < (size_t) decrypted_buffer_size){
824
1007
        if(quit_now){
 
1008
          errno = EINTR;
825
1009
          goto mandos_end;
826
1010
        }
827
1011
        
829
1013
                          (size_t)decrypted_buffer_size - written,
830
1014
                          stdout);
831
1015
        if(ret == 0 and ferror(stdout)){
 
1016
          int e = errno;
832
1017
          if(debug){
833
 
            fprintf(stderr, "Error writing encrypted data: %s\n",
834
 
                    strerror(errno));
 
1018
            fprintf_plus(stderr, "Error writing encrypted data: %s\n",
 
1019
                         strerror(errno));
835
1020
          }
 
1021
          errno = e;
836
1022
          goto mandos_end;
837
1023
        }
838
1024
        written += (size_t)ret;
844
1030
  /* Shutdown procedure */
845
1031
  
846
1032
 mandos_end:
847
 
  free(decrypted_buffer);
848
 
  free(buffer);
849
 
  if(tcp_sd >= 0){
850
 
    ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
851
 
  }
852
 
  if(ret == -1){
853
 
    perror("close");
854
 
  }
855
 
  gnutls_deinit(session);
856
 
  if(quit_now){
857
 
    retval = -1;
 
1033
  {
 
1034
    int e = errno;
 
1035
    free(decrypted_buffer);
 
1036
    free(buffer);
 
1037
    if(tcp_sd >= 0){
 
1038
      ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
 
1039
    }
 
1040
    if(ret == -1){
 
1041
      if(e == 0){
 
1042
        e = errno;
 
1043
      }
 
1044
      perror_plus("close");
 
1045
    }
 
1046
    gnutls_deinit(session);
 
1047
    errno = e;
 
1048
    if(quit_now){
 
1049
      errno = EINTR;
 
1050
      retval = -1;
 
1051
    }
858
1052
  }
859
1053
  return retval;
860
1054
}
861
1055
 
 
1056
__attribute__((nonnull))
862
1057
static void resolve_callback(AvahiSServiceResolver *r,
863
1058
                             AvahiIfIndex interface,
864
1059
                             AvahiProtocol proto,
872
1067
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
873
1068
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
874
1069
                             flags,
875
 
                             AVAHI_GCC_UNUSED void* userdata){
876
 
  assert(r);
 
1070
                             void *mc){
 
1071
  if(r == NULL){
 
1072
    return;
 
1073
  }
877
1074
  
878
1075
  /* Called whenever a service has been resolved successfully or
879
1076
     timed out */
880
1077
  
881
1078
  if(quit_now){
 
1079
    avahi_s_service_resolver_free(r);
882
1080
    return;
883
1081
  }
884
1082
  
885
1083
  switch(event){
886
1084
  default:
887
1085
  case AVAHI_RESOLVER_FAILURE:
888
 
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
889
 
            " of type '%s' in domain '%s': %s\n", name, type, domain,
890
 
            avahi_strerror(avahi_server_errno(mc.server)));
 
1086
    fprintf_plus(stderr, "(Avahi Resolver) Failed to resolve service "
 
1087
                 "'%s' of type '%s' in domain '%s': %s\n", name, type,
 
1088
                 domain,
 
1089
                 avahi_strerror(avahi_server_errno
 
1090
                                (((mandos_context*)mc)->server)));
891
1091
    break;
892
1092
    
893
1093
  case AVAHI_RESOLVER_FOUND:
895
1095
      char ip[AVAHI_ADDRESS_STR_MAX];
896
1096
      avahi_address_snprint(ip, sizeof(ip), address);
897
1097
      if(debug){
898
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
899
 
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
900
 
                ip, (intmax_t)interface, port);
 
1098
        fprintf_plus(stderr, "Mandos server \"%s\" found on %s (%s, %"
 
1099
                     PRIdMAX ") on port %" PRIu16 "\n", name,
 
1100
                     host_name, ip, (intmax_t)interface, port);
901
1101
      }
902
 
      int ret = start_mandos_communication(ip, port, interface,
903
 
                                           avahi_proto_to_af(proto));
 
1102
      int ret = start_mandos_communication(ip, (in_port_t)port,
 
1103
                                           interface,
 
1104
                                           avahi_proto_to_af(proto),
 
1105
                                           mc);
904
1106
      if(ret == 0){
905
 
        avahi_simple_poll_quit(mc.simple_poll);
 
1107
        avahi_simple_poll_quit(simple_poll);
 
1108
      } else {
 
1109
        if(not add_server(ip, (in_port_t)port, interface,
 
1110
                          avahi_proto_to_af(proto),
 
1111
                          &((mandos_context*)mc)->current_server)){
 
1112
          fprintf_plus(stderr, "Failed to add server \"%s\" to server"
 
1113
                       " list\n", name);
 
1114
        }
906
1115
      }
907
1116
    }
908
1117
  }
918
1127
                            const char *domain,
919
1128
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
920
1129
                            flags,
921
 
                            AVAHI_GCC_UNUSED void* userdata){
922
 
  assert(b);
 
1130
                            void *mc){
 
1131
  if(b == NULL){
 
1132
    return;
 
1133
  }
923
1134
  
924
1135
  /* Called whenever a new services becomes available on the LAN or
925
1136
     is removed from the LAN */
932
1143
  default:
933
1144
  case AVAHI_BROWSER_FAILURE:
934
1145
    
935
 
    fprintf(stderr, "(Avahi browser) %s\n",
936
 
            avahi_strerror(avahi_server_errno(mc.server)));
937
 
    avahi_simple_poll_quit(mc.simple_poll);
 
1146
    fprintf_plus(stderr, "(Avahi browser) %s\n",
 
1147
                 avahi_strerror(avahi_server_errno
 
1148
                                (((mandos_context*)mc)->server)));
 
1149
    avahi_simple_poll_quit(simple_poll);
938
1150
    return;
939
1151
    
940
1152
  case AVAHI_BROWSER_NEW:
943
1155
       the callback function is called the Avahi server will free the
944
1156
       resolver for us. */
945
1157
    
946
 
    if(avahi_s_service_resolver_new(mc.server, interface, protocol,
947
 
                                    name, type, domain, protocol, 0,
948
 
                                    resolve_callback, NULL) == NULL)
949
 
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
950
 
              name, avahi_strerror(avahi_server_errno(mc.server)));
 
1158
    if(avahi_s_service_resolver_new(((mandos_context*)mc)->server,
 
1159
                                    interface, protocol, name, type,
 
1160
                                    domain, protocol, 0,
 
1161
                                    resolve_callback, mc) == NULL)
 
1162
      fprintf_plus(stderr, "Avahi: Failed to resolve service '%s':"
 
1163
                   " %s\n", name,
 
1164
                   avahi_strerror(avahi_server_errno
 
1165
                                  (((mandos_context*)mc)->server)));
951
1166
    break;
952
1167
    
953
1168
  case AVAHI_BROWSER_REMOVE:
956
1171
  case AVAHI_BROWSER_ALL_FOR_NOW:
957
1172
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
958
1173
    if(debug){
959
 
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
1174
      fprintf_plus(stderr, "No Mandos server found, still"
 
1175
                   " searching...\n");
960
1176
    }
961
1177
    break;
962
1178
  }
963
1179
}
964
1180
 
965
 
/* stop main loop after sigterm has been called */
 
1181
/* Signal handler that stops main loop after SIGTERM */
966
1182
static void handle_sigterm(int sig){
967
1183
  if(quit_now){
968
1184
    return;
970
1186
  quit_now = 1;
971
1187
  signal_received = sig;
972
1188
  int old_errno = errno;
973
 
  if(mc.simple_poll != NULL){
974
 
    avahi_simple_poll_quit(mc.simple_poll);
 
1189
  /* set main loop to exit */
 
1190
  if(simple_poll != NULL){
 
1191
    avahi_simple_poll_quit(simple_poll);
975
1192
  }
976
1193
  errno = old_errno;
977
1194
}
978
1195
 
 
1196
__attribute__((nonnull, warn_unused_result))
 
1197
bool get_flags(const char *ifname, struct ifreq *ifr){
 
1198
  int ret;
 
1199
  error_t ret_errno;
 
1200
  
 
1201
  int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1202
  if(s < 0){
 
1203
    ret_errno = errno;
 
1204
    perror_plus("socket");
 
1205
    errno = ret_errno;
 
1206
    return false;
 
1207
  }
 
1208
  strcpy(ifr->ifr_name, ifname);
 
1209
  ret = ioctl(s, SIOCGIFFLAGS, ifr);
 
1210
  if(ret == -1){
 
1211
    if(debug){
 
1212
      ret_errno = errno;
 
1213
      perror_plus("ioctl SIOCGIFFLAGS");
 
1214
      errno = ret_errno;
 
1215
    }
 
1216
    return false;
 
1217
  }
 
1218
  return true;
 
1219
}
 
1220
 
 
1221
__attribute__((nonnull, warn_unused_result))
 
1222
bool good_flags(const char *ifname, const struct ifreq *ifr){
 
1223
  
 
1224
  /* Reject the loopback device */
 
1225
  if(ifr->ifr_flags & IFF_LOOPBACK){
 
1226
    if(debug){
 
1227
      fprintf_plus(stderr, "Rejecting loopback interface \"%s\"\n",
 
1228
                   ifname);
 
1229
    }
 
1230
    return false;
 
1231
  }
 
1232
  /* Accept point-to-point devices only if connect_to is specified */
 
1233
  if(connect_to != NULL and (ifr->ifr_flags & IFF_POINTOPOINT)){
 
1234
    if(debug){
 
1235
      fprintf_plus(stderr, "Accepting point-to-point interface"
 
1236
                   " \"%s\"\n", ifname);
 
1237
    }
 
1238
    return true;
 
1239
  }
 
1240
  /* Otherwise, reject non-broadcast-capable devices */
 
1241
  if(not (ifr->ifr_flags & IFF_BROADCAST)){
 
1242
    if(debug){
 
1243
      fprintf_plus(stderr, "Rejecting non-broadcast interface"
 
1244
                   " \"%s\"\n", ifname);
 
1245
    }
 
1246
    return false;
 
1247
  }
 
1248
  /* Reject non-ARP interfaces (including dummy interfaces) */
 
1249
  if(ifr->ifr_flags & IFF_NOARP){
 
1250
    if(debug){
 
1251
      fprintf_plus(stderr, "Rejecting non-ARP interface \"%s\"\n",
 
1252
                   ifname);
 
1253
    }
 
1254
    return false;
 
1255
  }
 
1256
  
 
1257
  /* Accept this device */
 
1258
  if(debug){
 
1259
    fprintf_plus(stderr, "Interface \"%s\" is good\n", ifname);
 
1260
  }
 
1261
  return true;
 
1262
}
 
1263
 
979
1264
/* 
980
1265
 * This function determines if a directory entry in /sys/class/net
981
1266
 * corresponds to an acceptable network device.
982
1267
 * (This function is passed to scandir(3) as a filter function.)
983
1268
 */
 
1269
__attribute__((nonnull, warn_unused_result))
984
1270
int good_interface(const struct dirent *if_entry){
985
 
  ssize_t ssret;
986
 
  char *flagname = NULL;
987
 
  int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
988
 
                     if_entry->d_name);
989
 
  if(ret < 0){
990
 
    perror("asprintf");
991
 
    return 0;
992
 
  }
993
1271
  if(if_entry->d_name[0] == '.'){
994
1272
    return 0;
995
1273
  }
996
 
  int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
997
 
  if(flags_fd == -1){
998
 
    perror("open");
999
 
    return 0;
1000
 
  }
1001
 
  typedef short ifreq_flags;    /* ifreq.ifr_flags in netdevice(7) */
1002
 
  /* read line from flags_fd */
1003
 
  ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1004
 
  char *flagstring = malloc((size_t)to_read);
1005
 
  if(flagstring == NULL){
1006
 
    perror("malloc");
1007
 
    close(flags_fd);
1008
 
    return 0;
1009
 
  }
1010
 
  while(to_read > 0){
1011
 
    ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1012
 
                                             (size_t)to_read));
1013
 
    if(ssret == -1){
1014
 
      perror("read");
1015
 
      free(flagstring);
1016
 
      close(flags_fd);
1017
 
      return 0;
1018
 
    }
1019
 
    to_read -= ssret;
1020
 
    if(ssret == 0){
 
1274
  
 
1275
  struct ifreq ifr;
 
1276
  if(not get_flags(if_entry->d_name, &ifr)){
 
1277
    if(debug){
 
1278
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1279
                   "\"%s\"\n", if_entry->d_name);
 
1280
    }
 
1281
    return 0;
 
1282
  }
 
1283
  
 
1284
  if(not good_flags(if_entry->d_name, &ifr)){
 
1285
    return 0;
 
1286
  }
 
1287
  return 1;
 
1288
}
 
1289
 
 
1290
/* 
 
1291
 * This function determines if a network interface is up.
 
1292
 */
 
1293
__attribute__((nonnull, warn_unused_result))
 
1294
bool interface_is_up(const char *interface){
 
1295
  struct ifreq ifr;
 
1296
  if(not get_flags(interface, &ifr)){
 
1297
    if(debug){
 
1298
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1299
                   "\"%s\"\n", interface);
 
1300
    }
 
1301
    return false;
 
1302
  }
 
1303
  
 
1304
  return (bool)(ifr.ifr_flags & IFF_UP);
 
1305
}
 
1306
 
 
1307
/* 
 
1308
 * This function determines if a network interface is running
 
1309
 */
 
1310
__attribute__((nonnull, warn_unused_result))
 
1311
bool interface_is_running(const char *interface){
 
1312
  struct ifreq ifr;
 
1313
  if(not get_flags(interface, &ifr)){
 
1314
    if(debug){
 
1315
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1316
                   "\"%s\"\n", interface);
 
1317
    }
 
1318
    return false;
 
1319
  }
 
1320
  
 
1321
  return (bool)(ifr.ifr_flags & IFF_RUNNING);
 
1322
}
 
1323
 
 
1324
__attribute__((nonnull, pure, warn_unused_result))
 
1325
int notdotentries(const struct dirent *direntry){
 
1326
  /* Skip "." and ".." */
 
1327
  if(direntry->d_name[0] == '.'
 
1328
     and (direntry->d_name[1] == '\0'
 
1329
          or (direntry->d_name[1] == '.'
 
1330
              and direntry->d_name[2] == '\0'))){
 
1331
    return 0;
 
1332
  }
 
1333
  return 1;
 
1334
}
 
1335
 
 
1336
/* Is this directory entry a runnable program? */
 
1337
__attribute__((nonnull, warn_unused_result))
 
1338
int runnable_hook(const struct dirent *direntry){
 
1339
  int ret;
 
1340
  size_t sret;
 
1341
  struct stat st;
 
1342
  
 
1343
  if((direntry->d_name)[0] == '\0'){
 
1344
    /* Empty name? */
 
1345
    return 0;
 
1346
  }
 
1347
  
 
1348
  sret = strspn(direntry->d_name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
1349
                "abcdefghijklmnopqrstuvwxyz"
 
1350
                "0123456789"
 
1351
                "_.-");
 
1352
  if((direntry->d_name)[sret] != '\0'){
 
1353
    /* Contains non-allowed characters */
 
1354
    if(debug){
 
1355
      fprintf_plus(stderr, "Ignoring hook \"%s\" with bad name\n",
 
1356
                   direntry->d_name);
 
1357
    }
 
1358
    return 0;
 
1359
  }
 
1360
  
 
1361
  ret = fstatat(hookdir_fd, direntry->d_name, &st, 0);
 
1362
  if(ret == -1){
 
1363
    if(debug){
 
1364
      perror_plus("Could not stat hook");
 
1365
    }
 
1366
    return 0;
 
1367
  }
 
1368
  if(not (S_ISREG(st.st_mode))){
 
1369
    /* Not a regular file */
 
1370
    if(debug){
 
1371
      fprintf_plus(stderr, "Ignoring hook \"%s\" - not a file\n",
 
1372
                   direntry->d_name);
 
1373
    }
 
1374
    return 0;
 
1375
  }
 
1376
  if(not (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))){
 
1377
    /* Not executable */
 
1378
    if(debug){
 
1379
      fprintf_plus(stderr, "Ignoring hook \"%s\" - not executable\n",
 
1380
                   direntry->d_name);
 
1381
    }
 
1382
    return 0;
 
1383
  }
 
1384
  if(debug){
 
1385
    fprintf_plus(stderr, "Hook \"%s\" is acceptable\n",
 
1386
                 direntry->d_name);
 
1387
  }
 
1388
  return 1;
 
1389
}
 
1390
 
 
1391
__attribute__((nonnull, warn_unused_result))
 
1392
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval,
 
1393
                            mandos_context *mc){
 
1394
  int ret;
 
1395
  struct timespec now;
 
1396
  struct timespec waited_time;
 
1397
  intmax_t block_time;
 
1398
  
 
1399
  while(true){
 
1400
    if(mc->current_server == NULL){
 
1401
      if(debug){
 
1402
        fprintf_plus(stderr, "Wait until first server is found."
 
1403
                     " No timeout!\n");
 
1404
      }
 
1405
      ret = avahi_simple_poll_iterate(s, -1);
 
1406
    } else {
 
1407
      if(debug){
 
1408
        fprintf_plus(stderr, "Check current_server if we should run"
 
1409
                     " it, or wait\n");
 
1410
      }
 
1411
      /* the current time */
 
1412
      ret = clock_gettime(CLOCK_MONOTONIC, &now);
 
1413
      if(ret == -1){
 
1414
        perror_plus("clock_gettime");
 
1415
        return -1;
 
1416
      }
 
1417
      /* Calculating in ms how long time between now and server
 
1418
         who we visted longest time ago. Now - last seen.  */
 
1419
      waited_time.tv_sec = (now.tv_sec
 
1420
                            - mc->current_server->last_seen.tv_sec);
 
1421
      waited_time.tv_nsec = (now.tv_nsec
 
1422
                             - mc->current_server->last_seen.tv_nsec);
 
1423
      /* total time is 10s/10,000ms.
 
1424
         Converting to s from ms by dividing by 1,000,
 
1425
         and ns to ms by dividing by 1,000,000. */
 
1426
      block_time = ((retry_interval
 
1427
                     - ((intmax_t)waited_time.tv_sec * 1000))
 
1428
                    - ((intmax_t)waited_time.tv_nsec / 1000000));
 
1429
      
 
1430
      if(debug){
 
1431
        fprintf_plus(stderr, "Blocking for %" PRIdMAX " ms\n",
 
1432
                     block_time);
 
1433
      }
 
1434
      
 
1435
      if(block_time <= 0){
 
1436
        ret = start_mandos_communication(mc->current_server->ip,
 
1437
                                         mc->current_server->port,
 
1438
                                         mc->current_server->if_index,
 
1439
                                         mc->current_server->af, mc);
 
1440
        if(ret == 0){
 
1441
          avahi_simple_poll_quit(s);
 
1442
          return 0;
 
1443
        }
 
1444
        ret = clock_gettime(CLOCK_MONOTONIC,
 
1445
                            &mc->current_server->last_seen);
 
1446
        if(ret == -1){
 
1447
          perror_plus("clock_gettime");
 
1448
          return -1;
 
1449
        }
 
1450
        mc->current_server = mc->current_server->next;
 
1451
        block_time = 0;         /* Call avahi to find new Mandos
 
1452
                                   servers, but don't block */
 
1453
      }
 
1454
      
 
1455
      ret = avahi_simple_poll_iterate(s, (int)block_time);
 
1456
    }
 
1457
    if(ret != 0){
 
1458
      if(ret > 0 or errno != EINTR){
 
1459
        return (ret != 1) ? ret : 0;
 
1460
      }
 
1461
    }
 
1462
  }
 
1463
}
 
1464
 
 
1465
/* Set effective uid to 0, return errno */
 
1466
__attribute__((warn_unused_result))
 
1467
error_t raise_privileges(void){
 
1468
  error_t old_errno = errno;
 
1469
  error_t ret_errno = 0;
 
1470
  if(seteuid(0) == -1){
 
1471
    ret_errno = errno;
 
1472
  }
 
1473
  errno = old_errno;
 
1474
  return ret_errno;
 
1475
}
 
1476
 
 
1477
/* Set effective and real user ID to 0.  Return errno. */
 
1478
__attribute__((warn_unused_result))
 
1479
error_t raise_privileges_permanently(void){
 
1480
  error_t old_errno = errno;
 
1481
  error_t ret_errno = raise_privileges();
 
1482
  if(ret_errno != 0){
 
1483
    errno = old_errno;
 
1484
    return ret_errno;
 
1485
  }
 
1486
  if(setuid(0) == -1){
 
1487
    ret_errno = errno;
 
1488
  }
 
1489
  errno = old_errno;
 
1490
  return ret_errno;
 
1491
}
 
1492
 
 
1493
/* Set effective user ID to unprivileged saved user ID */
 
1494
__attribute__((warn_unused_result))
 
1495
error_t lower_privileges(void){
 
1496
  error_t old_errno = errno;
 
1497
  error_t ret_errno = 0;
 
1498
  if(seteuid(uid) == -1){
 
1499
    ret_errno = errno;
 
1500
  }
 
1501
  errno = old_errno;
 
1502
  return ret_errno;
 
1503
}
 
1504
 
 
1505
/* Lower privileges permanently */
 
1506
__attribute__((warn_unused_result))
 
1507
error_t lower_privileges_permanently(void){
 
1508
  error_t old_errno = errno;
 
1509
  error_t ret_errno = 0;
 
1510
  if(setuid(uid) == -1){
 
1511
    ret_errno = errno;
 
1512
  }
 
1513
  errno = old_errno;
 
1514
  return ret_errno;
 
1515
}
 
1516
 
 
1517
__attribute__((nonnull))
 
1518
void run_network_hooks(const char *mode, const char *interface,
 
1519
                       const float delay){
 
1520
  struct dirent **direntries = NULL;
 
1521
  if(hookdir_fd == -1){
 
1522
    hookdir_fd = open(hookdir, O_RDONLY);
 
1523
    if(hookdir_fd == -1){
 
1524
      if(errno == ENOENT){
 
1525
        if(debug){
 
1526
          fprintf_plus(stderr, "Network hook directory \"%s\" not"
 
1527
                       " found\n", hookdir);
 
1528
        }
 
1529
      } else {
 
1530
        perror_plus("open");
 
1531
      }
 
1532
      return;
 
1533
    }
 
1534
  }
 
1535
#ifdef __GLIBC__
 
1536
#if __GLIBC_PREREQ(2, 15)
 
1537
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
 
1538
                           runnable_hook, alphasort);
 
1539
#else  /* not __GLIBC_PREREQ(2, 15) */
 
1540
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
 
1541
                         alphasort);
 
1542
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
1543
#else   /* not __GLIBC__ */
 
1544
  int numhooks = scandir(hookdir, &direntries, runnable_hook,
 
1545
                         alphasort);
 
1546
#endif  /* not __GLIBC__ */
 
1547
  if(numhooks == -1){
 
1548
    perror_plus("scandir");
 
1549
    return;
 
1550
  }
 
1551
  struct dirent *direntry;
 
1552
  int ret;
 
1553
  int devnull = open("/dev/null", O_RDONLY);
 
1554
  for(int i = 0; i < numhooks; i++){
 
1555
    direntry = direntries[i];
 
1556
    if(debug){
 
1557
      fprintf_plus(stderr, "Running network hook \"%s\"\n",
 
1558
                   direntry->d_name);
 
1559
    }
 
1560
    pid_t hook_pid = fork();
 
1561
    if(hook_pid == 0){
 
1562
      /* Child */
 
1563
      /* Raise privileges */
 
1564
      errno = raise_privileges_permanently();
 
1565
      if(errno != 0){
 
1566
        perror_plus("Failed to raise privileges");
 
1567
        _exit(EX_NOPERM);
 
1568
      }
 
1569
      /* Set group */
 
1570
      errno = 0;
 
1571
      ret = setgid(0);
 
1572
      if(ret == -1){
 
1573
        perror_plus("setgid");
 
1574
        _exit(EX_NOPERM);
 
1575
      }
 
1576
      /* Reset supplementary groups */
 
1577
      errno = 0;
 
1578
      ret = setgroups(0, NULL);
 
1579
      if(ret == -1){
 
1580
        perror_plus("setgroups");
 
1581
        _exit(EX_NOPERM);
 
1582
      }
 
1583
      ret = dup2(devnull, STDIN_FILENO);
 
1584
      if(ret == -1){
 
1585
        perror_plus("dup2(devnull, STDIN_FILENO)");
 
1586
        _exit(EX_OSERR);
 
1587
      }
 
1588
      ret = close(devnull);
 
1589
      if(ret == -1){
 
1590
        perror_plus("close");
 
1591
        _exit(EX_OSERR);
 
1592
      }
 
1593
      ret = dup2(STDERR_FILENO, STDOUT_FILENO);
 
1594
      if(ret == -1){
 
1595
        perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
 
1596
        _exit(EX_OSERR);
 
1597
      }
 
1598
      ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
 
1599
      if(ret == -1){
 
1600
        perror_plus("setenv");
 
1601
        _exit(EX_OSERR);
 
1602
      }
 
1603
      ret = setenv("DEVICE", interface, 1);
 
1604
      if(ret == -1){
 
1605
        perror_plus("setenv");
 
1606
        _exit(EX_OSERR);
 
1607
      }
 
1608
      ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
 
1609
      if(ret == -1){
 
1610
        perror_plus("setenv");
 
1611
        _exit(EX_OSERR);
 
1612
      }
 
1613
      ret = setenv("MODE", mode, 1);
 
1614
      if(ret == -1){
 
1615
        perror_plus("setenv");
 
1616
        _exit(EX_OSERR);
 
1617
      }
 
1618
      char *delaystring;
 
1619
      ret = asprintf(&delaystring, "%f", (double)delay);
 
1620
      if(ret == -1){
 
1621
        perror_plus("asprintf");
 
1622
        _exit(EX_OSERR);
 
1623
      }
 
1624
      ret = setenv("DELAY", delaystring, 1);
 
1625
      if(ret == -1){
 
1626
        free(delaystring);
 
1627
        perror_plus("setenv");
 
1628
        _exit(EX_OSERR);
 
1629
      }
 
1630
      free(delaystring);
 
1631
      if(connect_to != NULL){
 
1632
        ret = setenv("CONNECT", connect_to, 1);
 
1633
        if(ret == -1){
 
1634
          perror_plus("setenv");
 
1635
          _exit(EX_OSERR);
 
1636
        }
 
1637
      }
 
1638
      int hook_fd = openat(hookdir_fd, direntry->d_name, O_RDONLY);
 
1639
      if(hook_fd == -1){
 
1640
        perror_plus("openat");
 
1641
        _exit(EXIT_FAILURE);
 
1642
      }
 
1643
      if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1644
        perror_plus("close");
 
1645
        _exit(EXIT_FAILURE);
 
1646
      }
 
1647
      if(fexecve(hook_fd, (char *const []){ direntry->d_name, NULL },
 
1648
                 environ) == -1){
 
1649
        perror_plus("fexecve");
 
1650
        _exit(EXIT_FAILURE);
 
1651
      }
 
1652
    } else {
 
1653
      if(hook_pid == -1){
 
1654
        perror_plus("fork");
 
1655
        free(direntry);
 
1656
        continue;
 
1657
      }
 
1658
      int status;
 
1659
      if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
 
1660
        perror_plus("waitpid");
 
1661
        free(direntry);
 
1662
        continue;
 
1663
      }
 
1664
      if(WIFEXITED(status)){
 
1665
        if(WEXITSTATUS(status) != 0){
 
1666
          fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
 
1667
                       " with status %d\n", direntry->d_name,
 
1668
                       WEXITSTATUS(status));
 
1669
          free(direntry);
 
1670
          continue;
 
1671
        }
 
1672
      } else if(WIFSIGNALED(status)){
 
1673
        fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
 
1674
                     " signal %d\n", direntry->d_name,
 
1675
                     WTERMSIG(status));
 
1676
        free(direntry);
 
1677
        continue;
 
1678
      } else {
 
1679
        fprintf_plus(stderr, "Warning: network hook \"%s\""
 
1680
                     " crashed\n", direntry->d_name);
 
1681
        free(direntry);
 
1682
        continue;
 
1683
      }
 
1684
    }
 
1685
    if(debug){
 
1686
      fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
 
1687
                   direntry->d_name);
 
1688
    }
 
1689
    free(direntry);
 
1690
  }
 
1691
  free(direntries);
 
1692
  if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1693
    perror_plus("close");
 
1694
  } else {
 
1695
    hookdir_fd = -1;
 
1696
  }
 
1697
  close(devnull);
 
1698
}
 
1699
 
 
1700
__attribute__((nonnull, warn_unused_result))
 
1701
error_t bring_up_interface(const char *const interface,
 
1702
                           const float delay){
 
1703
  error_t old_errno = errno;
 
1704
  int ret;
 
1705
  struct ifreq network;
 
1706
  unsigned int if_index = if_nametoindex(interface);
 
1707
  if(if_index == 0){
 
1708
    fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
 
1709
    errno = old_errno;
 
1710
    return ENXIO;
 
1711
  }
 
1712
  
 
1713
  if(quit_now){
 
1714
    errno = old_errno;
 
1715
    return EINTR;
 
1716
  }
 
1717
  
 
1718
  if(not interface_is_up(interface)){
 
1719
    error_t ret_errno = 0, ioctl_errno = 0;
 
1720
    if(not get_flags(interface, &network)){
 
1721
      ret_errno = errno;
 
1722
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1723
                   "\"%s\"\n", interface);
 
1724
      errno = old_errno;
 
1725
      return ret_errno;
 
1726
    }
 
1727
    network.ifr_flags |= IFF_UP; /* set flag */
 
1728
    
 
1729
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1730
    if(sd == -1){
 
1731
      ret_errno = errno;
 
1732
      perror_plus("socket");
 
1733
      errno = old_errno;
 
1734
      return ret_errno;
 
1735
    }
 
1736
    
 
1737
    if(quit_now){
 
1738
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1739
      if(ret == -1){
 
1740
        perror_plus("close");
 
1741
      }
 
1742
      errno = old_errno;
 
1743
      return EINTR;
 
1744
    }
 
1745
    
 
1746
    if(debug){
 
1747
      fprintf_plus(stderr, "Bringing up interface \"%s\"\n",
 
1748
                   interface);
 
1749
    }
 
1750
    
 
1751
    /* Raise privileges */
 
1752
    ret_errno = raise_privileges();
 
1753
    if(ret_errno != 0){
 
1754
      errno = ret_errno;
 
1755
      perror_plus("Failed to raise privileges");
 
1756
    }
 
1757
    
 
1758
#ifdef __linux__
 
1759
    int ret_linux;
 
1760
    bool restore_loglevel = false;
 
1761
    if(ret_errno == 0){
 
1762
      /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1763
         messages about the network interface to mess up the prompt */
 
1764
      ret_linux = klogctl(8, NULL, 5);
 
1765
      if(ret_linux == -1){
 
1766
        perror_plus("klogctl");
 
1767
      } else {
 
1768
        restore_loglevel = true;
 
1769
      }
 
1770
    }
 
1771
#endif  /* __linux__ */
 
1772
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1773
    ioctl_errno = errno;
 
1774
#ifdef __linux__
 
1775
    if(restore_loglevel){
 
1776
      ret_linux = klogctl(7, NULL, 0);
 
1777
      if(ret_linux == -1){
 
1778
        perror_plus("klogctl");
 
1779
      }
 
1780
    }
 
1781
#endif  /* __linux__ */
 
1782
    
 
1783
    /* If raise_privileges() succeeded above */
 
1784
    if(ret_errno == 0){
 
1785
      /* Lower privileges */
 
1786
      ret_errno = lower_privileges();
 
1787
      if(ret_errno != 0){
 
1788
        errno = ret_errno;
 
1789
        perror_plus("Failed to lower privileges");
 
1790
      }
 
1791
    }
 
1792
    
 
1793
    /* Close the socket */
 
1794
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1795
    if(ret == -1){
 
1796
      perror_plus("close");
 
1797
    }
 
1798
    
 
1799
    if(ret_setflags == -1){
 
1800
      errno = ioctl_errno;
 
1801
      perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
 
1802
      errno = old_errno;
 
1803
      return ioctl_errno;
 
1804
    }
 
1805
  } else if(debug){
 
1806
    fprintf_plus(stderr, "Interface \"%s\" is already up; good\n",
 
1807
                 interface);
 
1808
  }
 
1809
  
 
1810
  /* Sleep checking until interface is running.
 
1811
     Check every 0.25s, up to total time of delay */
 
1812
  for(int i=0; i < delay * 4; i++){
 
1813
    if(interface_is_running(interface)){
1021
1814
      break;
1022
1815
    }
1023
 
  }
1024
 
  close(flags_fd);
1025
 
  intmax_t tmpmax;
1026
 
  char *tmp;
1027
 
  errno = 0;
1028
 
  tmpmax = strtoimax(flagstring, &tmp, 0);
1029
 
  if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1030
 
                                         and not (isspace(*tmp)))
1031
 
     or tmpmax != (ifreq_flags)tmpmax){
1032
 
    free(flagstring);
1033
 
    return 0;
1034
 
  }
1035
 
  free(flagstring);
1036
 
  ifreq_flags flags = (ifreq_flags)tmpmax;
1037
 
  /* Reject the loopback device */
1038
 
  if(flags & IFF_LOOPBACK){
1039
 
    return 0;
1040
 
  }
1041
 
  /* Accept point-to-point devices only if connect_to is specified */
1042
 
  if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1043
 
    return 1;
1044
 
  }
1045
 
  /* Otherwise, reject non-broadcast-capable devices */
1046
 
  if(not (flags & IFF_BROADCAST)){
1047
 
    return 0;
1048
 
  }
1049
 
  /* Accept this device */
1050
 
  return 1;
 
1816
    struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1817
    ret = nanosleep(&sleeptime, NULL);
 
1818
    if(ret == -1 and errno != EINTR){
 
1819
      perror_plus("nanosleep");
 
1820
    }
 
1821
  }
 
1822
  
 
1823
  errno = old_errno;
 
1824
  return 0;
 
1825
}
 
1826
 
 
1827
__attribute__((nonnull, warn_unused_result))
 
1828
error_t take_down_interface(const char *const interface){
 
1829
  error_t old_errno = errno;
 
1830
  struct ifreq network;
 
1831
  unsigned int if_index = if_nametoindex(interface);
 
1832
  if(if_index == 0){
 
1833
    fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
 
1834
    errno = old_errno;
 
1835
    return ENXIO;
 
1836
  }
 
1837
  if(interface_is_up(interface)){
 
1838
    error_t ret_errno = 0, ioctl_errno = 0;
 
1839
    if(not get_flags(interface, &network) and debug){
 
1840
      ret_errno = errno;
 
1841
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1842
                   "\"%s\"\n", interface);
 
1843
      errno = old_errno;
 
1844
      return ret_errno;
 
1845
    }
 
1846
    network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
 
1847
    
 
1848
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1849
    if(sd == -1){
 
1850
      ret_errno = errno;
 
1851
      perror_plus("socket");
 
1852
      errno = old_errno;
 
1853
      return ret_errno;
 
1854
    }
 
1855
    
 
1856
    if(debug){
 
1857
      fprintf_plus(stderr, "Taking down interface \"%s\"\n",
 
1858
                   interface);
 
1859
    }
 
1860
    
 
1861
    /* Raise privileges */
 
1862
    ret_errno = raise_privileges();
 
1863
    if(ret_errno != 0){
 
1864
      errno = ret_errno;
 
1865
      perror_plus("Failed to raise privileges");
 
1866
    }
 
1867
    
 
1868
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1869
    ioctl_errno = errno;
 
1870
    
 
1871
    /* If raise_privileges() succeeded above */
 
1872
    if(ret_errno == 0){
 
1873
      /* Lower privileges */
 
1874
      ret_errno = lower_privileges();
 
1875
      if(ret_errno != 0){
 
1876
        errno = ret_errno;
 
1877
        perror_plus("Failed to lower privileges");
 
1878
      }
 
1879
    }
 
1880
    
 
1881
    /* Close the socket */
 
1882
    int ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1883
    if(ret == -1){
 
1884
      perror_plus("close");
 
1885
    }
 
1886
    
 
1887
    if(ret_setflags == -1){
 
1888
      errno = ioctl_errno;
 
1889
      perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
 
1890
      errno = old_errno;
 
1891
      return ioctl_errno;
 
1892
    }
 
1893
  } else if(debug){
 
1894
    fprintf_plus(stderr, "Interface \"%s\" is already down; odd\n",
 
1895
                 interface);
 
1896
  }
 
1897
  
 
1898
  errno = old_errno;
 
1899
  return 0;
1051
1900
}
1052
1901
 
1053
1902
int main(int argc, char *argv[]){
 
1903
  mandos_context mc = { .server = NULL, .dh_bits = 1024,
 
1904
                        .priority = "SECURE256:!CTYPE-X.509:"
 
1905
                        "+CTYPE-OPENPGP:!RSA", .current_server = NULL,
 
1906
                        .interfaces = NULL, .interfaces_size = 0 };
1054
1907
  AvahiSServiceBrowser *sb = NULL;
1055
 
  int error;
 
1908
  error_t ret_errno;
1056
1909
  int ret;
1057
1910
  intmax_t tmpmax;
1058
1911
  char *tmp;
1059
1912
  int exitcode = EXIT_SUCCESS;
1060
 
  const char *interface = "";
1061
 
  struct ifreq network;
1062
 
  int sd = -1;
1063
 
  bool take_down_interface = false;
1064
 
  uid_t uid;
1065
 
  gid_t gid;
1066
 
  char tempdir[] = "/tmp/mandosXXXXXX";
1067
 
  bool tempdir_created = false;
 
1913
  char *interfaces_to_take_down = NULL;
 
1914
  size_t interfaces_to_take_down_size = 0;
 
1915
  char run_tempdir[] = "/run/tmp/mandosXXXXXX";
 
1916
  char old_tempdir[] = "/tmp/mandosXXXXXX";
 
1917
  char *tempdir = NULL;
1068
1918
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1069
1919
  const char *seckey = PATHDIR "/" SECKEY;
1070
1920
  const char *pubkey = PATHDIR "/" PUBKEY;
 
1921
  char *interfaces_hooks = NULL;
1071
1922
  
1072
1923
  bool gnutls_initialized = false;
1073
1924
  bool gpgme_initialized = false;
1074
1925
  float delay = 2.5f;
 
1926
  double retry_interval = 10; /* 10s between trying a server and
 
1927
                                 retrying the same server again */
1075
1928
  
1076
1929
  struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1077
1930
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1083
1936
  errno = 0;
1084
1937
  ret = setgid(gid);
1085
1938
  if(ret == -1){
1086
 
    perror("setgid");
 
1939
    perror_plus("setgid");
1087
1940
  }
1088
1941
  
1089
1942
  /* Lower user privileges (temporarily) */
1090
1943
  errno = 0;
1091
1944
  ret = seteuid(uid);
1092
1945
  if(ret == -1){
1093
 
    perror("seteuid");
 
1946
    perror_plus("seteuid");
1094
1947
  }
1095
1948
  
1096
1949
  if(quit_now){
1131
1984
        .arg = "SECONDS",
1132
1985
        .doc = "Maximum delay to wait for interface startup",
1133
1986
        .group = 2 },
 
1987
      { .name = "retry", .key = 132,
 
1988
        .arg = "SECONDS",
 
1989
        .doc = "Retry interval used when denied by the Mandos server",
 
1990
        .group = 2 },
 
1991
      { .name = "network-hook-dir", .key = 133,
 
1992
        .arg = "DIR",
 
1993
        .doc = "Directory where network hooks are located",
 
1994
        .group = 2 },
 
1995
      /*
 
1996
       * These reproduce what we would get without ARGP_NO_HELP
 
1997
       */
 
1998
      { .name = "help", .key = '?',
 
1999
        .doc = "Give this help list", .group = -1 },
 
2000
      { .name = "usage", .key = -3,
 
2001
        .doc = "Give a short usage message", .group = -1 },
 
2002
      { .name = "version", .key = 'V',
 
2003
        .doc = "Print program version", .group = -1 },
1134
2004
      { .name = NULL }
1135
2005
    };
1136
2006
    
1137
2007
    error_t parse_opt(int key, char *arg,
1138
2008
                      struct argp_state *state){
 
2009
      errno = 0;
1139
2010
      switch(key){
1140
2011
      case 128:                 /* --debug */
1141
2012
        debug = true;
1144
2015
        connect_to = arg;
1145
2016
        break;
1146
2017
      case 'i':                 /* --interface */
1147
 
        interface = arg;
 
2018
        ret_errno = argz_add_sep(&mc.interfaces, &mc.interfaces_size,
 
2019
                                 arg, (int)',');
 
2020
        if(ret_errno != 0){
 
2021
          argp_error(state, "%s", strerror(ret_errno));
 
2022
        }
1148
2023
        break;
1149
2024
      case 's':                 /* --seckey */
1150
2025
        seckey = arg;
1157
2032
        tmpmax = strtoimax(arg, &tmp, 10);
1158
2033
        if(errno != 0 or tmp == arg or *tmp != '\0'
1159
2034
           or tmpmax != (typeof(mc.dh_bits))tmpmax){
1160
 
          fprintf(stderr, "Bad number of DH bits\n");
1161
 
          exit(EXIT_FAILURE);
 
2035
          argp_error(state, "Bad number of DH bits");
1162
2036
        }
1163
2037
        mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1164
2038
        break;
1169
2043
        errno = 0;
1170
2044
        delay = strtof(arg, &tmp);
1171
2045
        if(errno != 0 or tmp == arg or *tmp != '\0'){
1172
 
          fprintf(stderr, "Bad delay\n");
1173
 
          exit(EXIT_FAILURE);
1174
 
        }
1175
 
        break;
1176
 
      case ARGP_KEY_ARG:
1177
 
        argp_usage(state);
1178
 
      case ARGP_KEY_END:
 
2046
          argp_error(state, "Bad delay");
 
2047
        }
 
2048
      case 132:                 /* --retry */
 
2049
        errno = 0;
 
2050
        retry_interval = strtod(arg, &tmp);
 
2051
        if(errno != 0 or tmp == arg or *tmp != '\0'
 
2052
           or (retry_interval * 1000) > INT_MAX
 
2053
           or retry_interval < 0){
 
2054
          argp_error(state, "Bad retry interval");
 
2055
        }
 
2056
        break;
 
2057
      case 133:                 /* --network-hook-dir */
 
2058
        hookdir = arg;
 
2059
        break;
 
2060
        /*
 
2061
         * These reproduce what we would get without ARGP_NO_HELP
 
2062
         */
 
2063
      case '?':                 /* --help */
 
2064
        argp_state_help(state, state->out_stream,
 
2065
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
 
2066
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
2067
      case -3:                  /* --usage */
 
2068
        argp_state_help(state, state->out_stream,
 
2069
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
2070
      case 'V':                 /* --version */
 
2071
        fprintf_plus(state->out_stream, "%s\n", argp_program_version);
 
2072
        exit(argp_err_exit_status);
1179
2073
        break;
1180
2074
      default:
1181
2075
        return ARGP_ERR_UNKNOWN;
1182
2076
      }
1183
 
      return 0;
 
2077
      return errno;
1184
2078
    }
1185
2079
    
1186
2080
    struct argp argp = { .options = options, .parser = parse_opt,
1187
2081
                         .args_doc = "",
1188
2082
                         .doc = "Mandos client -- Get and decrypt"
1189
2083
                         " passwords from a Mandos server" };
1190
 
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
1191
 
    if(ret == ARGP_ERR_UNKNOWN){
1192
 
      fprintf(stderr, "Unknown error while parsing arguments\n");
1193
 
      exitcode = EXIT_FAILURE;
1194
 
      goto end;
1195
 
    }
 
2084
    ret = argp_parse(&argp, argc, argv,
 
2085
                     ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
 
2086
    switch(ret){
 
2087
    case 0:
 
2088
      break;
 
2089
    case ENOMEM:
 
2090
    default:
 
2091
      errno = ret;
 
2092
      perror_plus("argp_parse");
 
2093
      exitcode = EX_OSERR;
 
2094
      goto end;
 
2095
    case EINVAL:
 
2096
      exitcode = EX_USAGE;
 
2097
      goto end;
 
2098
    }
 
2099
  }
 
2100
    
 
2101
  {
 
2102
    /* Work around Debian bug #633582:
 
2103
       <http://bugs.debian.org/633582> */
 
2104
    
 
2105
    /* Re-raise privileges */
 
2106
    ret_errno = raise_privileges();
 
2107
    if(ret_errno != 0){
 
2108
      errno = ret_errno;
 
2109
      perror_plus("Failed to raise privileges");
 
2110
    } else {
 
2111
      struct stat st;
 
2112
      
 
2113
      if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
 
2114
        int seckey_fd = open(seckey, O_RDONLY);
 
2115
        if(seckey_fd == -1){
 
2116
          perror_plus("open");
 
2117
        } else {
 
2118
          ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
 
2119
          if(ret == -1){
 
2120
            perror_plus("fstat");
 
2121
          } else {
 
2122
            if(S_ISREG(st.st_mode)
 
2123
               and st.st_uid == 0 and st.st_gid == 0){
 
2124
              ret = fchown(seckey_fd, uid, gid);
 
2125
              if(ret == -1){
 
2126
                perror_plus("fchown");
 
2127
              }
 
2128
            }
 
2129
          }
 
2130
          TEMP_FAILURE_RETRY(close(seckey_fd));
 
2131
        }
 
2132
      }
 
2133
    
 
2134
      if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){
 
2135
        int pubkey_fd = open(pubkey, O_RDONLY);
 
2136
        if(pubkey_fd == -1){
 
2137
          perror_plus("open");
 
2138
        } else {
 
2139
          ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
 
2140
          if(ret == -1){
 
2141
            perror_plus("fstat");
 
2142
          } else {
 
2143
            if(S_ISREG(st.st_mode)
 
2144
               and st.st_uid == 0 and st.st_gid == 0){
 
2145
              ret = fchown(pubkey_fd, uid, gid);
 
2146
              if(ret == -1){
 
2147
                perror_plus("fchown");
 
2148
              }
 
2149
            }
 
2150
          }
 
2151
          TEMP_FAILURE_RETRY(close(pubkey_fd));
 
2152
        }
 
2153
      }
 
2154
    
 
2155
      /* Lower privileges */
 
2156
      ret_errno = lower_privileges();
 
2157
      if(ret_errno != 0){
 
2158
        errno = ret_errno;
 
2159
        perror_plus("Failed to lower privileges");
 
2160
      }
 
2161
    }
 
2162
  }
 
2163
  
 
2164
  /* Remove invalid interface names (except "none") */
 
2165
  {
 
2166
    char *interface = NULL;
 
2167
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
 
2168
                                 interface))){
 
2169
      if(strcmp(interface, "none") != 0
 
2170
         and if_nametoindex(interface) == 0){
 
2171
        if(interface[0] != '\0'){
 
2172
          fprintf_plus(stderr, "Not using nonexisting interface"
 
2173
                       " \"%s\"\n", interface);
 
2174
        }
 
2175
        argz_delete(&mc.interfaces, &mc.interfaces_size, interface);
 
2176
        interface = NULL;
 
2177
      }
 
2178
    }
 
2179
  }
 
2180
  
 
2181
  /* Run network hooks */
 
2182
  {
 
2183
    if(mc.interfaces != NULL){
 
2184
      interfaces_hooks = malloc(mc.interfaces_size);
 
2185
      if(interfaces_hooks == NULL){
 
2186
        perror_plus("malloc");
 
2187
        goto end;
 
2188
      }
 
2189
      memcpy(interfaces_hooks, mc.interfaces, mc.interfaces_size);
 
2190
      argz_stringify(interfaces_hooks, mc.interfaces_size, (int)',');
 
2191
    }
 
2192
    run_network_hooks("start", interfaces_hooks != NULL ?
 
2193
                      interfaces_hooks : "", delay);
1196
2194
  }
1197
2195
  
1198
2196
  if(not debug){
1199
2197
    avahi_set_log_function(empty_log);
1200
2198
  }
1201
 
 
1202
 
  if(interface[0] == '\0'){
1203
 
    struct dirent **direntries;
1204
 
    ret = scandir(sys_class_net, &direntries, good_interface,
1205
 
                  alphasort);
1206
 
    if(ret >= 1){
1207
 
      /* Pick the first good interface */
1208
 
      interface = strdup(direntries[0]->d_name);
1209
 
      if(interface == NULL){
1210
 
        perror("malloc");
1211
 
        free(direntries);
1212
 
        exitcode = EXIT_FAILURE;
1213
 
        goto end;
1214
 
      }
1215
 
      free(direntries);
1216
 
    } else {
1217
 
      free(direntries);
1218
 
      fprintf(stderr, "Could not find a network interface\n");
1219
 
      exitcode = EXIT_FAILURE;
1220
 
      goto end;
1221
 
    }
1222
 
  }
1223
2199
  
1224
2200
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
1225
2201
     from the signal handler */
1226
2202
  /* Initialize the pseudo-RNG for Avahi */
1227
2203
  srand((unsigned int) time(NULL));
1228
 
  mc.simple_poll = avahi_simple_poll_new();
1229
 
  if(mc.simple_poll == NULL){
1230
 
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1231
 
    exitcode = EXIT_FAILURE;
 
2204
  simple_poll = avahi_simple_poll_new();
 
2205
  if(simple_poll == NULL){
 
2206
    fprintf_plus(stderr,
 
2207
                 "Avahi: Failed to create simple poll object.\n");
 
2208
    exitcode = EX_UNAVAILABLE;
1232
2209
    goto end;
1233
2210
  }
1234
2211
  
1235
2212
  sigemptyset(&sigterm_action.sa_mask);
1236
2213
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1237
2214
  if(ret == -1){
1238
 
    perror("sigaddset");
1239
 
    exitcode = EXIT_FAILURE;
 
2215
    perror_plus("sigaddset");
 
2216
    exitcode = EX_OSERR;
1240
2217
    goto end;
1241
2218
  }
1242
2219
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1243
2220
  if(ret == -1){
1244
 
    perror("sigaddset");
1245
 
    exitcode = EXIT_FAILURE;
 
2221
    perror_plus("sigaddset");
 
2222
    exitcode = EX_OSERR;
1246
2223
    goto end;
1247
2224
  }
1248
2225
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1249
2226
  if(ret == -1){
1250
 
    perror("sigaddset");
1251
 
    exitcode = EXIT_FAILURE;
 
2227
    perror_plus("sigaddset");
 
2228
    exitcode = EX_OSERR;
1252
2229
    goto end;
1253
2230
  }
1254
2231
  /* Need to check if the handler is SIG_IGN before handling:
1257
2234
  */
1258
2235
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1259
2236
  if(ret == -1){
1260
 
    perror("sigaction");
1261
 
    return EXIT_FAILURE;
 
2237
    perror_plus("sigaction");
 
2238
    return EX_OSERR;
1262
2239
  }
1263
2240
  if(old_sigterm_action.sa_handler != SIG_IGN){
1264
2241
    ret = sigaction(SIGINT, &sigterm_action, NULL);
1265
2242
    if(ret == -1){
1266
 
      perror("sigaction");
1267
 
      exitcode = EXIT_FAILURE;
 
2243
      perror_plus("sigaction");
 
2244
      exitcode = EX_OSERR;
1268
2245
      goto end;
1269
2246
    }
1270
2247
  }
1271
2248
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1272
2249
  if(ret == -1){
1273
 
    perror("sigaction");
1274
 
    return EXIT_FAILURE;
 
2250
    perror_plus("sigaction");
 
2251
    return EX_OSERR;
1275
2252
  }
1276
2253
  if(old_sigterm_action.sa_handler != SIG_IGN){
1277
2254
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
1278
2255
    if(ret == -1){
1279
 
      perror("sigaction");
1280
 
      exitcode = EXIT_FAILURE;
 
2256
      perror_plus("sigaction");
 
2257
      exitcode = EX_OSERR;
1281
2258
      goto end;
1282
2259
    }
1283
2260
  }
1284
2261
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1285
2262
  if(ret == -1){
1286
 
    perror("sigaction");
1287
 
    return EXIT_FAILURE;
 
2263
    perror_plus("sigaction");
 
2264
    return EX_OSERR;
1288
2265
  }
1289
2266
  if(old_sigterm_action.sa_handler != SIG_IGN){
1290
2267
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
1291
2268
    if(ret == -1){
1292
 
      perror("sigaction");
1293
 
      exitcode = EXIT_FAILURE;
1294
 
      goto end;
1295
 
    }
1296
 
  }
1297
 
  
1298
 
  /* If the interface is down, bring it up */
1299
 
  if(strcmp(interface, "none") != 0){
1300
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1301
 
    if(if_index == 0){
1302
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1303
 
      exitcode = EXIT_FAILURE;
1304
 
      goto end;
1305
 
    }
1306
 
    
1307
 
    if(quit_now){
1308
 
      goto end;
1309
 
    }
1310
 
    
1311
 
    /* Re-raise priviliges */
1312
 
    errno = 0;
1313
 
    ret = seteuid(0);
1314
 
    if(ret == -1){
1315
 
      perror("seteuid");
1316
 
    }
1317
 
    
1318
 
#ifdef __linux__
1319
 
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1320
 
       messages to mess up the prompt */
1321
 
    ret = klogctl(8, NULL, 5);
1322
 
    bool restore_loglevel = true;
1323
 
    if(ret == -1){
1324
 
      restore_loglevel = false;
1325
 
      perror("klogctl");
1326
 
    }
1327
 
#endif  /* __linux__ */
1328
 
    
1329
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1330
 
    if(sd < 0){
1331
 
      perror("socket");
1332
 
      exitcode = EXIT_FAILURE;
1333
 
#ifdef __linux__
1334
 
      if(restore_loglevel){
1335
 
        ret = klogctl(7, NULL, 0);
1336
 
        if(ret == -1){
1337
 
          perror("klogctl");
1338
 
        }
1339
 
      }
1340
 
#endif  /* __linux__ */
1341
 
      /* Lower privileges */
1342
 
      errno = 0;
1343
 
      ret = seteuid(uid);
1344
 
      if(ret == -1){
1345
 
        perror("seteuid");
1346
 
      }
1347
 
      goto end;
1348
 
    }
1349
 
    strcpy(network.ifr_name, interface);
1350
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
1351
 
    if(ret == -1){
1352
 
      perror("ioctl SIOCGIFFLAGS");
1353
 
#ifdef __linux__
1354
 
      if(restore_loglevel){
1355
 
        ret = klogctl(7, NULL, 0);
1356
 
        if(ret == -1){
1357
 
          perror("klogctl");
1358
 
        }
1359
 
      }
1360
 
#endif  /* __linux__ */
1361
 
      exitcode = EXIT_FAILURE;
1362
 
      /* Lower privileges */
1363
 
      errno = 0;
1364
 
      ret = seteuid(uid);
1365
 
      if(ret == -1){
1366
 
        perror("seteuid");
1367
 
      }
1368
 
      goto end;
1369
 
    }
1370
 
    if((network.ifr_flags & IFF_UP) == 0){
1371
 
      network.ifr_flags |= IFF_UP;
1372
 
      take_down_interface = true;
1373
 
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
1374
 
      if(ret == -1){
1375
 
        take_down_interface = false;
1376
 
        perror("ioctl SIOCSIFFLAGS");
1377
 
        exitcode = EXIT_FAILURE;
1378
 
#ifdef __linux__
1379
 
        if(restore_loglevel){
1380
 
          ret = klogctl(7, NULL, 0);
1381
 
          if(ret == -1){
1382
 
            perror("klogctl");
 
2269
      perror_plus("sigaction");
 
2270
      exitcode = EX_OSERR;
 
2271
      goto end;
 
2272
    }
 
2273
  }
 
2274
  
 
2275
  /* If no interfaces were specified, make a list */
 
2276
  if(mc.interfaces == NULL){
 
2277
    struct dirent **direntries = NULL;
 
2278
    /* Look for any good interfaces */
 
2279
    ret = scandir(sys_class_net, &direntries, good_interface,
 
2280
                  alphasort);
 
2281
    if(ret >= 1){
 
2282
      /* Add all found interfaces to interfaces list */
 
2283
      for(int i = 0; i < ret; ++i){
 
2284
        ret_errno = argz_add(&mc.interfaces, &mc.interfaces_size,
 
2285
                             direntries[i]->d_name);
 
2286
        if(ret_errno != 0){
 
2287
          errno = ret_errno;
 
2288
          perror_plus("argz_add");
 
2289
          free(direntries[i]);
 
2290
          continue;
 
2291
        }
 
2292
        if(debug){
 
2293
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
 
2294
                       direntries[i]->d_name);
 
2295
        }
 
2296
        free(direntries[i]);
 
2297
      }
 
2298
      free(direntries);
 
2299
    } else {
 
2300
      if(ret == 0){
 
2301
        free(direntries);
 
2302
      }
 
2303
      fprintf_plus(stderr, "Could not find a network interface\n");
 
2304
      exitcode = EXIT_FAILURE;
 
2305
      goto end;
 
2306
    }
 
2307
  }
 
2308
  
 
2309
  /* Bring up interfaces which are down, and remove any "none"s */
 
2310
  {
 
2311
    char *interface = NULL;
 
2312
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
 
2313
                                 interface))){
 
2314
      /* If interface name is "none", stop bringing up interfaces.
 
2315
         Also remove all instances of "none" from the list */
 
2316
      if(strcmp(interface, "none") == 0){
 
2317
        argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2318
                    interface);
 
2319
        interface = NULL;
 
2320
        while((interface = argz_next(mc.interfaces,
 
2321
                                     mc.interfaces_size, interface))){
 
2322
          if(strcmp(interface, "none") == 0){
 
2323
            argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2324
                        interface);
 
2325
            interface = NULL;
1383
2326
          }
1384
2327
        }
1385
 
#endif  /* __linux__ */
1386
 
        /* Lower privileges */
1387
 
        errno = 0;
1388
 
        ret = seteuid(uid);
1389
 
        if(ret == -1){
1390
 
          perror("seteuid");
1391
 
        }
1392
 
        goto end;
1393
 
      }
1394
 
    }
1395
 
    /* sleep checking until interface is running */
1396
 
    for(int i=0; i < delay * 4; i++){
1397
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1398
 
      if(ret == -1){
1399
 
        perror("ioctl SIOCGIFFLAGS");
1400
 
      } else if(network.ifr_flags & IFF_RUNNING){
1401
2328
        break;
1402
2329
      }
1403
 
      struct timespec sleeptime = { .tv_nsec = 250000000 };
1404
 
      ret = nanosleep(&sleeptime, NULL);
1405
 
      if(ret == -1 and errno != EINTR){
1406
 
        perror("nanosleep");
1407
 
      }
1408
 
    }
1409
 
    if(not take_down_interface){
1410
 
      /* We won't need the socket anymore */
1411
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1412
 
      if(ret == -1){
1413
 
        perror("close");
1414
 
      }
1415
 
    }
1416
 
#ifdef __linux__
1417
 
    if(restore_loglevel){
1418
 
      /* Restores kernel loglevel to default */
1419
 
      ret = klogctl(7, NULL, 0);
1420
 
      if(ret == -1){
1421
 
        perror("klogctl");
1422
 
      }
1423
 
    }
1424
 
#endif  /* __linux__ */
1425
 
    /* Lower privileges */
1426
 
    errno = 0;
1427
 
    if(take_down_interface){
1428
 
      /* Lower privileges */
1429
 
      ret = seteuid(uid);
1430
 
      if(ret == -1){
1431
 
        perror("seteuid");
1432
 
      }
1433
 
    } else {
1434
 
      /* Lower privileges permanently */
1435
 
      ret = setuid(uid);
1436
 
      if(ret == -1){
1437
 
        perror("setuid");
1438
 
      }
1439
 
    }
 
2330
      bool interface_was_up = interface_is_up(interface);
 
2331
      errno = bring_up_interface(interface, delay);
 
2332
      if(not interface_was_up){
 
2333
        if(errno != 0){
 
2334
          perror_plus("Failed to bring up interface");
 
2335
        } else {
 
2336
          errno = argz_add(&interfaces_to_take_down,
 
2337
                           &interfaces_to_take_down_size,
 
2338
                           interface);
 
2339
          if(errno != 0){
 
2340
            perror_plus("argz_add");
 
2341
          }
 
2342
        }
 
2343
      }
 
2344
    }
 
2345
    if(debug and (interfaces_to_take_down == NULL)){
 
2346
      fprintf_plus(stderr, "No interfaces were brought up\n");
 
2347
    }
 
2348
  }
 
2349
  
 
2350
  /* If we only got one interface, explicitly use only that one */
 
2351
  if(argz_count(mc.interfaces, mc.interfaces_size) == 1){
 
2352
    if(debug){
 
2353
      fprintf_plus(stderr, "Using only interface \"%s\"\n",
 
2354
                   mc.interfaces);
 
2355
    }
 
2356
    if_index = (AvahiIfIndex)if_nametoindex(mc.interfaces);
1440
2357
  }
1441
2358
  
1442
2359
  if(quit_now){
1443
2360
    goto end;
1444
2361
  }
1445
2362
  
1446
 
  ret = init_gnutls_global(pubkey, seckey);
 
2363
  ret = init_gnutls_global(pubkey, seckey, &mc);
1447
2364
  if(ret == -1){
1448
 
    fprintf(stderr, "init_gnutls_global failed\n");
1449
 
    exitcode = EXIT_FAILURE;
 
2365
    fprintf_plus(stderr, "init_gnutls_global failed\n");
 
2366
    exitcode = EX_UNAVAILABLE;
1450
2367
    goto end;
1451
2368
  } else {
1452
2369
    gnutls_initialized = true;
1456
2373
    goto end;
1457
2374
  }
1458
2375
  
1459
 
  tempdir_created = true;
1460
 
  if(mkdtemp(tempdir) == NULL){
1461
 
    tempdir_created = false;
1462
 
    perror("mkdtemp");
 
2376
  /* Try /run/tmp before /tmp */
 
2377
  tempdir = mkdtemp(run_tempdir);
 
2378
  if(tempdir == NULL and errno == ENOENT){
 
2379
      if(debug){
 
2380
        fprintf_plus(stderr, "Tempdir %s did not work, trying %s\n",
 
2381
                     run_tempdir, old_tempdir);
 
2382
      }
 
2383
      tempdir = mkdtemp(old_tempdir);
 
2384
  }
 
2385
  if(tempdir == NULL){
 
2386
    perror_plus("mkdtemp");
1463
2387
    goto end;
1464
2388
  }
1465
2389
  
1467
2391
    goto end;
1468
2392
  }
1469
2393
  
1470
 
  if(not init_gpgme(pubkey, seckey, tempdir)){
1471
 
    fprintf(stderr, "init_gpgme failed\n");
1472
 
    exitcode = EXIT_FAILURE;
 
2394
  if(not init_gpgme(pubkey, seckey, tempdir, &mc)){
 
2395
    fprintf_plus(stderr, "init_gpgme failed\n");
 
2396
    exitcode = EX_UNAVAILABLE;
1473
2397
    goto end;
1474
2398
  } else {
1475
2399
    gpgme_initialized = true;
1483
2407
    /* Connect directly, do not use Zeroconf */
1484
2408
    /* (Mainly meant for debugging) */
1485
2409
    char *address = strrchr(connect_to, ':');
 
2410
    
1486
2411
    if(address == NULL){
1487
 
      fprintf(stderr, "No colon in address\n");
1488
 
      exitcode = EXIT_FAILURE;
 
2412
      fprintf_plus(stderr, "No colon in address\n");
 
2413
      exitcode = EX_USAGE;
1489
2414
      goto end;
1490
2415
    }
1491
2416
    
1493
2418
      goto end;
1494
2419
    }
1495
2420
    
1496
 
    uint16_t port;
 
2421
    in_port_t port;
1497
2422
    errno = 0;
1498
2423
    tmpmax = strtoimax(address+1, &tmp, 10);
1499
2424
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
1500
 
       or tmpmax != (uint16_t)tmpmax){
1501
 
      fprintf(stderr, "Bad port number\n");
1502
 
      exitcode = EXIT_FAILURE;
 
2425
       or tmpmax != (in_port_t)tmpmax){
 
2426
      fprintf_plus(stderr, "Bad port number\n");
 
2427
      exitcode = EX_USAGE;
1503
2428
      goto end;
1504
2429
    }
1505
 
  
 
2430
    
1506
2431
    if(quit_now){
1507
2432
      goto end;
1508
2433
    }
1509
2434
    
1510
 
    port = (uint16_t)tmpmax;
 
2435
    port = (in_port_t)tmpmax;
1511
2436
    *address = '\0';
1512
 
    address = connect_to;
1513
2437
    /* Colon in address indicates IPv6 */
1514
2438
    int af;
1515
 
    if(strchr(address, ':') != NULL){
 
2439
    if(strchr(connect_to, ':') != NULL){
1516
2440
      af = AF_INET6;
 
2441
      /* Accept [] around IPv6 address - see RFC 5952 */
 
2442
      if(connect_to[0] == '[' and address[-1] == ']')
 
2443
        {
 
2444
          connect_to++;
 
2445
          address[-1] = '\0';
 
2446
        }
1517
2447
    } else {
1518
2448
      af = AF_INET;
1519
2449
    }
 
2450
    address = connect_to;
1520
2451
    
1521
2452
    if(quit_now){
1522
2453
      goto end;
1523
2454
    }
1524
2455
    
1525
 
    ret = start_mandos_communication(address, port, if_index, af);
1526
 
    if(ret < 0){
1527
 
      exitcode = EXIT_FAILURE;
1528
 
    } else {
 
2456
    while(not quit_now){
 
2457
      ret = start_mandos_communication(address, port, if_index, af,
 
2458
                                       &mc);
 
2459
      if(quit_now or ret == 0){
 
2460
        break;
 
2461
      }
 
2462
      if(debug){
 
2463
        fprintf_plus(stderr, "Retrying in %d seconds\n",
 
2464
                     (int)retry_interval);
 
2465
      }
 
2466
      sleep((unsigned int)retry_interval);
 
2467
    }
 
2468
    
 
2469
    if(not quit_now){
1529
2470
      exitcode = EXIT_SUCCESS;
1530
2471
    }
 
2472
    
1531
2473
    goto end;
1532
2474
  }
1533
2475
  
1545
2487
    config.publish_domain = 0;
1546
2488
    
1547
2489
    /* Allocate a new server */
1548
 
    mc.server = avahi_server_new(avahi_simple_poll_get
1549
 
                                 (mc.simple_poll), &config, NULL,
1550
 
                                 NULL, &error);
 
2490
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
2491
                                 &config, NULL, NULL, &ret_errno);
1551
2492
    
1552
2493
    /* Free the Avahi configuration data */
1553
2494
    avahi_server_config_free(&config);
1555
2496
  
1556
2497
  /* Check if creating the Avahi server object succeeded */
1557
2498
  if(mc.server == NULL){
1558
 
    fprintf(stderr, "Failed to create Avahi server: %s\n",
1559
 
            avahi_strerror(error));
1560
 
    exitcode = EXIT_FAILURE;
 
2499
    fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
 
2500
                 avahi_strerror(ret_errno));
 
2501
    exitcode = EX_UNAVAILABLE;
1561
2502
    goto end;
1562
2503
  }
1563
2504
  
1568
2509
  /* Create the Avahi service browser */
1569
2510
  sb = avahi_s_service_browser_new(mc.server, if_index,
1570
2511
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1571
 
                                   NULL, 0, browse_callback, NULL);
 
2512
                                   NULL, 0, browse_callback,
 
2513
                                   (void *)&mc);
1572
2514
  if(sb == NULL){
1573
 
    fprintf(stderr, "Failed to create service browser: %s\n",
1574
 
            avahi_strerror(avahi_server_errno(mc.server)));
1575
 
    exitcode = EXIT_FAILURE;
 
2515
    fprintf_plus(stderr, "Failed to create service browser: %s\n",
 
2516
                 avahi_strerror(avahi_server_errno(mc.server)));
 
2517
    exitcode = EX_UNAVAILABLE;
1576
2518
    goto end;
1577
2519
  }
1578
2520
  
1583
2525
  /* Run the main loop */
1584
2526
  
1585
2527
  if(debug){
1586
 
    fprintf(stderr, "Starting Avahi loop search\n");
 
2528
    fprintf_plus(stderr, "Starting Avahi loop search\n");
1587
2529
  }
1588
2530
  
1589
 
  avahi_simple_poll_loop(mc.simple_poll);
 
2531
  ret = avahi_loop_with_timeout(simple_poll,
 
2532
                                (int)(retry_interval * 1000), &mc);
 
2533
  if(debug){
 
2534
    fprintf_plus(stderr, "avahi_loop_with_timeout exited %s\n",
 
2535
                 (ret == 0) ? "successfully" : "with error");
 
2536
  }
1590
2537
  
1591
2538
 end:
1592
2539
  
1593
2540
  if(debug){
1594
 
    fprintf(stderr, "%s exiting\n", argv[0]);
 
2541
    fprintf_plus(stderr, "%s exiting\n", argv[0]);
1595
2542
  }
1596
2543
  
1597
2544
  /* Cleanup things */
 
2545
  free(mc.interfaces);
 
2546
  
1598
2547
  if(sb != NULL)
1599
2548
    avahi_s_service_browser_free(sb);
1600
2549
  
1601
2550
  if(mc.server != NULL)
1602
2551
    avahi_server_free(mc.server);
1603
2552
  
1604
 
  if(mc.simple_poll != NULL)
1605
 
    avahi_simple_poll_free(mc.simple_poll);
 
2553
  if(simple_poll != NULL)
 
2554
    avahi_simple_poll_free(simple_poll);
1606
2555
  
1607
2556
  if(gnutls_initialized){
1608
2557
    gnutls_certificate_free_credentials(mc.cred);
1614
2563
    gpgme_release(mc.ctx);
1615
2564
  }
1616
2565
  
1617
 
  /* Take down the network interface */
1618
 
  if(take_down_interface){
1619
 
    /* Re-raise priviliges */
1620
 
    errno = 0;
1621
 
    ret = seteuid(0);
1622
 
    if(ret == -1){
1623
 
      perror("seteuid");
1624
 
    }
1625
 
    if(geteuid() == 0){
1626
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1627
 
      if(ret == -1){
1628
 
        perror("ioctl SIOCGIFFLAGS");
1629
 
      } else if(network.ifr_flags & IFF_UP) {
1630
 
        network.ifr_flags &= ~IFF_UP; /* clear flag */
1631
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
1632
 
        if(ret == -1){
1633
 
          perror("ioctl SIOCSIFFLAGS");
1634
 
        }
1635
 
      }
1636
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1637
 
      if(ret == -1){
1638
 
        perror("close");
1639
 
      }
1640
 
      /* Lower privileges permanently */
1641
 
      errno = 0;
1642
 
      ret = setuid(uid);
1643
 
      if(ret == -1){
1644
 
        perror("setuid");
1645
 
      }
1646
 
    }
1647
 
  }
1648
 
  
1649
 
  /* Removes the temp directory used by GPGME */
1650
 
  if(tempdir_created){
1651
 
    DIR *d;
1652
 
    struct dirent *direntry;
1653
 
    d = opendir(tempdir);
1654
 
    if(d == NULL){
1655
 
      if(errno != ENOENT){
1656
 
        perror("opendir");
1657
 
      }
1658
 
    } else {
1659
 
      while(true){
1660
 
        direntry = readdir(d);
1661
 
        if(direntry == NULL){
1662
 
          break;
1663
 
        }
1664
 
        /* Skip "." and ".." */
1665
 
        if(direntry->d_name[0] == '.'
1666
 
           and (direntry->d_name[1] == '\0'
1667
 
                or (direntry->d_name[1] == '.'
1668
 
                    and direntry->d_name[2] == '\0'))){
1669
 
          continue;
1670
 
        }
1671
 
        char *fullname = NULL;
1672
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
1673
 
                       direntry->d_name);
1674
 
        if(ret < 0){
1675
 
          perror("asprintf");
1676
 
          continue;
1677
 
        }
1678
 
        ret = remove(fullname);
1679
 
        if(ret == -1){
1680
 
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1681
 
                  strerror(errno));
1682
 
        }
1683
 
        free(fullname);
1684
 
      }
1685
 
      closedir(d);
1686
 
    }
1687
 
    ret = rmdir(tempdir);
1688
 
    if(ret == -1 and errno != ENOENT){
1689
 
      perror("rmdir");
 
2566
  /* Cleans up the circular linked list of Mandos servers the client
 
2567
     has seen */
 
2568
  if(mc.current_server != NULL){
 
2569
    mc.current_server->prev->next = NULL;
 
2570
    while(mc.current_server != NULL){
 
2571
      server *next = mc.current_server->next;
 
2572
#ifdef __GNUC__
 
2573
#pragma GCC diagnostic push
 
2574
#pragma GCC diagnostic ignored "-Wcast-qual"
 
2575
#endif
 
2576
      free((char *)(mc.current_server->ip));
 
2577
#ifdef __GNUC__
 
2578
#pragma GCC diagnostic pop
 
2579
#endif
 
2580
      free(mc.current_server);
 
2581
      mc.current_server = next;
 
2582
    }
 
2583
  }
 
2584
  
 
2585
  /* Re-raise privileges */
 
2586
  {
 
2587
    ret_errno = raise_privileges();
 
2588
    if(ret_errno != 0){
 
2589
      errno = ret_errno;
 
2590
      perror_plus("Failed to raise privileges");
 
2591
    } else {
 
2592
      
 
2593
      /* Run network hooks */
 
2594
      run_network_hooks("stop", interfaces_hooks != NULL ?
 
2595
                        interfaces_hooks : "", delay);
 
2596
      
 
2597
      /* Take down the network interfaces which were brought up */
 
2598
      {
 
2599
        char *interface = NULL;
 
2600
        while((interface=argz_next(interfaces_to_take_down,
 
2601
                                   interfaces_to_take_down_size,
 
2602
                                   interface))){
 
2603
          ret_errno = take_down_interface(interface);
 
2604
          if(ret_errno != 0){
 
2605
            errno = ret_errno;
 
2606
            perror_plus("Failed to take down interface");
 
2607
          }
 
2608
        }
 
2609
        if(debug and (interfaces_to_take_down == NULL)){
 
2610
          fprintf_plus(stderr, "No interfaces needed to be taken"
 
2611
                       " down\n");
 
2612
        }
 
2613
      }
 
2614
    }
 
2615
    
 
2616
    ret_errno = lower_privileges_permanently();
 
2617
    if(ret_errno != 0){
 
2618
      errno = ret_errno;
 
2619
      perror_plus("Failed to lower privileges permanently");
 
2620
    }
 
2621
  }
 
2622
  
 
2623
  free(interfaces_to_take_down);
 
2624
  free(interfaces_hooks);
 
2625
  
 
2626
  /* Removes the GPGME temp directory and all files inside */
 
2627
  if(tempdir != NULL){
 
2628
    struct dirent **direntries = NULL;
 
2629
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY |
 
2630
                                                  O_NOFOLLOW));
 
2631
    if(tempdir_fd == -1){
 
2632
      perror_plus("open");
 
2633
    } else {
 
2634
#ifdef __GLIBC__
 
2635
#if __GLIBC_PREREQ(2, 15)
 
2636
      int numentries = scandirat(tempdir_fd, ".", &direntries,
 
2637
                                 notdotentries, alphasort);
 
2638
#else  /* not __GLIBC_PREREQ(2, 15) */
 
2639
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2640
                               alphasort);
 
2641
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
2642
#else   /* not __GLIBC__ */
 
2643
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2644
                               alphasort);
 
2645
#endif  /* not __GLIBC__ */
 
2646
      if(numentries >= 0){
 
2647
        for(int i = 0; i < numentries; i++){
 
2648
          ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
 
2649
          if(ret == -1){
 
2650
            fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
 
2651
                         " \"%s\", 0): %s\n", tempdir,
 
2652
                         direntries[i]->d_name, strerror(errno));
 
2653
          }
 
2654
          free(direntries[i]);
 
2655
        }
 
2656
        
 
2657
        /* need to clean even if 0 because man page doesn't specify */
 
2658
        free(direntries);
 
2659
        if(numentries == -1){
 
2660
          perror_plus("scandir");
 
2661
        }
 
2662
        ret = rmdir(tempdir);
 
2663
        if(ret == -1 and errno != ENOENT){
 
2664
          perror_plus("rmdir");
 
2665
        }
 
2666
      }
 
2667
      TEMP_FAILURE_RETRY(close(tempdir_fd));
1690
2668
    }
1691
2669
  }
1692
2670
  
1697
2675
                                            &old_sigterm_action,
1698
2676
                                            NULL));
1699
2677
    if(ret == -1){
1700
 
      perror("sigaction");
 
2678
      perror_plus("sigaction");
1701
2679
    }
1702
2680
    do {
1703
2681
      ret = raise(signal_received);
1704
2682
    } while(ret != 0 and errno == EINTR);
1705
2683
    if(ret != 0){
1706
 
      perror("raise");
 
2684
      perror_plus("raise");
1707
2685
      abort();
1708
2686
    }
1709
2687
    TEMP_FAILURE_RETRY(pause());