/mandos/trunk

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

« back to all changes in this revision

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

  • Committer: Teddy Hogeborn
  • Date: 2014-07-25 22:44:20 UTC
  • mto: This revision was merged to the branch mainline in revision 724.
  • Revision ID: teddy@recompile.se-20140725224420-4a5ct2ptt0hsc92z
Require Python 2.7.

This is in preparation for the eventual move to Python 3, which will
happen as soon as all Python modules required by Mandos are available.
The mandos-ctl and mandos-monitor programs are already portable
between Python 2.6 and Python 3 without changes; this change will
bring the requirement up to Python 2.7.

* INSTALL (Prerequisites/Libraries/Mandos Server): Document
                                                   requirement of
                                                   Python 2.7; remove
                                                   Python-argparse
                                                   which is in the
                                                   Python 2.7 standard
                                                   library.
* debian/control (Source: mandos/Build-Depends-Indep): Depend on
                                                       exactly the
                                                       python2.7
                                                       package and all
                                                       the Python 2.7
                                                       versions of the
                                                       python modules.
  (Package: mandos/Depends): - '' - but still depend on python (<=2.7)
                            and the generic versions of the Python
                            modules; this is for mandos-ctl and
                            mandos-monitor, both of which are
                            compatible with Python 3, and use
                            #!/usr/bin/python.
* mandos: Use #!/usr/bin/python2.7 instead of #!/usr/bin/python.

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-2011 Teddy Hogeborn
13
 
 * Copyright © 2008-2011 Björn Påhlsson
 
12
 * Copyright © 2008-2014 Teddy Hogeborn
 
13
 * Copyright © 2008-2014 Björn Påhlsson
14
14
 * 
15
15
 * This program is free software: you can redistribute it and/or
16
16
 * modify it under the terms of the GNU General Public License as
26
26
 * along with this program.  If not, see
27
27
 * <http://www.gnu.org/licenses/>.
28
28
 * 
29
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
29
 * Contact the authors at <mandos@recompile.se>.
30
30
 */
31
31
 
32
32
/* Needed by GPGME, specifically gpgme_data_seek() */
33
33
#ifndef _LARGEFILE_SOURCE
34
34
#define _LARGEFILE_SOURCE
35
 
#endif
 
35
#endif  /* not _LARGEFILE_SOURCE */
36
36
#ifndef _FILE_OFFSET_BITS
37
37
#define _FILE_OFFSET_BITS 64
38
 
#endif
 
38
#endif  /* not _FILE_OFFSET_BITS */
39
39
 
40
40
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
41
41
 
42
42
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
43
 
                                   stdout, ferror(), remove() */
44
 
#include <stdint.h>             /* uint16_t, uint32_t */
 
43
                                   stdout, ferror() */
 
44
#include <stdint.h>             /* uint16_t, uint32_t, intptr_t */
45
45
#include <stddef.h>             /* NULL, size_t, ssize_t */
46
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
47
47
                                   strtof(), abort() */
53
53
                                   sockaddr_in6, PF_INET6,
54
54
                                   SOCK_STREAM, uid_t, gid_t, open(),
55
55
                                   opendir(), DIR */
56
 
#include <sys/stat.h>           /* open() */
 
56
#include <sys/stat.h>           /* open(), S_ISREG */
57
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
58
 
                                   inet_pton(), connect() */
59
 
#include <fcntl.h>              /* open() */
 
58
                                   inet_pton(), connect(),
 
59
                                   getnameinfo() */
 
60
#include <fcntl.h>              /* open(), unlinkat() */
60
61
#include <dirent.h>             /* opendir(), struct dirent, readdir()
61
62
                                 */
62
63
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
63
64
                                   strtoimax() */
64
 
#include <assert.h>             /* assert() */
65
 
#include <errno.h>              /* perror(), errno */
 
65
#include <errno.h>              /* perror(), errno,
 
66
                                   program_invocation_short_name */
66
67
#include <time.h>               /* nanosleep(), time(), sleep() */
67
68
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
68
69
                                   SIOCSIFFLAGS, if_indextoname(),
72
73
                                */
73
74
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
74
75
                                   getuid(), getgid(), seteuid(),
75
 
                                   setgid(), pause() */
76
 
#include <arpa/inet.h>          /* inet_pton(), htons */
 
76
                                   setgid(), pause(), _exit(),
 
77
                                   unlinkat() */
 
78
#include <arpa/inet.h>          /* inet_pton(), htons() */
77
79
#include <iso646.h>             /* not, or, and */
78
80
#include <argp.h>               /* struct argp_option, error_t, struct
79
81
                                   argp_state, struct argp,
84
86
                                   raise() */
85
87
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
86
88
                                   EX_NOHOST, EX_IOERR, EX_PROTOCOL */
 
89
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
 
90
                                   WEXITSTATUS(), WTERMSIG() */
 
91
#include <grp.h>                /* setgroups() */
 
92
#include <argz.h>               /* argz_add_sep(), argz_next(),
 
93
                                   argz_delete(), argz_append(),
 
94
                                   argz_stringify(), argz_add(),
 
95
                                   argz_count() */
 
96
#include <netdb.h>              /* getnameinfo(), NI_NUMERICHOST,
 
97
                                   EAI_SYSTEM, gai_strerror() */
87
98
 
88
99
#ifdef __linux__
89
100
#include <sys/klog.h>           /* klogctl() */
107
118
                                   init_gnutls_session(),
108
119
                                   GNUTLS_* */
109
120
#include <gnutls/openpgp.h>
110
 
                          /* gnutls_certificate_set_openpgp_key_file(),
111
 
                                   GNUTLS_OPENPGP_FMT_BASE64 */
 
121
                         /* gnutls_certificate_set_openpgp_key_file(),
 
122
                            GNUTLS_OPENPGP_FMT_BASE64 */
112
123
 
113
124
/* GPGME */
114
125
#include <gpgme.h>              /* All GPGME types, constants and
122
133
#define PATHDIR "/conf/conf.d/mandos"
123
134
#define SECKEY "seckey.txt"
124
135
#define PUBKEY "pubkey.txt"
 
136
#define HOOKDIR "/lib/mandos/network-hooks.d"
125
137
 
126
138
bool debug = false;
127
139
static const char mandos_protocol_version[] = "1";
128
140
const char *argp_program_version = "mandos-client " VERSION;
129
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
141
const char *argp_program_bug_address = "<mandos@recompile.se>";
130
142
static const char sys_class_net[] = "/sys/class/net";
131
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;
132
159
 
133
160
/* Used for passing in values through the Avahi callback functions */
134
161
typedef struct {
135
 
  AvahiSimplePoll *simple_poll;
136
162
  AvahiServer *server;
137
163
  gnutls_certificate_credentials_t cred;
138
164
  unsigned int dh_bits;
139
165
  gnutls_dh_params_t dh_params;
140
166
  const char *priority;
141
167
  gpgme_ctx_t ctx;
 
168
  server *current_server;
 
169
  char *interfaces;
 
170
  size_t interfaces_size;
142
171
} mandos_context;
143
172
 
144
 
/* global context so signal handler can reach it*/
145
 
mandos_context mc = { .simple_poll = NULL, .server = NULL,
146
 
                      .dh_bits = 1024, .priority = "SECURE256"
147
 
                      ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
173
/* global so signal handler can reach it*/
 
174
AvahiSimplePoll *simple_poll;
148
175
 
149
176
sig_atomic_t quit_now = 0;
150
177
int signal_received = 0;
151
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
 
152
198
/*
153
199
 * Make additional room in "buffer" for at least BUFFER_SIZE more
154
200
 * bytes. "buffer_capacity" is how much is currently allocated,
155
201
 * "buffer_length" is how much is already used.
156
202
 */
 
203
__attribute__((nonnull, warn_unused_result))
157
204
size_t incbuffer(char **buffer, size_t buffer_length,
158
 
                  size_t buffer_capacity){
 
205
                 size_t buffer_capacity){
159
206
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
160
 
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
161
 
    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;
162
213
      return 0;
163
214
    }
 
215
    *buffer = new_buf;
164
216
    buffer_capacity += BUFFER_SIZE;
165
217
  }
166
218
  return buffer_capacity;
167
219
}
168
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
 
169
269
/* 
170
270
 * Initialize GPGME.
171
271
 */
172
 
static bool init_gpgme(const char *seckey,
173
 
                       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){
174
277
  gpgme_error_t rc;
175
278
  gpgme_engine_info_t engine_info;
176
279
  
177
 
  
178
280
  /*
179
281
   * Helper function to insert pub and seckey to the engine keyring.
180
282
   */
181
 
  bool import_key(const char *filename){
 
283
  bool import_key(const char * const filename){
182
284
    int ret;
183
285
    int fd;
184
286
    gpgme_data_t pgp_data;
185
287
    
186
288
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
187
289
    if(fd == -1){
188
 
      perror("open");
 
290
      perror_plus("open");
189
291
      return false;
190
292
    }
191
293
    
192
294
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
193
295
    if(rc != GPG_ERR_NO_ERROR){
194
 
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
195
 
              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));
196
298
      return false;
197
299
    }
198
300
    
199
 
    rc = gpgme_op_import(mc.ctx, pgp_data);
 
301
    rc = gpgme_op_import(mc->ctx, pgp_data);
200
302
    if(rc != GPG_ERR_NO_ERROR){
201
 
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
202
 
              gpgme_strsource(rc), gpgme_strerror(rc));
 
303
      fprintf_plus(stderr, "bad gpgme_op_import: %s: %s\n",
 
304
                   gpgme_strsource(rc), gpgme_strerror(rc));
203
305
      return false;
204
306
    }
205
307
    
206
308
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
207
309
    if(ret == -1){
208
 
      perror("close");
 
310
      perror_plus("close");
209
311
    }
210
312
    gpgme_data_release(pgp_data);
211
313
    return true;
212
314
  }
213
315
  
214
316
  if(debug){
215
 
    fprintf(stderr, "Initializing GPGME\n");
 
317
    fprintf_plus(stderr, "Initializing GPGME\n");
216
318
  }
217
319
  
218
320
  /* Init GPGME */
219
321
  gpgme_check_version(NULL);
220
322
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
221
323
  if(rc != GPG_ERR_NO_ERROR){
222
 
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
223
 
            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));
224
326
    return false;
225
327
  }
226
328
  
227
 
    /* Set GPGME home directory for the OpenPGP engine only */
 
329
  /* Set GPGME home directory for the OpenPGP engine only */
228
330
  rc = gpgme_get_engine_info(&engine_info);
229
331
  if(rc != GPG_ERR_NO_ERROR){
230
 
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
231
 
            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));
232
334
    return false;
233
335
  }
234
336
  while(engine_info != NULL){
240
342
    engine_info = engine_info->next;
241
343
  }
242
344
  if(engine_info == NULL){
243
 
    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);
244
347
    return false;
245
348
  }
246
349
  
247
350
  /* Create new GPGME "context" */
248
 
  rc = gpgme_new(&(mc.ctx));
 
351
  rc = gpgme_new(&(mc->ctx));
249
352
  if(rc != GPG_ERR_NO_ERROR){
250
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
251
 
            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));
252
356
    return false;
253
357
  }
254
358
  
263
367
 * Decrypt OpenPGP data.
264
368
 * Returns -1 on error
265
369
 */
 
370
__attribute__((nonnull, warn_unused_result))
266
371
static ssize_t pgp_packet_decrypt(const char *cryptotext,
267
372
                                  size_t crypto_size,
268
 
                                  char **plaintext){
 
373
                                  char **plaintext,
 
374
                                  mandos_context *mc){
269
375
  gpgme_data_t dh_crypto, dh_plain;
270
376
  gpgme_error_t rc;
271
377
  ssize_t ret;
273
379
  ssize_t plaintext_length = 0;
274
380
  
275
381
  if(debug){
276
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
382
    fprintf_plus(stderr, "Trying to decrypt OpenPGP data\n");
277
383
  }
278
384
  
279
385
  /* Create new GPGME data buffer from memory cryptotext */
280
386
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
281
387
                               0);
282
388
  if(rc != GPG_ERR_NO_ERROR){
283
 
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
284
 
            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));
285
391
    return -1;
286
392
  }
287
393
  
288
394
  /* Create new empty GPGME data buffer for the plaintext */
289
395
  rc = gpgme_data_new(&dh_plain);
290
396
  if(rc != GPG_ERR_NO_ERROR){
291
 
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
292
 
            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));
293
400
    gpgme_data_release(dh_crypto);
294
401
    return -1;
295
402
  }
296
403
  
297
404
  /* Decrypt data from the cryptotext data buffer to the plaintext
298
405
     data buffer */
299
 
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
406
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
300
407
  if(rc != GPG_ERR_NO_ERROR){
301
 
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
302
 
            gpgme_strsource(rc), gpgme_strerror(rc));
 
408
    fprintf_plus(stderr, "bad gpgme_op_decrypt: %s: %s\n",
 
409
                 gpgme_strsource(rc), gpgme_strerror(rc));
303
410
    plaintext_length = -1;
304
411
    if(debug){
305
412
      gpgme_decrypt_result_t result;
306
 
      result = gpgme_op_decrypt_result(mc.ctx);
 
413
      result = gpgme_op_decrypt_result(mc->ctx);
307
414
      if(result == NULL){
308
 
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
415
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
309
416
      } else {
310
 
        fprintf(stderr, "Unsupported algorithm: %s\n",
311
 
                result->unsupported_algorithm);
312
 
        fprintf(stderr, "Wrong key usage: %u\n",
313
 
                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);
314
421
        if(result->file_name != NULL){
315
 
          fprintf(stderr, "File name: %s\n", result->file_name);
 
422
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
316
423
        }
317
424
        gpgme_recipient_t recipient;
318
425
        recipient = result->recipients;
319
426
        while(recipient != NULL){
320
 
          fprintf(stderr, "Public key algorithm: %s\n",
321
 
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
322
 
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
323
 
          fprintf(stderr, "Secret key available: %s\n",
324
 
                  recipient->status == GPG_ERR_NO_SECKEY
325
 
                  ? "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");
326
434
          recipient = recipient->next;
327
435
        }
328
436
      }
331
439
  }
332
440
  
333
441
  if(debug){
334
 
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
 
442
    fprintf_plus(stderr, "Decryption of OpenPGP data succeeded\n");
335
443
  }
336
444
  
337
445
  /* Seek back to the beginning of the GPGME plaintext data buffer */
338
446
  if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
339
 
    perror("gpgme_data_seek");
 
447
    perror_plus("gpgme_data_seek");
340
448
    plaintext_length = -1;
341
449
    goto decrypt_end;
342
450
  }
344
452
  *plaintext = NULL;
345
453
  while(true){
346
454
    plaintext_capacity = incbuffer(plaintext,
347
 
                                      (size_t)plaintext_length,
348
 
                                      plaintext_capacity);
 
455
                                   (size_t)plaintext_length,
 
456
                                   plaintext_capacity);
349
457
    if(plaintext_capacity == 0){
350
 
        perror("incbuffer");
351
 
        plaintext_length = -1;
352
 
        goto decrypt_end;
 
458
      perror_plus("incbuffer");
 
459
      plaintext_length = -1;
 
460
      goto decrypt_end;
353
461
    }
354
462
    
355
463
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
360
468
      break;
361
469
    }
362
470
    if(ret < 0){
363
 
      perror("gpgme_data_read");
 
471
      perror_plus("gpgme_data_read");
364
472
      plaintext_length = -1;
365
473
      goto decrypt_end;
366
474
    }
368
476
  }
369
477
  
370
478
  if(debug){
371
 
    fprintf(stderr, "Decrypted password is: ");
 
479
    fprintf_plus(stderr, "Decrypted password is: ");
372
480
    for(ssize_t i = 0; i < plaintext_length; i++){
373
481
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
374
482
    }
385
493
  return plaintext_length;
386
494
}
387
495
 
388
 
static const char * safer_gnutls_strerror(int value){
389
 
  const char *ret = gnutls_strerror(value); /* Spurious warning from
390
 
                                               -Wunreachable-code */
 
496
__attribute__((warn_unused_result))
 
497
static const char *safer_gnutls_strerror(int value){
 
498
  const char *ret = gnutls_strerror(value);
391
499
  if(ret == NULL)
392
500
    ret = "(unknown)";
393
501
  return ret;
394
502
}
395
503
 
396
504
/* GnuTLS log function callback */
 
505
__attribute__((nonnull))
397
506
static void debuggnutls(__attribute__((unused)) int level,
398
507
                        const char* string){
399
 
  fprintf(stderr, "GnuTLS: %s", string);
 
508
  fprintf_plus(stderr, "GnuTLS: %s", string);
400
509
}
401
510
 
 
511
__attribute__((nonnull, warn_unused_result))
402
512
static int init_gnutls_global(const char *pubkeyfilename,
403
 
                              const char *seckeyfilename){
 
513
                              const char *seckeyfilename,
 
514
                              mandos_context *mc){
404
515
  int ret;
405
516
  
406
517
  if(debug){
407
 
    fprintf(stderr, "Initializing GnuTLS\n");
 
518
    fprintf_plus(stderr, "Initializing GnuTLS\n");
408
519
  }
409
520
  
410
521
  ret = gnutls_global_init();
411
522
  if(ret != GNUTLS_E_SUCCESS){
412
 
    fprintf(stderr, "GnuTLS global_init: %s\n",
413
 
            safer_gnutls_strerror(ret));
 
523
    fprintf_plus(stderr, "GnuTLS global_init: %s\n",
 
524
                 safer_gnutls_strerror(ret));
414
525
    return -1;
415
526
  }
416
527
  
423
534
  }
424
535
  
425
536
  /* OpenPGP credentials */
426
 
  gnutls_certificate_allocate_credentials(&mc.cred);
 
537
  ret = gnutls_certificate_allocate_credentials(&mc->cred);
427
538
  if(ret != GNUTLS_E_SUCCESS){
428
 
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
429
 
                                                    from
430
 
                                                    -Wunreachable-code
431
 
                                                 */
432
 
            safer_gnutls_strerror(ret));
 
539
    fprintf_plus(stderr, "GnuTLS memory error: %s\n",
 
540
                 safer_gnutls_strerror(ret));
433
541
    gnutls_global_deinit();
434
542
    return -1;
435
543
  }
436
544
  
437
545
  if(debug){
438
 
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
439
 
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
440
 
            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);
441
550
  }
442
551
  
443
552
  ret = gnutls_certificate_set_openpgp_key_file
444
 
    (mc.cred, pubkeyfilename, seckeyfilename,
 
553
    (mc->cred, pubkeyfilename, seckeyfilename,
445
554
     GNUTLS_OPENPGP_FMT_BASE64);
446
555
  if(ret != GNUTLS_E_SUCCESS){
447
 
    fprintf(stderr,
448
 
            "Error[%d] while reading the OpenPGP key pair ('%s',"
449
 
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
450
 
    fprintf(stderr, "The GnuTLS error is: %s\n",
451
 
            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));
452
561
    goto globalfail;
453
562
  }
454
563
  
455
564
  /* GnuTLS server initialization */
456
 
  ret = gnutls_dh_params_init(&mc.dh_params);
 
565
  ret = gnutls_dh_params_init(&mc->dh_params);
457
566
  if(ret != GNUTLS_E_SUCCESS){
458
 
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
459
 
            " %s\n", safer_gnutls_strerror(ret));
 
567
    fprintf_plus(stderr, "Error in GnuTLS DH parameter"
 
568
                 " initialization: %s\n",
 
569
                 safer_gnutls_strerror(ret));
460
570
    goto globalfail;
461
571
  }
462
 
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
572
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
463
573
  if(ret != GNUTLS_E_SUCCESS){
464
 
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
465
 
            safer_gnutls_strerror(ret));
 
574
    fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
 
575
                 safer_gnutls_strerror(ret));
466
576
    goto globalfail;
467
577
  }
468
578
  
469
 
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
579
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
470
580
  
471
581
  return 0;
472
582
  
473
583
 globalfail:
474
584
  
475
 
  gnutls_certificate_free_credentials(mc.cred);
 
585
  gnutls_certificate_free_credentials(mc->cred);
476
586
  gnutls_global_deinit();
477
 
  gnutls_dh_params_deinit(mc.dh_params);
 
587
  gnutls_dh_params_deinit(mc->dh_params);
478
588
  return -1;
479
589
}
480
590
 
481
 
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){
482
594
  int ret;
483
595
  /* GnuTLS session creation */
484
596
  do {
488
600
    }
489
601
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
490
602
  if(ret != GNUTLS_E_SUCCESS){
491
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
492
 
            safer_gnutls_strerror(ret));
 
603
    fprintf_plus(stderr,
 
604
                 "Error in GnuTLS session initialization: %s\n",
 
605
                 safer_gnutls_strerror(ret));
493
606
  }
494
607
  
495
608
  {
496
609
    const char *err;
497
610
    do {
498
 
      ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
611
      ret = gnutls_priority_set_direct(*session, mc->priority, &err);
499
612
      if(quit_now){
500
613
        gnutls_deinit(*session);
501
614
        return -1;
502
615
      }
503
616
    } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
504
617
    if(ret != GNUTLS_E_SUCCESS){
505
 
      fprintf(stderr, "Syntax error at: %s\n", err);
506
 
      fprintf(stderr, "GnuTLS error: %s\n",
507
 
              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));
508
621
      gnutls_deinit(*session);
509
622
      return -1;
510
623
    }
512
625
  
513
626
  do {
514
627
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
515
 
                                 mc.cred);
 
628
                                 mc->cred);
516
629
    if(quit_now){
517
630
      gnutls_deinit(*session);
518
631
      return -1;
519
632
    }
520
633
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
521
634
  if(ret != GNUTLS_E_SUCCESS){
522
 
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
523
 
            safer_gnutls_strerror(ret));
 
635
    fprintf_plus(stderr, "Error setting GnuTLS credentials: %s\n",
 
636
                 safer_gnutls_strerror(ret));
524
637
    gnutls_deinit(*session);
525
638
    return -1;
526
639
  }
528
641
  /* ignore client certificate if any. */
529
642
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
530
643
  
531
 
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
 
644
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
532
645
  
533
646
  return 0;
534
647
}
538
651
                      __attribute__((unused)) const char *txt){}
539
652
 
540
653
/* Called when a Mandos server is found */
541
 
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,
542
656
                                      AvahiIfIndex if_index,
543
 
                                      int af){
 
657
                                      int af, mandos_context *mc){
544
658
  int ret, tcp_sd = -1;
545
659
  ssize_t sret;
546
 
  union {
547
 
    struct sockaddr_in in;
548
 
    struct sockaddr_in6 in6;
549
 
  } to;
 
660
  struct sockaddr_storage to;
550
661
  char *buffer = NULL;
551
662
  char *decrypted_buffer = NULL;
552
663
  size_t buffer_length = 0;
571
682
    pf = PF_INET;
572
683
    break;
573
684
  default:
574
 
    fprintf(stderr, "Bad address family: %d\n", af);
 
685
    fprintf_plus(stderr, "Bad address family: %d\n", af);
575
686
    errno = EINVAL;
576
687
    return -1;
577
688
  }
578
689
  
579
 
  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);
580
723
  if(ret != 0){
581
724
    return -1;
582
725
  }
583
726
  
584
727
  if(debug){
585
 
    fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
586
 
            "\n", ip, port);
 
728
    fprintf_plus(stderr, "Setting up a TCP connection to %s, port %"
 
729
                 PRIuMAX "\n", ip, (uintmax_t)port);
587
730
  }
588
731
  
589
732
  tcp_sd = socket(pf, SOCK_STREAM, 0);
590
733
  if(tcp_sd < 0){
591
734
    int e = errno;
592
 
    perror("socket");
 
735
    perror_plus("socket");
593
736
    errno = e;
594
737
    goto mandos_end;
595
738
  }
601
744
  
602
745
  memset(&to, 0, sizeof(to));
603
746
  if(af == AF_INET6){
604
 
    to.in6.sin6_family = (sa_family_t)af;
605
 
    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);
606
749
  } else {                      /* IPv4 */
607
 
    to.in.sin_family = (sa_family_t)af;
608
 
    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);
609
752
  }
610
753
  if(ret < 0 ){
611
754
    int e = errno;
612
 
    perror("inet_pton");
 
755
    perror_plus("inet_pton");
613
756
    errno = e;
614
757
    goto mandos_end;
615
758
  }
616
759
  if(ret == 0){
617
760
    int e = errno;
618
 
    fprintf(stderr, "Bad address: %s\n", ip);
 
761
    fprintf_plus(stderr, "Bad address: %s\n", ip);
619
762
    errno = e;
620
763
    goto mandos_end;
621
764
  }
622
765
  if(af == AF_INET6){
623
 
    to.in6.sin6_port = htons(port); /* Spurious warnings from
624
 
                                       -Wconversion and
625
 
                                       -Wunreachable-code */
626
 
    
627
 
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
628
 
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
629
 
                              -Wunreachable-code*/
 
766
    ((struct sockaddr_in6 *)&to)->sin6_port = htons(port);
 
767
    if(IN6_IS_ADDR_LINKLOCAL
 
768
       (&((struct sockaddr_in6 *)&to)->sin6_addr)){
630
769
      if(if_index == AVAHI_IF_UNSPEC){
631
 
        fprintf(stderr, "An IPv6 link-local address is incomplete"
632
 
                " without a network interface\n");
 
770
        fprintf_plus(stderr, "An IPv6 link-local address is"
 
771
                     " incomplete without a network interface\n");
633
772
        errno = EINVAL;
634
773
        goto mandos_end;
635
774
      }
636
775
      /* Set the network interface number as scope */
637
 
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
776
      ((struct sockaddr_in6 *)&to)->sin6_scope_id = (uint32_t)if_index;
638
777
    }
639
778
  } else {
640
 
    to.in.sin_port = htons(port); /* Spurious warnings from
641
 
                                     -Wconversion and
642
 
                                     -Wunreachable-code */
 
779
    ((struct sockaddr_in *)&to)->sin_port = htons(port);
643
780
  }
644
781
  
645
782
  if(quit_now){
651
788
    if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
652
789
      char interface[IF_NAMESIZE];
653
790
      if(if_indextoname((unsigned int)if_index, interface) == NULL){
654
 
        perror("if_indextoname");
 
791
        perror_plus("if_indextoname");
655
792
      } else {
656
 
        fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
657
 
                ip, interface, port);
 
793
        fprintf_plus(stderr, "Connection to: %s%%%s, port %" PRIuMAX
 
794
                     "\n", ip, interface, (uintmax_t)port);
658
795
      }
659
796
    } else {
660
 
      fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
661
 
              port);
 
797
      fprintf_plus(stderr, "Connection to: %s, port %" PRIuMAX "\n",
 
798
                   ip, (uintmax_t)port);
662
799
    }
663
800
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
664
801
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
665
 
    const char *pcret;
666
802
    if(af == AF_INET6){
667
 
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
668
 
                        sizeof(addrstr));
 
803
      ret = getnameinfo((struct sockaddr *)&to,
 
804
                        sizeof(struct sockaddr_in6),
 
805
                        addrstr, sizeof(addrstr), NULL, 0,
 
806
                        NI_NUMERICHOST);
669
807
    } else {
670
 
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
671
 
                        sizeof(addrstr));
 
808
      ret = getnameinfo((struct sockaddr *)&to,
 
809
                        sizeof(struct sockaddr_in),
 
810
                        addrstr, sizeof(addrstr), NULL, 0,
 
811
                        NI_NUMERICHOST);
672
812
    }
673
 
    if(pcret == NULL){
674
 
      perror("inet_ntop");
675
 
    } else {
676
 
      if(strcmp(addrstr, ip) != 0){
677
 
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
678
 
      }
 
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);
679
819
    }
680
820
  }
681
821
  
685
825
  }
686
826
  
687
827
  if(af == AF_INET6){
688
 
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
828
    ret = connect(tcp_sd, (struct sockaddr *)&to,
 
829
                  sizeof(struct sockaddr_in6));
689
830
  } else {
690
 
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
831
    ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
832
                  sizeof(struct sockaddr_in));
691
833
  }
692
834
  if(ret < 0){
693
 
    if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
835
    if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
694
836
      int e = errno;
695
 
      perror("connect");
 
837
      perror_plus("connect");
696
838
      errno = e;
697
839
    }
698
840
    goto mandos_end;
708
850
  while(true){
709
851
    size_t out_size = strlen(out);
710
852
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
711
 
                                   out_size - written));
 
853
                                        out_size - written));
712
854
    if(ret == -1){
713
855
      int e = errno;
714
 
      perror("write");
 
856
      perror_plus("write");
715
857
      errno = e;
716
858
      goto mandos_end;
717
859
    }
734
876
  }
735
877
  
736
878
  if(debug){
737
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
879
    fprintf_plus(stderr, "Establishing TLS session with %s\n", ip);
738
880
  }
739
881
  
740
882
  if(quit_now){
742
884
    goto mandos_end;
743
885
  }
744
886
  
745
 
  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);
746
892
  
747
893
  if(quit_now){
748
894
    errno = EINTR;
759
905
  
760
906
  if(ret != GNUTLS_E_SUCCESS){
761
907
    if(debug){
762
 
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
908
      fprintf_plus(stderr, "*** GnuTLS Handshake failed ***\n");
763
909
      gnutls_perror(ret);
764
910
    }
765
911
    errno = EPROTO;
769
915
  /* Read OpenPGP packet that contains the wanted password */
770
916
  
771
917
  if(debug){
772
 
    fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
773
 
            ip);
 
918
    fprintf_plus(stderr, "Retrieving OpenPGP encrypted password from"
 
919
                 " %s\n", ip);
774
920
  }
775
921
  
776
922
  while(true){
781
927
    }
782
928
    
783
929
    buffer_capacity = incbuffer(&buffer, buffer_length,
784
 
                                   buffer_capacity);
 
930
                                buffer_capacity);
785
931
    if(buffer_capacity == 0){
786
932
      int e = errno;
787
 
      perror("incbuffer");
 
933
      perror_plus("incbuffer");
788
934
      errno = e;
789
935
      goto mandos_end;
790
936
    }
814
960
          }
815
961
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
816
962
        if(ret < 0){
817
 
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
963
          fprintf_plus(stderr, "*** GnuTLS Re-handshake failed "
 
964
                       "***\n");
818
965
          gnutls_perror(ret);
819
966
          errno = EPROTO;
820
967
          goto mandos_end;
821
968
        }
822
969
        break;
823
970
      default:
824
 
        fprintf(stderr, "Unknown error while reading data from"
825
 
                " encrypted session with Mandos server\n");
 
971
        fprintf_plus(stderr, "Unknown error while reading data from"
 
972
                     " encrypted session with Mandos server\n");
826
973
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
827
974
        errno = EIO;
828
975
        goto mandos_end;
833
980
  }
834
981
  
835
982
  if(debug){
836
 
    fprintf(stderr, "Closing TLS session\n");
 
983
    fprintf_plus(stderr, "Closing TLS session\n");
837
984
  }
838
985
  
839
986
  if(quit_now){
851
998
  
852
999
  if(buffer_length > 0){
853
1000
    ssize_t decrypted_buffer_size;
854
 
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
855
 
                                               buffer_length,
856
 
                                               &decrypted_buffer);
 
1001
    decrypted_buffer_size = pgp_packet_decrypt(buffer, buffer_length,
 
1002
                                               &decrypted_buffer, mc);
857
1003
    if(decrypted_buffer_size >= 0){
858
1004
      
859
1005
      written = 0;
869
1015
        if(ret == 0 and ferror(stdout)){
870
1016
          int e = errno;
871
1017
          if(debug){
872
 
            fprintf(stderr, "Error writing encrypted data: %s\n",
873
 
                    strerror(errno));
 
1018
            fprintf_plus(stderr, "Error writing encrypted data: %s\n",
 
1019
                         strerror(errno));
874
1020
          }
875
1021
          errno = e;
876
1022
          goto mandos_end;
895
1041
      if(e == 0){
896
1042
        e = errno;
897
1043
      }
898
 
      perror("close");
 
1044
      perror_plus("close");
899
1045
    }
900
1046
    gnutls_deinit(session);
 
1047
    errno = e;
901
1048
    if(quit_now){
902
 
      e = EINTR;
 
1049
      errno = EINTR;
903
1050
      retval = -1;
904
1051
    }
905
 
    errno = e;
906
1052
  }
907
1053
  return retval;
908
1054
}
909
1055
 
 
1056
__attribute__((nonnull))
910
1057
static void resolve_callback(AvahiSServiceResolver *r,
911
1058
                             AvahiIfIndex interface,
912
1059
                             AvahiProtocol proto,
920
1067
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
921
1068
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
922
1069
                             flags,
923
 
                             AVAHI_GCC_UNUSED void* userdata){
924
 
  assert(r);
 
1070
                             void *mc){
 
1071
  if(r == NULL){
 
1072
    return;
 
1073
  }
925
1074
  
926
1075
  /* Called whenever a service has been resolved successfully or
927
1076
     timed out */
928
1077
  
929
1078
  if(quit_now){
 
1079
    avahi_s_service_resolver_free(r);
930
1080
    return;
931
1081
  }
932
1082
  
933
1083
  switch(event){
934
1084
  default:
935
1085
  case AVAHI_RESOLVER_FAILURE:
936
 
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
937
 
            " of type '%s' in domain '%s': %s\n", name, type, domain,
938
 
            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)));
939
1091
    break;
940
1092
    
941
1093
  case AVAHI_RESOLVER_FOUND:
943
1095
      char ip[AVAHI_ADDRESS_STR_MAX];
944
1096
      avahi_address_snprint(ip, sizeof(ip), address);
945
1097
      if(debug){
946
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
947
 
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
948
 
                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);
949
1101
      }
950
 
      int ret = start_mandos_communication(ip, port, interface,
951
 
                                           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);
952
1106
      if(ret == 0){
953
 
        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
        }
954
1115
      }
955
1116
    }
956
1117
  }
966
1127
                            const char *domain,
967
1128
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
968
1129
                            flags,
969
 
                            AVAHI_GCC_UNUSED void* userdata){
970
 
  assert(b);
 
1130
                            void *mc){
 
1131
  if(b == NULL){
 
1132
    return;
 
1133
  }
971
1134
  
972
1135
  /* Called whenever a new services becomes available on the LAN or
973
1136
     is removed from the LAN */
980
1143
  default:
981
1144
  case AVAHI_BROWSER_FAILURE:
982
1145
    
983
 
    fprintf(stderr, "(Avahi browser) %s\n",
984
 
            avahi_strerror(avahi_server_errno(mc.server)));
985
 
    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);
986
1150
    return;
987
1151
    
988
1152
  case AVAHI_BROWSER_NEW:
991
1155
       the callback function is called the Avahi server will free the
992
1156
       resolver for us. */
993
1157
    
994
 
    if(avahi_s_service_resolver_new(mc.server, interface, protocol,
995
 
                                    name, type, domain, protocol, 0,
996
 
                                    resolve_callback, NULL) == NULL)
997
 
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
998
 
              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)));
999
1166
    break;
1000
1167
    
1001
1168
  case AVAHI_BROWSER_REMOVE:
1004
1171
  case AVAHI_BROWSER_ALL_FOR_NOW:
1005
1172
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
1006
1173
    if(debug){
1007
 
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
1174
      fprintf_plus(stderr, "No Mandos server found, still"
 
1175
                   " searching...\n");
1008
1176
    }
1009
1177
    break;
1010
1178
  }
1011
1179
}
1012
1180
 
1013
 
/* stop main loop after sigterm has been called */
 
1181
/* Signal handler that stops main loop after SIGTERM */
1014
1182
static void handle_sigterm(int sig){
1015
1183
  if(quit_now){
1016
1184
    return;
1018
1186
  quit_now = 1;
1019
1187
  signal_received = sig;
1020
1188
  int old_errno = errno;
1021
 
  if(mc.simple_poll != NULL){
1022
 
    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);
1023
1192
  }
1024
1193
  errno = old_errno;
1025
1194
}
1026
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
 
1027
1264
/* 
1028
1265
 * This function determines if a directory entry in /sys/class/net
1029
1266
 * corresponds to an acceptable network device.
1030
1267
 * (This function is passed to scandir(3) as a filter function.)
1031
1268
 */
 
1269
__attribute__((nonnull, warn_unused_result))
1032
1270
int good_interface(const struct dirent *if_entry){
1033
 
  ssize_t ssret;
1034
 
  char *flagname = NULL;
1035
1271
  if(if_entry->d_name[0] == '.'){
1036
1272
    return 0;
1037
1273
  }
1038
 
  int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1039
 
                     if_entry->d_name);
1040
 
  if(ret < 0){
1041
 
    perror("asprintf");
1042
 
    return 0;
1043
 
  }
1044
 
  int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1045
 
  if(flags_fd == -1){
1046
 
    perror("open");
1047
 
    free(flagname);
1048
 
    return 0;
1049
 
  }
1050
 
  free(flagname);
1051
 
  typedef short ifreq_flags;    /* ifreq.ifr_flags in netdevice(7) */
1052
 
  /* read line from flags_fd */
1053
 
  ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1054
 
  char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1055
 
  flagstring[(size_t)to_read] = '\0';
1056
 
  if(flagstring == NULL){
1057
 
    perror("malloc");
1058
 
    close(flags_fd);
1059
 
    return 0;
1060
 
  }
1061
 
  while(to_read > 0){
1062
 
    ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1063
 
                                             (size_t)to_read));
1064
 
    if(ssret == -1){
1065
 
      perror("read");
1066
 
      free(flagstring);
1067
 
      close(flags_fd);
1068
 
      return 0;
1069
 
    }
1070
 
    to_read -= ssret;
1071
 
    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
      int status;
 
1654
      if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
 
1655
        perror_plus("waitpid");
 
1656
        free(direntry);
 
1657
        continue;
 
1658
      }
 
1659
      if(WIFEXITED(status)){
 
1660
        if(WEXITSTATUS(status) != 0){
 
1661
          fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
 
1662
                       " with status %d\n", direntry->d_name,
 
1663
                       WEXITSTATUS(status));
 
1664
          free(direntry);
 
1665
          continue;
 
1666
        }
 
1667
      } else if(WIFSIGNALED(status)){
 
1668
        fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
 
1669
                     " signal %d\n", direntry->d_name,
 
1670
                     WTERMSIG(status));
 
1671
        free(direntry);
 
1672
        continue;
 
1673
      } else {
 
1674
        fprintf_plus(stderr, "Warning: network hook \"%s\""
 
1675
                     " crashed\n", direntry->d_name);
 
1676
        free(direntry);
 
1677
        continue;
 
1678
      }
 
1679
    }
 
1680
    if(debug){
 
1681
      fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
 
1682
                   direntry->d_name);
 
1683
    }
 
1684
    free(direntry);
 
1685
  }
 
1686
  free(direntries);
 
1687
  if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
 
1688
    perror_plus("close");
 
1689
  } else {
 
1690
    hookdir_fd = -1;
 
1691
  }
 
1692
  close(devnull);
 
1693
}
 
1694
 
 
1695
__attribute__((nonnull, warn_unused_result))
 
1696
error_t bring_up_interface(const char *const interface,
 
1697
                           const float delay){
 
1698
  error_t old_errno = errno;
 
1699
  int ret;
 
1700
  struct ifreq network;
 
1701
  unsigned int if_index = if_nametoindex(interface);
 
1702
  if(if_index == 0){
 
1703
    fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
 
1704
    errno = old_errno;
 
1705
    return ENXIO;
 
1706
  }
 
1707
  
 
1708
  if(quit_now){
 
1709
    errno = old_errno;
 
1710
    return EINTR;
 
1711
  }
 
1712
  
 
1713
  if(not interface_is_up(interface)){
 
1714
    error_t ret_errno = 0, ioctl_errno = 0;
 
1715
    if(not get_flags(interface, &network)){
 
1716
      ret_errno = errno;
 
1717
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1718
                   "\"%s\"\n", interface);
 
1719
      errno = old_errno;
 
1720
      return ret_errno;
 
1721
    }
 
1722
    network.ifr_flags |= IFF_UP; /* set flag */
 
1723
    
 
1724
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1725
    if(sd == -1){
 
1726
      ret_errno = errno;
 
1727
      perror_plus("socket");
 
1728
      errno = old_errno;
 
1729
      return ret_errno;
 
1730
    }
 
1731
    
 
1732
    if(quit_now){
 
1733
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1734
      if(ret == -1){
 
1735
        perror_plus("close");
 
1736
      }
 
1737
      errno = old_errno;
 
1738
      return EINTR;
 
1739
    }
 
1740
    
 
1741
    if(debug){
 
1742
      fprintf_plus(stderr, "Bringing up interface \"%s\"\n",
 
1743
                   interface);
 
1744
    }
 
1745
    
 
1746
    /* Raise privileges */
 
1747
    ret_errno = raise_privileges();
 
1748
    if(ret_errno != 0){
 
1749
      errno = ret_errno;
 
1750
      perror_plus("Failed to raise privileges");
 
1751
    }
 
1752
    
 
1753
#ifdef __linux__
 
1754
    int ret_linux;
 
1755
    bool restore_loglevel = false;
 
1756
    if(ret_errno == 0){
 
1757
      /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1758
         messages about the network interface to mess up the prompt */
 
1759
      ret_linux = klogctl(8, NULL, 5);
 
1760
      if(ret_linux == -1){
 
1761
        perror_plus("klogctl");
 
1762
      } else {
 
1763
        restore_loglevel = true;
 
1764
      }
 
1765
    }
 
1766
#endif  /* __linux__ */
 
1767
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1768
    ioctl_errno = errno;
 
1769
#ifdef __linux__
 
1770
    if(restore_loglevel){
 
1771
      ret_linux = klogctl(7, NULL, 0);
 
1772
      if(ret_linux == -1){
 
1773
        perror_plus("klogctl");
 
1774
      }
 
1775
    }
 
1776
#endif  /* __linux__ */
 
1777
    
 
1778
    /* If raise_privileges() succeeded above */
 
1779
    if(ret_errno == 0){
 
1780
      /* Lower privileges */
 
1781
      ret_errno = lower_privileges();
 
1782
      if(ret_errno != 0){
 
1783
        errno = ret_errno;
 
1784
        perror_plus("Failed to lower privileges");
 
1785
      }
 
1786
    }
 
1787
    
 
1788
    /* Close the socket */
 
1789
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1790
    if(ret == -1){
 
1791
      perror_plus("close");
 
1792
    }
 
1793
    
 
1794
    if(ret_setflags == -1){
 
1795
      errno = ioctl_errno;
 
1796
      perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
 
1797
      errno = old_errno;
 
1798
      return ioctl_errno;
 
1799
    }
 
1800
  } else if(debug){
 
1801
    fprintf_plus(stderr, "Interface \"%s\" is already up; good\n",
 
1802
                 interface);
 
1803
  }
 
1804
  
 
1805
  /* Sleep checking until interface is running.
 
1806
     Check every 0.25s, up to total time of delay */
 
1807
  for(int i=0; i < delay * 4; i++){
 
1808
    if(interface_is_running(interface)){
1072
1809
      break;
1073
1810
    }
1074
 
  }
1075
 
  close(flags_fd);
1076
 
  intmax_t tmpmax;
1077
 
  char *tmp;
1078
 
  errno = 0;
1079
 
  tmpmax = strtoimax(flagstring, &tmp, 0);
1080
 
  if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1081
 
                                         and not (isspace(*tmp)))
1082
 
     or tmpmax != (ifreq_flags)tmpmax){
1083
 
    if(debug){
1084
 
      fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1085
 
              flagstring, if_entry->d_name);
1086
 
    }
1087
 
    free(flagstring);
1088
 
    return 0;
1089
 
  }
1090
 
  free(flagstring);
1091
 
  ifreq_flags flags = (ifreq_flags)tmpmax;
1092
 
  /* Reject the loopback device */
1093
 
  if(flags & IFF_LOOPBACK){
1094
 
    if(debug){
1095
 
      fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1096
 
              if_entry->d_name);
1097
 
    }
1098
 
    return 0;
1099
 
  }
1100
 
  /* Accept point-to-point devices only if connect_to is specified */
1101
 
  if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1102
 
    if(debug){
1103
 
      fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1104
 
              if_entry->d_name);
1105
 
    }
1106
 
    return 1;
1107
 
  }
1108
 
  /* Otherwise, reject non-broadcast-capable devices */
1109
 
  if(not (flags & IFF_BROADCAST)){
1110
 
    if(debug){
1111
 
      fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1112
 
              if_entry->d_name);
1113
 
    }
1114
 
    return 0;
1115
 
  }
1116
 
  /* Accept this device */
1117
 
  if(debug){
1118
 
    fprintf(stderr, "Interface \"%s\" is acceptable\n",
1119
 
            if_entry->d_name);
1120
 
  }
1121
 
  return 1;
 
1811
    struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1812
    ret = nanosleep(&sleeptime, NULL);
 
1813
    if(ret == -1 and errno != EINTR){
 
1814
      perror_plus("nanosleep");
 
1815
    }
 
1816
  }
 
1817
  
 
1818
  errno = old_errno;
 
1819
  return 0;
 
1820
}
 
1821
 
 
1822
__attribute__((nonnull, warn_unused_result))
 
1823
error_t take_down_interface(const char *const interface){
 
1824
  error_t old_errno = errno;
 
1825
  struct ifreq network;
 
1826
  unsigned int if_index = if_nametoindex(interface);
 
1827
  if(if_index == 0){
 
1828
    fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
 
1829
    errno = old_errno;
 
1830
    return ENXIO;
 
1831
  }
 
1832
  if(interface_is_up(interface)){
 
1833
    error_t ret_errno = 0, ioctl_errno = 0;
 
1834
    if(not get_flags(interface, &network) and debug){
 
1835
      ret_errno = errno;
 
1836
      fprintf_plus(stderr, "Failed to get flags for interface "
 
1837
                   "\"%s\"\n", interface);
 
1838
      errno = old_errno;
 
1839
      return ret_errno;
 
1840
    }
 
1841
    network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
 
1842
    
 
1843
    int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1844
    if(sd == -1){
 
1845
      ret_errno = errno;
 
1846
      perror_plus("socket");
 
1847
      errno = old_errno;
 
1848
      return ret_errno;
 
1849
    }
 
1850
    
 
1851
    if(debug){
 
1852
      fprintf_plus(stderr, "Taking down interface \"%s\"\n",
 
1853
                   interface);
 
1854
    }
 
1855
    
 
1856
    /* Raise privileges */
 
1857
    ret_errno = raise_privileges();
 
1858
    if(ret_errno != 0){
 
1859
      errno = ret_errno;
 
1860
      perror_plus("Failed to raise privileges");
 
1861
    }
 
1862
    
 
1863
    int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
 
1864
    ioctl_errno = errno;
 
1865
    
 
1866
    /* If raise_privileges() succeeded above */
 
1867
    if(ret_errno == 0){
 
1868
      /* Lower privileges */
 
1869
      ret_errno = lower_privileges();
 
1870
      if(ret_errno != 0){
 
1871
        errno = ret_errno;
 
1872
        perror_plus("Failed to lower privileges");
 
1873
      }
 
1874
    }
 
1875
    
 
1876
    /* Close the socket */
 
1877
    int ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1878
    if(ret == -1){
 
1879
      perror_plus("close");
 
1880
    }
 
1881
    
 
1882
    if(ret_setflags == -1){
 
1883
      errno = ioctl_errno;
 
1884
      perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
 
1885
      errno = old_errno;
 
1886
      return ioctl_errno;
 
1887
    }
 
1888
  } else if(debug){
 
1889
    fprintf_plus(stderr, "Interface \"%s\" is already down; odd\n",
 
1890
                 interface);
 
1891
  }
 
1892
  
 
1893
  errno = old_errno;
 
1894
  return 0;
1122
1895
}
1123
1896
 
1124
1897
int main(int argc, char *argv[]){
 
1898
  mandos_context mc = { .server = NULL, .dh_bits = 1024,
 
1899
                        .priority = "SECURE256:!CTYPE-X.509:"
 
1900
                        "+CTYPE-OPENPGP", .current_server = NULL,
 
1901
                        .interfaces = NULL, .interfaces_size = 0 };
1125
1902
  AvahiSServiceBrowser *sb = NULL;
1126
 
  int error;
 
1903
  error_t ret_errno;
1127
1904
  int ret;
1128
1905
  intmax_t tmpmax;
1129
1906
  char *tmp;
1130
1907
  int exitcode = EXIT_SUCCESS;
1131
 
  const char *interface = "";
1132
 
  struct ifreq network;
1133
 
  int sd = -1;
1134
 
  bool take_down_interface = false;
1135
 
  uid_t uid;
1136
 
  gid_t gid;
1137
 
  char tempdir[] = "/tmp/mandosXXXXXX";
1138
 
  bool tempdir_created = false;
 
1908
  char *interfaces_to_take_down = NULL;
 
1909
  size_t interfaces_to_take_down_size = 0;
 
1910
  char run_tempdir[] = "/run/tmp/mandosXXXXXX";
 
1911
  char old_tempdir[] = "/tmp/mandosXXXXXX";
 
1912
  char *tempdir = NULL;
1139
1913
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1140
1914
  const char *seckey = PATHDIR "/" SECKEY;
1141
1915
  const char *pubkey = PATHDIR "/" PUBKEY;
 
1916
  char *interfaces_hooks = NULL;
1142
1917
  
1143
1918
  bool gnutls_initialized = false;
1144
1919
  bool gpgme_initialized = false;
1145
1920
  float delay = 2.5f;
 
1921
  double retry_interval = 10; /* 10s between trying a server and
 
1922
                                 retrying the same server again */
1146
1923
  
1147
1924
  struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1148
1925
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1154
1931
  errno = 0;
1155
1932
  ret = setgid(gid);
1156
1933
  if(ret == -1){
1157
 
    perror("setgid");
 
1934
    perror_plus("setgid");
1158
1935
  }
1159
1936
  
1160
1937
  /* Lower user privileges (temporarily) */
1161
1938
  errno = 0;
1162
1939
  ret = seteuid(uid);
1163
1940
  if(ret == -1){
1164
 
    perror("seteuid");
 
1941
    perror_plus("seteuid");
1165
1942
  }
1166
1943
  
1167
1944
  if(quit_now){
1202
1979
        .arg = "SECONDS",
1203
1980
        .doc = "Maximum delay to wait for interface startup",
1204
1981
        .group = 2 },
 
1982
      { .name = "retry", .key = 132,
 
1983
        .arg = "SECONDS",
 
1984
        .doc = "Retry interval used when denied by the Mandos server",
 
1985
        .group = 2 },
 
1986
      { .name = "network-hook-dir", .key = 133,
 
1987
        .arg = "DIR",
 
1988
        .doc = "Directory where network hooks are located",
 
1989
        .group = 2 },
1205
1990
      /*
1206
1991
       * These reproduce what we would get without ARGP_NO_HELP
1207
1992
       */
1225
2010
        connect_to = arg;
1226
2011
        break;
1227
2012
      case 'i':                 /* --interface */
1228
 
        interface = arg;
 
2013
        ret_errno = argz_add_sep(&mc.interfaces, &mc.interfaces_size,
 
2014
                                 arg, (int)',');
 
2015
        if(ret_errno != 0){
 
2016
          argp_error(state, "%s", strerror(ret_errno));
 
2017
        }
1229
2018
        break;
1230
2019
      case 's':                 /* --seckey */
1231
2020
        seckey = arg;
1251
2040
        if(errno != 0 or tmp == arg or *tmp != '\0'){
1252
2041
          argp_error(state, "Bad delay");
1253
2042
        }
 
2043
      case 132:                 /* --retry */
 
2044
        errno = 0;
 
2045
        retry_interval = strtod(arg, &tmp);
 
2046
        if(errno != 0 or tmp == arg or *tmp != '\0'
 
2047
           or (retry_interval * 1000) > INT_MAX
 
2048
           or retry_interval < 0){
 
2049
          argp_error(state, "Bad retry interval");
 
2050
        }
 
2051
        break;
 
2052
      case 133:                 /* --network-hook-dir */
 
2053
        hookdir = arg;
1254
2054
        break;
1255
2055
        /*
1256
2056
         * These reproduce what we would get without ARGP_NO_HELP
1263
2063
        argp_state_help(state, state->out_stream,
1264
2064
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1265
2065
      case 'V':                 /* --version */
1266
 
        fprintf(state->out_stream, "%s\n", argp_program_version);
 
2066
        fprintf_plus(state->out_stream, "%s\n", argp_program_version);
1267
2067
        exit(argp_err_exit_status);
1268
2068
        break;
1269
2069
      default:
1284
2084
    case ENOMEM:
1285
2085
    default:
1286
2086
      errno = ret;
1287
 
      perror("argp_parse");
 
2087
      perror_plus("argp_parse");
1288
2088
      exitcode = EX_OSERR;
1289
2089
      goto end;
1290
2090
    case EINVAL:
1292
2092
      goto end;
1293
2093
    }
1294
2094
  }
 
2095
    
 
2096
  {
 
2097
    /* Work around Debian bug #633582:
 
2098
       <http://bugs.debian.org/633582> */
 
2099
    
 
2100
    /* Re-raise privileges */
 
2101
    ret_errno = raise_privileges();
 
2102
    if(ret_errno != 0){
 
2103
      errno = ret_errno;
 
2104
      perror_plus("Failed to raise privileges");
 
2105
    } else {
 
2106
      struct stat st;
 
2107
      
 
2108
      if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
 
2109
        int seckey_fd = open(seckey, O_RDONLY);
 
2110
        if(seckey_fd == -1){
 
2111
          perror_plus("open");
 
2112
        } else {
 
2113
          ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
 
2114
          if(ret == -1){
 
2115
            perror_plus("fstat");
 
2116
          } else {
 
2117
            if(S_ISREG(st.st_mode)
 
2118
               and st.st_uid == 0 and st.st_gid == 0){
 
2119
              ret = fchown(seckey_fd, uid, gid);
 
2120
              if(ret == -1){
 
2121
                perror_plus("fchown");
 
2122
              }
 
2123
            }
 
2124
          }
 
2125
          TEMP_FAILURE_RETRY(close(seckey_fd));
 
2126
        }
 
2127
      }
 
2128
    
 
2129
      if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){
 
2130
        int pubkey_fd = open(pubkey, O_RDONLY);
 
2131
        if(pubkey_fd == -1){
 
2132
          perror_plus("open");
 
2133
        } else {
 
2134
          ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
 
2135
          if(ret == -1){
 
2136
            perror_plus("fstat");
 
2137
          } else {
 
2138
            if(S_ISREG(st.st_mode)
 
2139
               and st.st_uid == 0 and st.st_gid == 0){
 
2140
              ret = fchown(pubkey_fd, uid, gid);
 
2141
              if(ret == -1){
 
2142
                perror_plus("fchown");
 
2143
              }
 
2144
            }
 
2145
          }
 
2146
          TEMP_FAILURE_RETRY(close(pubkey_fd));
 
2147
        }
 
2148
      }
 
2149
    
 
2150
      /* Lower privileges */
 
2151
      ret_errno = lower_privileges();
 
2152
      if(ret_errno != 0){
 
2153
        errno = ret_errno;
 
2154
        perror_plus("Failed to lower privileges");
 
2155
      }
 
2156
    }
 
2157
  }
 
2158
  
 
2159
  /* Remove invalid interface names (except "none") */
 
2160
  {
 
2161
    char *interface = NULL;
 
2162
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
 
2163
                                 interface))){
 
2164
      if(strcmp(interface, "none") != 0
 
2165
         and if_nametoindex(interface) == 0){
 
2166
        if(interface[0] != '\0'){
 
2167
          fprintf_plus(stderr, "Not using nonexisting interface"
 
2168
                       " \"%s\"\n", interface);
 
2169
        }
 
2170
        argz_delete(&mc.interfaces, &mc.interfaces_size, interface);
 
2171
        interface = NULL;
 
2172
      }
 
2173
    }
 
2174
  }
 
2175
  
 
2176
  /* Run network hooks */
 
2177
  {
 
2178
    if(mc.interfaces != NULL){
 
2179
      interfaces_hooks = malloc(mc.interfaces_size);
 
2180
      if(interfaces_hooks == NULL){
 
2181
        perror_plus("malloc");
 
2182
        goto end;
 
2183
      }
 
2184
      memcpy(interfaces_hooks, mc.interfaces, mc.interfaces_size);
 
2185
      argz_stringify(interfaces_hooks, mc.interfaces_size, (int)',');
 
2186
    }
 
2187
    run_network_hooks("start", interfaces_hooks != NULL ?
 
2188
                      interfaces_hooks : "", delay);
 
2189
  }
1295
2190
  
1296
2191
  if(not debug){
1297
2192
    avahi_set_log_function(empty_log);
1298
2193
  }
1299
 
 
1300
 
  if(interface[0] == '\0'){
1301
 
    struct dirent **direntries;
1302
 
    ret = scandir(sys_class_net, &direntries, good_interface,
1303
 
                  alphasort);
1304
 
    if(ret >= 1){
1305
 
      /* Pick the first good interface */
1306
 
      interface = strdup(direntries[0]->d_name);
1307
 
      if(debug){
1308
 
        fprintf(stderr, "Using interface \"%s\"\n", interface);
1309
 
      }
1310
 
      if(interface == NULL){
1311
 
        perror("malloc");
1312
 
        free(direntries);
1313
 
        exitcode = EXIT_FAILURE;
1314
 
        goto end;
1315
 
      }
1316
 
      free(direntries);
1317
 
    } else {
1318
 
      free(direntries);
1319
 
      fprintf(stderr, "Could not find a network interface\n");
1320
 
      exitcode = EXIT_FAILURE;
1321
 
      goto end;
1322
 
    }
1323
 
  }
1324
2194
  
1325
2195
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
1326
2196
     from the signal handler */
1327
2197
  /* Initialize the pseudo-RNG for Avahi */
1328
2198
  srand((unsigned int) time(NULL));
1329
 
  mc.simple_poll = avahi_simple_poll_new();
1330
 
  if(mc.simple_poll == NULL){
1331
 
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
 
2199
  simple_poll = avahi_simple_poll_new();
 
2200
  if(simple_poll == NULL){
 
2201
    fprintf_plus(stderr,
 
2202
                 "Avahi: Failed to create simple poll object.\n");
1332
2203
    exitcode = EX_UNAVAILABLE;
1333
2204
    goto end;
1334
2205
  }
1336
2207
  sigemptyset(&sigterm_action.sa_mask);
1337
2208
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1338
2209
  if(ret == -1){
1339
 
    perror("sigaddset");
 
2210
    perror_plus("sigaddset");
1340
2211
    exitcode = EX_OSERR;
1341
2212
    goto end;
1342
2213
  }
1343
2214
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1344
2215
  if(ret == -1){
1345
 
    perror("sigaddset");
 
2216
    perror_plus("sigaddset");
1346
2217
    exitcode = EX_OSERR;
1347
2218
    goto end;
1348
2219
  }
1349
2220
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1350
2221
  if(ret == -1){
1351
 
    perror("sigaddset");
 
2222
    perror_plus("sigaddset");
1352
2223
    exitcode = EX_OSERR;
1353
2224
    goto end;
1354
2225
  }
1358
2229
  */
1359
2230
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1360
2231
  if(ret == -1){
1361
 
    perror("sigaction");
 
2232
    perror_plus("sigaction");
1362
2233
    return EX_OSERR;
1363
2234
  }
1364
2235
  if(old_sigterm_action.sa_handler != SIG_IGN){
1365
2236
    ret = sigaction(SIGINT, &sigterm_action, NULL);
1366
2237
    if(ret == -1){
1367
 
      perror("sigaction");
 
2238
      perror_plus("sigaction");
1368
2239
      exitcode = EX_OSERR;
1369
2240
      goto end;
1370
2241
    }
1371
2242
  }
1372
2243
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1373
2244
  if(ret == -1){
1374
 
    perror("sigaction");
 
2245
    perror_plus("sigaction");
1375
2246
    return EX_OSERR;
1376
2247
  }
1377
2248
  if(old_sigterm_action.sa_handler != SIG_IGN){
1378
2249
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
1379
2250
    if(ret == -1){
1380
 
      perror("sigaction");
 
2251
      perror_plus("sigaction");
1381
2252
      exitcode = EX_OSERR;
1382
2253
      goto end;
1383
2254
    }
1384
2255
  }
1385
2256
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1386
2257
  if(ret == -1){
1387
 
    perror("sigaction");
 
2258
    perror_plus("sigaction");
1388
2259
    return EX_OSERR;
1389
2260
  }
1390
2261
  if(old_sigterm_action.sa_handler != SIG_IGN){
1391
2262
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
1392
2263
    if(ret == -1){
1393
 
      perror("sigaction");
1394
 
      exitcode = EX_OSERR;
1395
 
      goto end;
1396
 
    }
1397
 
  }
1398
 
  
1399
 
  /* If the interface is down, bring it up */
1400
 
  if(strcmp(interface, "none") != 0){
1401
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1402
 
    if(if_index == 0){
1403
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1404
 
      exitcode = EX_UNAVAILABLE;
1405
 
      goto end;
1406
 
    }
1407
 
    
1408
 
    if(quit_now){
1409
 
      goto end;
1410
 
    }
1411
 
    
1412
 
    /* Re-raise priviliges */
1413
 
    errno = 0;
1414
 
    ret = seteuid(0);
1415
 
    if(ret == -1){
1416
 
      perror("seteuid");
1417
 
    }
1418
 
    
1419
 
#ifdef __linux__
1420
 
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1421
 
       messages about the network interface to mess up the prompt */
1422
 
    ret = klogctl(8, NULL, 5);
1423
 
    bool restore_loglevel = true;
1424
 
    if(ret == -1){
1425
 
      restore_loglevel = false;
1426
 
      perror("klogctl");
1427
 
    }
1428
 
#endif  /* __linux__ */
1429
 
    
1430
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1431
 
    if(sd < 0){
1432
 
      perror("socket");
1433
 
      exitcode = EX_OSERR;
1434
 
#ifdef __linux__
1435
 
      if(restore_loglevel){
1436
 
        ret = klogctl(7, NULL, 0);
1437
 
        if(ret == -1){
1438
 
          perror("klogctl");
1439
 
        }
1440
 
      }
1441
 
#endif  /* __linux__ */
1442
 
      /* Lower privileges */
1443
 
      errno = 0;
1444
 
      ret = seteuid(uid);
1445
 
      if(ret == -1){
1446
 
        perror("seteuid");
1447
 
      }
1448
 
      goto end;
1449
 
    }
1450
 
    strcpy(network.ifr_name, interface);
1451
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
1452
 
    if(ret == -1){
1453
 
      perror("ioctl SIOCGIFFLAGS");
1454
 
#ifdef __linux__
1455
 
      if(restore_loglevel){
1456
 
        ret = klogctl(7, NULL, 0);
1457
 
        if(ret == -1){
1458
 
          perror("klogctl");
1459
 
        }
1460
 
      }
1461
 
#endif  /* __linux__ */
1462
 
      exitcode = EX_OSERR;
1463
 
      /* Lower privileges */
1464
 
      errno = 0;
1465
 
      ret = seteuid(uid);
1466
 
      if(ret == -1){
1467
 
        perror("seteuid");
1468
 
      }
1469
 
      goto end;
1470
 
    }
1471
 
    if((network.ifr_flags & IFF_UP) == 0){
1472
 
      network.ifr_flags |= IFF_UP;
1473
 
      take_down_interface = true;
1474
 
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
1475
 
      if(ret == -1){
1476
 
        take_down_interface = false;
1477
 
        perror("ioctl SIOCSIFFLAGS +IFF_UP");
1478
 
        exitcode = EX_OSERR;
1479
 
#ifdef __linux__
1480
 
        if(restore_loglevel){
1481
 
          ret = klogctl(7, NULL, 0);
1482
 
          if(ret == -1){
1483
 
            perror("klogctl");
 
2264
      perror_plus("sigaction");
 
2265
      exitcode = EX_OSERR;
 
2266
      goto end;
 
2267
    }
 
2268
  }
 
2269
  
 
2270
  /* If no interfaces were specified, make a list */
 
2271
  if(mc.interfaces == NULL){
 
2272
    struct dirent **direntries = NULL;
 
2273
    /* Look for any good interfaces */
 
2274
    ret = scandir(sys_class_net, &direntries, good_interface,
 
2275
                  alphasort);
 
2276
    if(ret >= 1){
 
2277
      /* Add all found interfaces to interfaces list */
 
2278
      for(int i = 0; i < ret; ++i){
 
2279
        ret_errno = argz_add(&mc.interfaces, &mc.interfaces_size,
 
2280
                             direntries[i]->d_name);
 
2281
        if(ret_errno != 0){
 
2282
          errno = ret_errno;
 
2283
          perror_plus("argz_add");
 
2284
          free(direntries[i]);
 
2285
          continue;
 
2286
        }
 
2287
        if(debug){
 
2288
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
 
2289
                       direntries[i]->d_name);
 
2290
        }
 
2291
        free(direntries[i]);
 
2292
      }
 
2293
      free(direntries);
 
2294
    } else {
 
2295
      if(ret == 0){
 
2296
        free(direntries);
 
2297
      }
 
2298
      fprintf_plus(stderr, "Could not find a network interface\n");
 
2299
      exitcode = EXIT_FAILURE;
 
2300
      goto end;
 
2301
    }
 
2302
  }
 
2303
  
 
2304
  /* Bring up interfaces which are down, and remove any "none"s */
 
2305
  {
 
2306
    char *interface = NULL;
 
2307
    while((interface = argz_next(mc.interfaces, mc.interfaces_size,
 
2308
                                 interface))){
 
2309
      /* If interface name is "none", stop bringing up interfaces.
 
2310
         Also remove all instances of "none" from the list */
 
2311
      if(strcmp(interface, "none") == 0){
 
2312
        argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2313
                    interface);
 
2314
        interface = NULL;
 
2315
        while((interface = argz_next(mc.interfaces,
 
2316
                                     mc.interfaces_size, interface))){
 
2317
          if(strcmp(interface, "none") == 0){
 
2318
            argz_delete(&mc.interfaces, &mc.interfaces_size,
 
2319
                        interface);
 
2320
            interface = NULL;
1484
2321
          }
1485
2322
        }
1486
 
#endif  /* __linux__ */
1487
 
        /* Lower privileges */
1488
 
        errno = 0;
1489
 
        ret = seteuid(uid);
1490
 
        if(ret == -1){
1491
 
          perror("seteuid");
1492
 
        }
1493
 
        goto end;
1494
 
      }
1495
 
    }
1496
 
    /* sleep checking until interface is running */
1497
 
    for(int i=0; i < delay * 4; i++){
1498
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1499
 
      if(ret == -1){
1500
 
        perror("ioctl SIOCGIFFLAGS");
1501
 
      } else if(network.ifr_flags & IFF_RUNNING){
1502
2323
        break;
1503
2324
      }
1504
 
      struct timespec sleeptime = { .tv_nsec = 250000000 };
1505
 
      ret = nanosleep(&sleeptime, NULL);
1506
 
      if(ret == -1 and errno != EINTR){
1507
 
        perror("nanosleep");
1508
 
      }
1509
 
    }
1510
 
    if(not take_down_interface){
1511
 
      /* We won't need the socket anymore */
1512
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1513
 
      if(ret == -1){
1514
 
        perror("close");
1515
 
      }
1516
 
    }
1517
 
#ifdef __linux__
1518
 
    if(restore_loglevel){
1519
 
      /* Restores kernel loglevel to default */
1520
 
      ret = klogctl(7, NULL, 0);
1521
 
      if(ret == -1){
1522
 
        perror("klogctl");
1523
 
      }
1524
 
    }
1525
 
#endif  /* __linux__ */
1526
 
    /* Lower privileges */
1527
 
    errno = 0;
1528
 
    if(take_down_interface){
1529
 
      /* Lower privileges */
1530
 
      ret = seteuid(uid);
1531
 
      if(ret == -1){
1532
 
        perror("seteuid");
1533
 
      }
1534
 
    } else {
1535
 
      /* Lower privileges permanently */
1536
 
      ret = setuid(uid);
1537
 
      if(ret == -1){
1538
 
        perror("setuid");
1539
 
      }
1540
 
    }
 
2325
      bool interface_was_up = interface_is_up(interface);
 
2326
      errno = bring_up_interface(interface, delay);
 
2327
      if(not interface_was_up){
 
2328
        if(errno != 0){
 
2329
          perror_plus("Failed to bring up interface");
 
2330
        } else {
 
2331
          errno = argz_add(&interfaces_to_take_down,
 
2332
                           &interfaces_to_take_down_size,
 
2333
                           interface);
 
2334
          if(errno != 0){
 
2335
            perror_plus("argz_add");
 
2336
          }
 
2337
        }
 
2338
      }
 
2339
    }
 
2340
    if(debug and (interfaces_to_take_down == NULL)){
 
2341
      fprintf_plus(stderr, "No interfaces were brought up\n");
 
2342
    }
 
2343
  }
 
2344
  
 
2345
  /* If we only got one interface, explicitly use only that one */
 
2346
  if(argz_count(mc.interfaces, mc.interfaces_size) == 1){
 
2347
    if(debug){
 
2348
      fprintf_plus(stderr, "Using only interface \"%s\"\n",
 
2349
                   mc.interfaces);
 
2350
    }
 
2351
    if_index = (AvahiIfIndex)if_nametoindex(mc.interfaces);
1541
2352
  }
1542
2353
  
1543
2354
  if(quit_now){
1544
2355
    goto end;
1545
2356
  }
1546
2357
  
1547
 
  ret = init_gnutls_global(pubkey, seckey);
 
2358
  ret = init_gnutls_global(pubkey, seckey, &mc);
1548
2359
  if(ret == -1){
1549
 
    fprintf(stderr, "init_gnutls_global failed\n");
 
2360
    fprintf_plus(stderr, "init_gnutls_global failed\n");
1550
2361
    exitcode = EX_UNAVAILABLE;
1551
2362
    goto end;
1552
2363
  } else {
1557
2368
    goto end;
1558
2369
  }
1559
2370
  
1560
 
  tempdir_created = true;
1561
 
  if(mkdtemp(tempdir) == NULL){
1562
 
    tempdir_created = false;
1563
 
    perror("mkdtemp");
 
2371
  /* Try /run/tmp before /tmp */
 
2372
  tempdir = mkdtemp(run_tempdir);
 
2373
  if(tempdir == NULL and errno == ENOENT){
 
2374
      if(debug){
 
2375
        fprintf_plus(stderr, "Tempdir %s did not work, trying %s\n",
 
2376
                     run_tempdir, old_tempdir);
 
2377
      }
 
2378
      tempdir = mkdtemp(old_tempdir);
 
2379
  }
 
2380
  if(tempdir == NULL){
 
2381
    perror_plus("mkdtemp");
1564
2382
    goto end;
1565
2383
  }
1566
2384
  
1568
2386
    goto end;
1569
2387
  }
1570
2388
  
1571
 
  if(not init_gpgme(pubkey, seckey, tempdir)){
1572
 
    fprintf(stderr, "init_gpgme failed\n");
 
2389
  if(not init_gpgme(pubkey, seckey, tempdir, &mc)){
 
2390
    fprintf_plus(stderr, "init_gpgme failed\n");
1573
2391
    exitcode = EX_UNAVAILABLE;
1574
2392
    goto end;
1575
2393
  } else {
1584
2402
    /* Connect directly, do not use Zeroconf */
1585
2403
    /* (Mainly meant for debugging) */
1586
2404
    char *address = strrchr(connect_to, ':');
 
2405
    
1587
2406
    if(address == NULL){
1588
 
      fprintf(stderr, "No colon in address\n");
 
2407
      fprintf_plus(stderr, "No colon in address\n");
1589
2408
      exitcode = EX_USAGE;
1590
2409
      goto end;
1591
2410
    }
1594
2413
      goto end;
1595
2414
    }
1596
2415
    
1597
 
    uint16_t port;
 
2416
    in_port_t port;
1598
2417
    errno = 0;
1599
2418
    tmpmax = strtoimax(address+1, &tmp, 10);
1600
2419
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
1601
 
       or tmpmax != (uint16_t)tmpmax){
1602
 
      fprintf(stderr, "Bad port number\n");
 
2420
       or tmpmax != (in_port_t)tmpmax){
 
2421
      fprintf_plus(stderr, "Bad port number\n");
1603
2422
      exitcode = EX_USAGE;
1604
2423
      goto end;
1605
2424
    }
1606
 
  
 
2425
    
1607
2426
    if(quit_now){
1608
2427
      goto end;
1609
2428
    }
1610
2429
    
1611
 
    port = (uint16_t)tmpmax;
 
2430
    port = (in_port_t)tmpmax;
1612
2431
    *address = '\0';
1613
 
    address = connect_to;
1614
2432
    /* Colon in address indicates IPv6 */
1615
2433
    int af;
1616
 
    if(strchr(address, ':') != NULL){
 
2434
    if(strchr(connect_to, ':') != NULL){
1617
2435
      af = AF_INET6;
 
2436
      /* Accept [] around IPv6 address - see RFC 5952 */
 
2437
      if(connect_to[0] == '[' and address[-1] == ']')
 
2438
        {
 
2439
          connect_to++;
 
2440
          address[-1] = '\0';
 
2441
        }
1618
2442
    } else {
1619
2443
      af = AF_INET;
1620
2444
    }
 
2445
    address = connect_to;
1621
2446
    
1622
2447
    if(quit_now){
1623
2448
      goto end;
1624
2449
    }
1625
 
 
 
2450
    
1626
2451
    while(not quit_now){
1627
 
      ret = start_mandos_communication(address, port, if_index, af);
 
2452
      ret = start_mandos_communication(address, port, if_index, af,
 
2453
                                       &mc);
1628
2454
      if(quit_now or ret == 0){
1629
2455
        break;
1630
2456
      }
1631
 
      sleep(15);
1632
 
    };
1633
 
 
1634
 
    if (not quit_now){
 
2457
      if(debug){
 
2458
        fprintf_plus(stderr, "Retrying in %d seconds\n",
 
2459
                     (int)retry_interval);
 
2460
      }
 
2461
      sleep((unsigned int)retry_interval);
 
2462
    }
 
2463
    
 
2464
    if(not quit_now){
1635
2465
      exitcode = EXIT_SUCCESS;
1636
2466
    }
1637
 
 
 
2467
    
1638
2468
    goto end;
1639
2469
  }
1640
2470
  
1652
2482
    config.publish_domain = 0;
1653
2483
    
1654
2484
    /* Allocate a new server */
1655
 
    mc.server = avahi_server_new(avahi_simple_poll_get
1656
 
                                 (mc.simple_poll), &config, NULL,
1657
 
                                 NULL, &error);
 
2485
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
2486
                                 &config, NULL, NULL, &ret_errno);
1658
2487
    
1659
2488
    /* Free the Avahi configuration data */
1660
2489
    avahi_server_config_free(&config);
1662
2491
  
1663
2492
  /* Check if creating the Avahi server object succeeded */
1664
2493
  if(mc.server == NULL){
1665
 
    fprintf(stderr, "Failed to create Avahi server: %s\n",
1666
 
            avahi_strerror(error));
 
2494
    fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
 
2495
                 avahi_strerror(ret_errno));
1667
2496
    exitcode = EX_UNAVAILABLE;
1668
2497
    goto end;
1669
2498
  }
1675
2504
  /* Create the Avahi service browser */
1676
2505
  sb = avahi_s_service_browser_new(mc.server, if_index,
1677
2506
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1678
 
                                   NULL, 0, browse_callback, NULL);
 
2507
                                   NULL, 0, browse_callback,
 
2508
                                   (void *)&mc);
1679
2509
  if(sb == NULL){
1680
 
    fprintf(stderr, "Failed to create service browser: %s\n",
1681
 
            avahi_strerror(avahi_server_errno(mc.server)));
 
2510
    fprintf_plus(stderr, "Failed to create service browser: %s\n",
 
2511
                 avahi_strerror(avahi_server_errno(mc.server)));
1682
2512
    exitcode = EX_UNAVAILABLE;
1683
2513
    goto end;
1684
2514
  }
1690
2520
  /* Run the main loop */
1691
2521
  
1692
2522
  if(debug){
1693
 
    fprintf(stderr, "Starting Avahi loop search\n");
 
2523
    fprintf_plus(stderr, "Starting Avahi loop search\n");
1694
2524
  }
1695
2525
  
1696
 
  avahi_simple_poll_loop(mc.simple_poll);
 
2526
  ret = avahi_loop_with_timeout(simple_poll,
 
2527
                                (int)(retry_interval * 1000), &mc);
 
2528
  if(debug){
 
2529
    fprintf_plus(stderr, "avahi_loop_with_timeout exited %s\n",
 
2530
                 (ret == 0) ? "successfully" : "with error");
 
2531
  }
1697
2532
  
1698
2533
 end:
1699
2534
  
1700
2535
  if(debug){
1701
 
    fprintf(stderr, "%s exiting\n", argv[0]);
 
2536
    fprintf_plus(stderr, "%s exiting\n", argv[0]);
1702
2537
  }
1703
2538
  
1704
2539
  /* Cleanup things */
 
2540
  free(mc.interfaces);
 
2541
  
1705
2542
  if(sb != NULL)
1706
2543
    avahi_s_service_browser_free(sb);
1707
2544
  
1708
2545
  if(mc.server != NULL)
1709
2546
    avahi_server_free(mc.server);
1710
2547
  
1711
 
  if(mc.simple_poll != NULL)
1712
 
    avahi_simple_poll_free(mc.simple_poll);
 
2548
  if(simple_poll != NULL)
 
2549
    avahi_simple_poll_free(simple_poll);
1713
2550
  
1714
2551
  if(gnutls_initialized){
1715
2552
    gnutls_certificate_free_credentials(mc.cred);
1721
2558
    gpgme_release(mc.ctx);
1722
2559
  }
1723
2560
  
1724
 
  /* Take down the network interface */
1725
 
  if(take_down_interface){
1726
 
    /* Re-raise priviliges */
1727
 
    errno = 0;
1728
 
    ret = seteuid(0);
1729
 
    if(ret == -1){
1730
 
      perror("seteuid");
1731
 
    }
1732
 
    if(geteuid() == 0){
1733
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1734
 
      if(ret == -1){
1735
 
        perror("ioctl SIOCGIFFLAGS");
1736
 
      } else if(network.ifr_flags & IFF_UP) {
1737
 
        network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1738
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
1739
 
        if(ret == -1){
1740
 
          perror("ioctl SIOCSIFFLAGS -IFF_UP");
1741
 
        }
1742
 
      }
1743
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1744
 
      if(ret == -1){
1745
 
        perror("close");
1746
 
      }
1747
 
      /* Lower privileges permanently */
1748
 
      errno = 0;
1749
 
      ret = setuid(uid);
1750
 
      if(ret == -1){
1751
 
        perror("setuid");
1752
 
      }
1753
 
    }
1754
 
  }
1755
 
  
1756
 
  /* Removes the temp directory used by GPGME */
1757
 
  if(tempdir_created){
1758
 
    DIR *d;
1759
 
    struct dirent *direntry;
1760
 
    d = opendir(tempdir);
1761
 
    if(d == NULL){
1762
 
      if(errno != ENOENT){
1763
 
        perror("opendir");
1764
 
      }
1765
 
    } else {
1766
 
      while(true){
1767
 
        direntry = readdir(d);
1768
 
        if(direntry == NULL){
1769
 
          break;
1770
 
        }
1771
 
        /* Skip "." and ".." */
1772
 
        if(direntry->d_name[0] == '.'
1773
 
           and (direntry->d_name[1] == '\0'
1774
 
                or (direntry->d_name[1] == '.'
1775
 
                    and direntry->d_name[2] == '\0'))){
1776
 
          continue;
1777
 
        }
1778
 
        char *fullname = NULL;
1779
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
1780
 
                       direntry->d_name);
1781
 
        if(ret < 0){
1782
 
          perror("asprintf");
1783
 
          continue;
1784
 
        }
1785
 
        ret = remove(fullname);
1786
 
        if(ret == -1){
1787
 
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1788
 
                  strerror(errno));
1789
 
        }
1790
 
        free(fullname);
1791
 
      }
1792
 
      closedir(d);
1793
 
    }
1794
 
    ret = rmdir(tempdir);
1795
 
    if(ret == -1 and errno != ENOENT){
1796
 
      perror("rmdir");
 
2561
  /* Cleans up the circular linked list of Mandos servers the client
 
2562
     has seen */
 
2563
  if(mc.current_server != NULL){
 
2564
    mc.current_server->prev->next = NULL;
 
2565
    while(mc.current_server != NULL){
 
2566
      server *next = mc.current_server->next;
 
2567
#ifdef __GNUC__
 
2568
#pragma GCC diagnostic push
 
2569
#pragma GCC diagnostic ignored "-Wcast-qual"
 
2570
#endif
 
2571
      free((char *)(mc.current_server->ip));
 
2572
#ifdef __GNUC__
 
2573
#pragma GCC diagnostic pop
 
2574
#endif
 
2575
      free(mc.current_server);
 
2576
      mc.current_server = next;
 
2577
    }
 
2578
  }
 
2579
  
 
2580
  /* Re-raise privileges */
 
2581
  {
 
2582
    ret_errno = raise_privileges();
 
2583
    if(ret_errno != 0){
 
2584
      errno = ret_errno;
 
2585
      perror_plus("Failed to raise privileges");
 
2586
    } else {
 
2587
      
 
2588
      /* Run network hooks */
 
2589
      run_network_hooks("stop", interfaces_hooks != NULL ?
 
2590
                        interfaces_hooks : "", delay);
 
2591
      
 
2592
      /* Take down the network interfaces which were brought up */
 
2593
      {
 
2594
        char *interface = NULL;
 
2595
        while((interface=argz_next(interfaces_to_take_down,
 
2596
                                   interfaces_to_take_down_size,
 
2597
                                   interface))){
 
2598
          ret_errno = take_down_interface(interface);
 
2599
          if(ret_errno != 0){
 
2600
            errno = ret_errno;
 
2601
            perror_plus("Failed to take down interface");
 
2602
          }
 
2603
        }
 
2604
        if(debug and (interfaces_to_take_down == NULL)){
 
2605
          fprintf_plus(stderr, "No interfaces needed to be taken"
 
2606
                       " down\n");
 
2607
        }
 
2608
      }
 
2609
    }
 
2610
    
 
2611
    ret_errno = lower_privileges_permanently();
 
2612
    if(ret_errno != 0){
 
2613
      errno = ret_errno;
 
2614
      perror_plus("Failed to lower privileges permanently");
 
2615
    }
 
2616
  }
 
2617
  
 
2618
  free(interfaces_to_take_down);
 
2619
  free(interfaces_hooks);
 
2620
  
 
2621
  /* Removes the GPGME temp directory and all files inside */
 
2622
  if(tempdir != NULL){
 
2623
    struct dirent **direntries = NULL;
 
2624
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY |
 
2625
                                                  O_NOFOLLOW));
 
2626
    if(tempdir_fd == -1){
 
2627
      perror_plus("open");
 
2628
    } else {
 
2629
#ifdef __GLIBC__
 
2630
#if __GLIBC_PREREQ(2, 15)
 
2631
      int numentries = scandirat(tempdir_fd, ".", &direntries,
 
2632
                                 notdotentries, alphasort);
 
2633
#else  /* not __GLIBC_PREREQ(2, 15) */
 
2634
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2635
                               alphasort);
 
2636
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
2637
#else   /* not __GLIBC__ */
 
2638
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
2639
                               alphasort);
 
2640
#endif  /* not __GLIBC__ */
 
2641
      if(numentries >= 0){
 
2642
        for(int i = 0; i < numentries; i++){
 
2643
          ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
 
2644
          if(ret == -1){
 
2645
            fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
 
2646
                         " \"%s\", 0): %s\n", tempdir,
 
2647
                         direntries[i]->d_name, strerror(errno));
 
2648
          }
 
2649
          free(direntries[i]);
 
2650
        }
 
2651
        
 
2652
        /* need to clean even if 0 because man page doesn't specify */
 
2653
        free(direntries);
 
2654
        if(numentries == -1){
 
2655
          perror_plus("scandir");
 
2656
        }
 
2657
        ret = rmdir(tempdir);
 
2658
        if(ret == -1 and errno != ENOENT){
 
2659
          perror_plus("rmdir");
 
2660
        }
 
2661
      }
 
2662
      TEMP_FAILURE_RETRY(close(tempdir_fd));
1797
2663
    }
1798
2664
  }
1799
2665
  
1804
2670
                                            &old_sigterm_action,
1805
2671
                                            NULL));
1806
2672
    if(ret == -1){
1807
 
      perror("sigaction");
 
2673
      perror_plus("sigaction");
1808
2674
    }
1809
2675
    do {
1810
2676
      ret = raise(signal_received);
1811
2677
    } while(ret != 0 and errno == EINTR);
1812
2678
    if(ret != 0){
1813
 
      perror("raise");
 
2679
      perror_plus("raise");
1814
2680
      abort();
1815
2681
    }
1816
2682
    TEMP_FAILURE_RETRY(pause());