/mandos/release

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

« back to all changes in this revision

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

  • Committer: Teddy Hogeborn
  • Date: 2014-07-25 22:44:20 UTC
  • mto: (237.7.272 trunk)
  • mto: This revision was merged to the branch mainline in revision 321.
  • 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,2009 Teddy Hogeborn
13
 
 * Copyright © 2008,2009 Björn Påhlsson
 
12
 * Copyright © 2008-2014 Teddy Hogeborn
 
13
 * Copyright © 2008-2014 Björn Påhlsson
14
14
 * 
15
15
 * This program is free software: you can redistribute it and/or
16
16
 * modify it under the terms of the GNU General Public License as
26
26
 * along with this program.  If not, see
27
27
 * <http://www.gnu.org/licenses/>.
28
28
 * 
29
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
29
 * Contact the authors at <mandos@recompile.se>.
30
30
 */
31
31
 
32
32
/* Needed by GPGME, specifically gpgme_data_seek() */
33
33
#ifndef _LARGEFILE_SOURCE
34
34
#define _LARGEFILE_SOURCE
35
 
#endif
 
35
#endif  /* not _LARGEFILE_SOURCE */
36
36
#ifndef _FILE_OFFSET_BITS
37
37
#define _FILE_OFFSET_BITS 64
38
 
#endif
 
38
#endif  /* not _FILE_OFFSET_BITS */
39
39
 
40
40
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
41
41
 
42
42
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
43
 
                                   stdout, ferror(), remove() */
44
 
#include <stdint.h>             /* uint16_t, uint32_t */
 
43
                                   stdout, ferror() */
 
44
#include <stdint.h>             /* uint16_t, uint32_t, intptr_t */
45
45
#include <stddef.h>             /* NULL, size_t, ssize_t */
46
 
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
47
 
                                   srand(), strtof() */
 
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
 
47
                                   strtof(), abort() */
48
48
#include <stdbool.h>            /* bool, false, true */
49
49
#include <string.h>             /* memset(), strcmp(), strlen(),
50
50
                                   strerror(), asprintf(), strcpy() */
53
53
                                   sockaddr_in6, PF_INET6,
54
54
                                   SOCK_STREAM, uid_t, gid_t, open(),
55
55
                                   opendir(), DIR */
56
 
#include <sys/stat.h>           /* open() */
 
56
#include <sys/stat.h>           /* open(), S_ISREG */
57
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
58
 
                                   inet_pton(), connect() */
59
 
#include <fcntl.h>              /* open() */
 
58
                                   inet_pton(), connect(),
 
59
                                   getnameinfo() */
 
60
#include <fcntl.h>              /* open(), unlinkat() */
60
61
#include <dirent.h>             /* opendir(), struct dirent, readdir()
61
62
                                 */
62
63
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
63
64
                                   strtoimax() */
64
 
#include <assert.h>             /* assert() */
65
 
#include <errno.h>              /* perror(), errno */
66
 
#include <time.h>               /* nanosleep(), time() */
 
65
#include <errno.h>              /* perror(), errno,
 
66
                                   program_invocation_short_name */
 
67
#include <time.h>               /* nanosleep(), time(), sleep() */
67
68
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
68
69
                                   SIOCSIFFLAGS, if_indextoname(),
69
70
                                   if_nametoindex(), IF_NAMESIZE */
72
73
                                */
73
74
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
74
75
                                   getuid(), getgid(), seteuid(),
75
 
                                   setgid() */
76
 
#include <arpa/inet.h>          /* inet_pton(), htons */
 
76
                                   setgid(), pause(), _exit(),
 
77
                                   unlinkat() */
 
78
#include <arpa/inet.h>          /* inet_pton(), htons() */
77
79
#include <iso646.h>             /* not, or, and */
78
80
#include <argp.h>               /* struct argp_option, error_t, struct
79
81
                                   argp_state, struct argp,
82
84
#include <signal.h>             /* sigemptyset(), sigaddset(),
83
85
                                   sigaction(), SIGTERM, sig_atomic_t,
84
86
                                   raise() */
 
87
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
 
88
                                   EX_NOHOST, EX_IOERR, EX_PROTOCOL */
 
89
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
 
90
                                   WEXITSTATUS(), WTERMSIG() */
 
91
#include <grp.h>                /* setgroups() */
 
92
#include <argz.h>               /* argz_add_sep(), argz_next(),
 
93
                                   argz_delete(), argz_append(),
 
94
                                   argz_stringify(), argz_add(),
 
95
                                   argz_count() */
 
96
#include <netdb.h>              /* getnameinfo(), NI_NUMERICHOST,
 
97
                                   EAI_SYSTEM, gai_strerror() */
85
98
 
86
99
#ifdef __linux__
87
100
#include <sys/klog.h>           /* klogctl() */
105
118
                                   init_gnutls_session(),
106
119
                                   GNUTLS_* */
107
120
#include <gnutls/openpgp.h>
108
 
                          /* gnutls_certificate_set_openpgp_key_file(),
109
 
                                   GNUTLS_OPENPGP_FMT_BASE64 */
 
121
                         /* gnutls_certificate_set_openpgp_key_file(),
 
122
                            GNUTLS_OPENPGP_FMT_BASE64 */
110
123
 
111
124
/* GPGME */
112
125
#include <gpgme.h>              /* All GPGME types, constants and
120
133
#define PATHDIR "/conf/conf.d/mandos"
121
134
#define SECKEY "seckey.txt"
122
135
#define PUBKEY "pubkey.txt"
 
136
#define HOOKDIR "/lib/mandos/network-hooks.d"
123
137
 
124
138
bool debug = false;
125
139
static const char mandos_protocol_version[] = "1";
126
140
const char *argp_program_version = "mandos-client " VERSION;
127
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
141
const char *argp_program_bug_address = "<mandos@recompile.se>";
 
142
static const char sys_class_net[] = "/sys/class/net";
 
143
char *connect_to = NULL;
 
144
const char *hookdir = HOOKDIR;
 
145
int hookdir_fd = -1;
 
146
uid_t uid = 65534;
 
147
gid_t gid = 65534;
 
148
 
 
149
/* Doubly linked list that need to be circularly linked when used */
 
150
typedef struct server{
 
151
  const char *ip;
 
152
  in_port_t port;
 
153
  AvahiIfIndex if_index;
 
154
  int af;
 
155
  struct timespec last_seen;
 
156
  struct server *next;
 
157
  struct server *prev;
 
158
} server;
128
159
 
129
160
/* Used for passing in values through the Avahi callback functions */
130
161
typedef struct {
131
 
  AvahiSimplePoll *simple_poll;
132
162
  AvahiServer *server;
133
163
  gnutls_certificate_credentials_t cred;
134
164
  unsigned int dh_bits;
135
165
  gnutls_dh_params_t dh_params;
136
166
  const char *priority;
137
167
  gpgme_ctx_t ctx;
 
168
  server *current_server;
 
169
  char *interfaces;
 
170
  size_t interfaces_size;
138
171
} mandos_context;
139
172
 
140
 
/* global context so signal handler can reach it*/
141
 
mandos_context mc = { .simple_poll = NULL, .server = NULL,
142
 
                      .dh_bits = 1024, .priority = "SECURE256"
143
 
                      ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
173
/* global so signal handler can reach it*/
 
174
AvahiSimplePoll *simple_poll;
 
175
 
 
176
sig_atomic_t quit_now = 0;
 
177
int signal_received = 0;
 
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
}
144
197
 
145
198
/*
146
199
 * Make additional room in "buffer" for at least BUFFER_SIZE more
147
200
 * bytes. "buffer_capacity" is how much is currently allocated,
148
201
 * "buffer_length" is how much is already used.
149
202
 */
 
203
__attribute__((nonnull, warn_unused_result))
150
204
size_t incbuffer(char **buffer, size_t buffer_length,
151
 
                  size_t buffer_capacity){
 
205
                 size_t buffer_capacity){
152
206
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
153
 
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
154
 
    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;
155
213
      return 0;
156
214
    }
 
215
    *buffer = new_buf;
157
216
    buffer_capacity += BUFFER_SIZE;
158
217
  }
159
218
  return buffer_capacity;
160
219
}
161
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
 
162
269
/* 
163
270
 * Initialize GPGME.
164
271
 */
165
 
static bool init_gpgme(const char *seckey,
166
 
                       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){
167
277
  gpgme_error_t rc;
168
278
  gpgme_engine_info_t engine_info;
169
279
  
170
 
  
171
280
  /*
172
281
   * Helper function to insert pub and seckey to the engine keyring.
173
282
   */
174
 
  bool import_key(const char *filename){
 
283
  bool import_key(const char * const filename){
175
284
    int ret;
176
285
    int fd;
177
286
    gpgme_data_t pgp_data;
178
287
    
179
288
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
180
289
    if(fd == -1){
181
 
      perror("open");
 
290
      perror_plus("open");
182
291
      return false;
183
292
    }
184
293
    
185
294
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
186
295
    if(rc != GPG_ERR_NO_ERROR){
187
 
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
188
 
              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));
189
298
      return false;
190
299
    }
191
300
    
192
 
    rc = gpgme_op_import(mc.ctx, pgp_data);
 
301
    rc = gpgme_op_import(mc->ctx, pgp_data);
193
302
    if(rc != GPG_ERR_NO_ERROR){
194
 
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
195
 
              gpgme_strsource(rc), gpgme_strerror(rc));
 
303
      fprintf_plus(stderr, "bad gpgme_op_import: %s: %s\n",
 
304
                   gpgme_strsource(rc), gpgme_strerror(rc));
196
305
      return false;
197
306
    }
198
307
    
199
308
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
200
309
    if(ret == -1){
201
 
      perror("close");
 
310
      perror_plus("close");
202
311
    }
203
312
    gpgme_data_release(pgp_data);
204
313
    return true;
205
314
  }
206
315
  
207
316
  if(debug){
208
 
    fprintf(stderr, "Initializing GPGME\n");
 
317
    fprintf_plus(stderr, "Initializing GPGME\n");
209
318
  }
210
319
  
211
320
  /* Init GPGME */
212
321
  gpgme_check_version(NULL);
213
322
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
214
323
  if(rc != GPG_ERR_NO_ERROR){
215
 
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
216
 
            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));
217
326
    return false;
218
327
  }
219
328
  
220
 
    /* Set GPGME home directory for the OpenPGP engine only */
 
329
  /* Set GPGME home directory for the OpenPGP engine only */
221
330
  rc = gpgme_get_engine_info(&engine_info);
222
331
  if(rc != GPG_ERR_NO_ERROR){
223
 
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
224
 
            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));
225
334
    return false;
226
335
  }
227
336
  while(engine_info != NULL){
233
342
    engine_info = engine_info->next;
234
343
  }
235
344
  if(engine_info == NULL){
236
 
    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);
237
347
    return false;
238
348
  }
239
349
  
240
350
  /* Create new GPGME "context" */
241
 
  rc = gpgme_new(&(mc.ctx));
 
351
  rc = gpgme_new(&(mc->ctx));
242
352
  if(rc != GPG_ERR_NO_ERROR){
243
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
244
 
            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));
245
356
    return false;
246
357
  }
247
358
  
256
367
 * Decrypt OpenPGP data.
257
368
 * Returns -1 on error
258
369
 */
 
370
__attribute__((nonnull, warn_unused_result))
259
371
static ssize_t pgp_packet_decrypt(const char *cryptotext,
260
372
                                  size_t crypto_size,
261
 
                                  char **plaintext){
 
373
                                  char **plaintext,
 
374
                                  mandos_context *mc){
262
375
  gpgme_data_t dh_crypto, dh_plain;
263
376
  gpgme_error_t rc;
264
377
  ssize_t ret;
266
379
  ssize_t plaintext_length = 0;
267
380
  
268
381
  if(debug){
269
 
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
382
    fprintf_plus(stderr, "Trying to decrypt OpenPGP data\n");
270
383
  }
271
384
  
272
385
  /* Create new GPGME data buffer from memory cryptotext */
273
386
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
274
387
                               0);
275
388
  if(rc != GPG_ERR_NO_ERROR){
276
 
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
277
 
            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));
278
391
    return -1;
279
392
  }
280
393
  
281
394
  /* Create new empty GPGME data buffer for the plaintext */
282
395
  rc = gpgme_data_new(&dh_plain);
283
396
  if(rc != GPG_ERR_NO_ERROR){
284
 
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
285
 
            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));
286
400
    gpgme_data_release(dh_crypto);
287
401
    return -1;
288
402
  }
289
403
  
290
404
  /* Decrypt data from the cryptotext data buffer to the plaintext
291
405
     data buffer */
292
 
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
406
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
293
407
  if(rc != GPG_ERR_NO_ERROR){
294
 
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
295
 
            gpgme_strsource(rc), gpgme_strerror(rc));
 
408
    fprintf_plus(stderr, "bad gpgme_op_decrypt: %s: %s\n",
 
409
                 gpgme_strsource(rc), gpgme_strerror(rc));
296
410
    plaintext_length = -1;
297
411
    if(debug){
298
412
      gpgme_decrypt_result_t result;
299
 
      result = gpgme_op_decrypt_result(mc.ctx);
 
413
      result = gpgme_op_decrypt_result(mc->ctx);
300
414
      if(result == NULL){
301
 
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
415
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
302
416
      } else {
303
 
        fprintf(stderr, "Unsupported algorithm: %s\n",
304
 
                result->unsupported_algorithm);
305
 
        fprintf(stderr, "Wrong key usage: %u\n",
306
 
                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);
307
421
        if(result->file_name != NULL){
308
 
          fprintf(stderr, "File name: %s\n", result->file_name);
 
422
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
309
423
        }
310
424
        gpgme_recipient_t recipient;
311
425
        recipient = result->recipients;
312
426
        while(recipient != NULL){
313
 
          fprintf(stderr, "Public key algorithm: %s\n",
314
 
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
315
 
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
316
 
          fprintf(stderr, "Secret key available: %s\n",
317
 
                  recipient->status == GPG_ERR_NO_SECKEY
318
 
                  ? "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");
319
434
          recipient = recipient->next;
320
435
        }
321
436
      }
324
439
  }
325
440
  
326
441
  if(debug){
327
 
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
 
442
    fprintf_plus(stderr, "Decryption of OpenPGP data succeeded\n");
328
443
  }
329
444
  
330
445
  /* Seek back to the beginning of the GPGME plaintext data buffer */
331
446
  if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
332
 
    perror("gpgme_data_seek");
 
447
    perror_plus("gpgme_data_seek");
333
448
    plaintext_length = -1;
334
449
    goto decrypt_end;
335
450
  }
337
452
  *plaintext = NULL;
338
453
  while(true){
339
454
    plaintext_capacity = incbuffer(plaintext,
340
 
                                      (size_t)plaintext_length,
341
 
                                      plaintext_capacity);
 
455
                                   (size_t)plaintext_length,
 
456
                                   plaintext_capacity);
342
457
    if(plaintext_capacity == 0){
343
 
        perror("incbuffer");
344
 
        plaintext_length = -1;
345
 
        goto decrypt_end;
 
458
      perror_plus("incbuffer");
 
459
      plaintext_length = -1;
 
460
      goto decrypt_end;
346
461
    }
347
462
    
348
463
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
353
468
      break;
354
469
    }
355
470
    if(ret < 0){
356
 
      perror("gpgme_data_read");
 
471
      perror_plus("gpgme_data_read");
357
472
      plaintext_length = -1;
358
473
      goto decrypt_end;
359
474
    }
361
476
  }
362
477
  
363
478
  if(debug){
364
 
    fprintf(stderr, "Decrypted password is: ");
 
479
    fprintf_plus(stderr, "Decrypted password is: ");
365
480
    for(ssize_t i = 0; i < plaintext_length; i++){
366
481
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
367
482
    }
378
493
  return plaintext_length;
379
494
}
380
495
 
381
 
static const char * safer_gnutls_strerror(int value){
382
 
  const char *ret = gnutls_strerror(value); /* Spurious warning from
383
 
                                               -Wunreachable-code */
 
496
__attribute__((warn_unused_result))
 
497
static const char *safer_gnutls_strerror(int value){
 
498
  const char *ret = gnutls_strerror(value);
384
499
  if(ret == NULL)
385
500
    ret = "(unknown)";
386
501
  return ret;
387
502
}
388
503
 
389
504
/* GnuTLS log function callback */
 
505
__attribute__((nonnull))
390
506
static void debuggnutls(__attribute__((unused)) int level,
391
507
                        const char* string){
392
 
  fprintf(stderr, "GnuTLS: %s", string);
 
508
  fprintf_plus(stderr, "GnuTLS: %s", string);
393
509
}
394
510
 
 
511
__attribute__((nonnull, warn_unused_result))
395
512
static int init_gnutls_global(const char *pubkeyfilename,
396
 
                              const char *seckeyfilename){
 
513
                              const char *seckeyfilename,
 
514
                              mandos_context *mc){
397
515
  int ret;
398
516
  
399
517
  if(debug){
400
 
    fprintf(stderr, "Initializing GnuTLS\n");
 
518
    fprintf_plus(stderr, "Initializing GnuTLS\n");
401
519
  }
402
520
  
403
521
  ret = gnutls_global_init();
404
522
  if(ret != GNUTLS_E_SUCCESS){
405
 
    fprintf(stderr, "GnuTLS global_init: %s\n",
406
 
            safer_gnutls_strerror(ret));
 
523
    fprintf_plus(stderr, "GnuTLS global_init: %s\n",
 
524
                 safer_gnutls_strerror(ret));
407
525
    return -1;
408
526
  }
409
527
  
416
534
  }
417
535
  
418
536
  /* OpenPGP credentials */
419
 
  gnutls_certificate_allocate_credentials(&mc.cred);
 
537
  ret = gnutls_certificate_allocate_credentials(&mc->cred);
420
538
  if(ret != GNUTLS_E_SUCCESS){
421
 
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
422
 
                                                    from
423
 
                                                    -Wunreachable-code
424
 
                                                 */
425
 
            safer_gnutls_strerror(ret));
 
539
    fprintf_plus(stderr, "GnuTLS memory error: %s\n",
 
540
                 safer_gnutls_strerror(ret));
426
541
    gnutls_global_deinit();
427
542
    return -1;
428
543
  }
429
544
  
430
545
  if(debug){
431
 
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
432
 
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
433
 
            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);
434
550
  }
435
551
  
436
552
  ret = gnutls_certificate_set_openpgp_key_file
437
 
    (mc.cred, pubkeyfilename, seckeyfilename,
 
553
    (mc->cred, pubkeyfilename, seckeyfilename,
438
554
     GNUTLS_OPENPGP_FMT_BASE64);
439
555
  if(ret != GNUTLS_E_SUCCESS){
440
 
    fprintf(stderr,
441
 
            "Error[%d] while reading the OpenPGP key pair ('%s',"
442
 
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
443
 
    fprintf(stderr, "The GnuTLS error is: %s\n",
444
 
            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));
445
561
    goto globalfail;
446
562
  }
447
563
  
448
564
  /* GnuTLS server initialization */
449
 
  ret = gnutls_dh_params_init(&mc.dh_params);
 
565
  ret = gnutls_dh_params_init(&mc->dh_params);
450
566
  if(ret != GNUTLS_E_SUCCESS){
451
 
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
452
 
            " %s\n", safer_gnutls_strerror(ret));
 
567
    fprintf_plus(stderr, "Error in GnuTLS DH parameter"
 
568
                 " initialization: %s\n",
 
569
                 safer_gnutls_strerror(ret));
453
570
    goto globalfail;
454
571
  }
455
 
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
572
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
456
573
  if(ret != GNUTLS_E_SUCCESS){
457
 
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
458
 
            safer_gnutls_strerror(ret));
 
574
    fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
 
575
                 safer_gnutls_strerror(ret));
459
576
    goto globalfail;
460
577
  }
461
578
  
462
 
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
579
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
463
580
  
464
581
  return 0;
465
582
  
466
583
 globalfail:
467
584
  
468
 
  gnutls_certificate_free_credentials(mc.cred);
 
585
  gnutls_certificate_free_credentials(mc->cred);
469
586
  gnutls_global_deinit();
470
 
  gnutls_dh_params_deinit(mc.dh_params);
 
587
  gnutls_dh_params_deinit(mc->dh_params);
471
588
  return -1;
472
589
}
473
590
 
474
 
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){
475
594
  int ret;
476
595
  /* GnuTLS session creation */
477
 
  ret = gnutls_init(session, GNUTLS_SERVER);
 
596
  do {
 
597
    ret = gnutls_init(session, GNUTLS_SERVER);
 
598
    if(quit_now){
 
599
      return -1;
 
600
    }
 
601
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
478
602
  if(ret != GNUTLS_E_SUCCESS){
479
 
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
480
 
            safer_gnutls_strerror(ret));
 
603
    fprintf_plus(stderr,
 
604
                 "Error in GnuTLS session initialization: %s\n",
 
605
                 safer_gnutls_strerror(ret));
481
606
  }
482
607
  
483
608
  {
484
609
    const char *err;
485
 
    ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
610
    do {
 
611
      ret = gnutls_priority_set_direct(*session, mc->priority, &err);
 
612
      if(quit_now){
 
613
        gnutls_deinit(*session);
 
614
        return -1;
 
615
      }
 
616
    } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
486
617
    if(ret != GNUTLS_E_SUCCESS){
487
 
      fprintf(stderr, "Syntax error at: %s\n", err);
488
 
      fprintf(stderr, "GnuTLS error: %s\n",
489
 
              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));
490
621
      gnutls_deinit(*session);
491
622
      return -1;
492
623
    }
493
624
  }
494
625
  
495
 
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
496
 
                               mc.cred);
 
626
  do {
 
627
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
628
                                 mc->cred);
 
629
    if(quit_now){
 
630
      gnutls_deinit(*session);
 
631
      return -1;
 
632
    }
 
633
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
497
634
  if(ret != GNUTLS_E_SUCCESS){
498
 
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
499
 
            safer_gnutls_strerror(ret));
 
635
    fprintf_plus(stderr, "Error setting GnuTLS credentials: %s\n",
 
636
                 safer_gnutls_strerror(ret));
500
637
    gnutls_deinit(*session);
501
638
    return -1;
502
639
  }
503
640
  
504
641
  /* ignore client certificate if any. */
505
 
  gnutls_certificate_server_set_request(*session,
506
 
                                        GNUTLS_CERT_IGNORE);
 
642
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
507
643
  
508
 
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
 
644
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
509
645
  
510
646
  return 0;
511
647
}
514
650
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
515
651
                      __attribute__((unused)) const char *txt){}
516
652
 
517
 
sig_atomic_t quit_now = 0;
518
 
int signal_received = 0;
519
 
 
520
653
/* Called when a Mandos server is found */
521
 
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,
522
656
                                      AvahiIfIndex if_index,
523
 
                                      int af){
 
657
                                      int af, mandos_context *mc){
524
658
  int ret, tcp_sd = -1;
525
659
  ssize_t sret;
526
 
  union {
527
 
    struct sockaddr_in in;
528
 
    struct sockaddr_in6 in6;
529
 
  } to;
 
660
  struct sockaddr_storage to;
530
661
  char *buffer = NULL;
531
 
  char *decrypted_buffer;
 
662
  char *decrypted_buffer = NULL;
532
663
  size_t buffer_length = 0;
533
664
  size_t buffer_capacity = 0;
534
665
  size_t written;
535
 
  int retval = 0;
 
666
  int retval = -1;
536
667
  gnutls_session_t session;
537
668
  int pf;                       /* Protocol family */
538
669
  
 
670
  errno = 0;
 
671
  
539
672
  if(quit_now){
 
673
    errno = EINTR;
540
674
    return -1;
541
675
  }
542
676
  
548
682
    pf = PF_INET;
549
683
    break;
550
684
  default:
551
 
    fprintf(stderr, "Bad address family: %d\n", af);
 
685
    fprintf_plus(stderr, "Bad address family: %d\n", af);
 
686
    errno = EINVAL;
552
687
    return -1;
553
688
  }
554
689
  
555
 
  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);
556
723
  if(ret != 0){
557
724
    return -1;
558
725
  }
559
726
  
560
727
  if(debug){
561
 
    fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
562
 
            "\n", ip, port);
 
728
    fprintf_plus(stderr, "Setting up a TCP connection to %s, port %"
 
729
                 PRIuMAX "\n", ip, (uintmax_t)port);
563
730
  }
564
731
  
565
732
  tcp_sd = socket(pf, SOCK_STREAM, 0);
566
733
  if(tcp_sd < 0){
567
 
    perror("socket");
568
 
    retval = -1;
 
734
    int e = errno;
 
735
    perror_plus("socket");
 
736
    errno = e;
569
737
    goto mandos_end;
570
738
  }
571
739
  
572
740
  if(quit_now){
 
741
    errno = EINTR;
573
742
    goto mandos_end;
574
743
  }
575
744
  
576
745
  memset(&to, 0, sizeof(to));
577
746
  if(af == AF_INET6){
578
 
    to.in6.sin6_family = (sa_family_t)af;
579
 
    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);
580
749
  } else {                      /* IPv4 */
581
 
    to.in.sin_family = (sa_family_t)af;
582
 
    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);
583
752
  }
584
753
  if(ret < 0 ){
585
 
    perror("inet_pton");
586
 
    retval = -1;
 
754
    int e = errno;
 
755
    perror_plus("inet_pton");
 
756
    errno = e;
587
757
    goto mandos_end;
588
758
  }
589
759
  if(ret == 0){
590
 
    fprintf(stderr, "Bad address: %s\n", ip);
591
 
    retval = -1;
 
760
    int e = errno;
 
761
    fprintf_plus(stderr, "Bad address: %s\n", ip);
 
762
    errno = e;
592
763
    goto mandos_end;
593
764
  }
594
765
  if(af == AF_INET6){
595
 
    to.in6.sin6_port = htons(port); /* Spurious warnings from
596
 
                                       -Wconversion and
597
 
                                       -Wunreachable-code */
598
 
    
599
 
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
600
 
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
601
 
                              -Wunreachable-code*/
 
766
    ((struct sockaddr_in6 *)&to)->sin6_port = htons(port);
 
767
    if(IN6_IS_ADDR_LINKLOCAL
 
768
       (&((struct sockaddr_in6 *)&to)->sin6_addr)){
602
769
      if(if_index == AVAHI_IF_UNSPEC){
603
 
        fprintf(stderr, "An IPv6 link-local address is incomplete"
604
 
                " without a network interface\n");
605
 
        retval = -1;
 
770
        fprintf_plus(stderr, "An IPv6 link-local address is"
 
771
                     " incomplete without a network interface\n");
 
772
        errno = EINVAL;
606
773
        goto mandos_end;
607
774
      }
608
775
      /* Set the network interface number as scope */
609
 
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
776
      ((struct sockaddr_in6 *)&to)->sin6_scope_id = (uint32_t)if_index;
610
777
    }
611
778
  } else {
612
 
    to.in.sin_port = htons(port); /* Spurious warnings from
613
 
                                     -Wconversion and
614
 
                                     -Wunreachable-code */
 
779
    ((struct sockaddr_in *)&to)->sin_port = htons(port);
615
780
  }
616
781
  
617
782
  if(quit_now){
 
783
    errno = EINTR;
618
784
    goto mandos_end;
619
785
  }
620
786
  
622
788
    if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
623
789
      char interface[IF_NAMESIZE];
624
790
      if(if_indextoname((unsigned int)if_index, interface) == NULL){
625
 
        perror("if_indextoname");
 
791
        perror_plus("if_indextoname");
626
792
      } else {
627
 
        fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
628
 
                ip, interface, port);
 
793
        fprintf_plus(stderr, "Connection to: %s%%%s, port %" PRIuMAX
 
794
                     "\n", ip, interface, (uintmax_t)port);
629
795
      }
630
796
    } else {
631
 
      fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
632
 
              port);
 
797
      fprintf_plus(stderr, "Connection to: %s, port %" PRIuMAX "\n",
 
798
                   ip, (uintmax_t)port);
633
799
    }
634
800
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
635
801
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
636
 
    const char *pcret;
637
802
    if(af == AF_INET6){
638
 
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
639
 
                        sizeof(addrstr));
 
803
      ret = getnameinfo((struct sockaddr *)&to,
 
804
                        sizeof(struct sockaddr_in6),
 
805
                        addrstr, sizeof(addrstr), NULL, 0,
 
806
                        NI_NUMERICHOST);
640
807
    } else {
641
 
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
642
 
                        sizeof(addrstr));
 
808
      ret = getnameinfo((struct sockaddr *)&to,
 
809
                        sizeof(struct sockaddr_in),
 
810
                        addrstr, sizeof(addrstr), NULL, 0,
 
811
                        NI_NUMERICHOST);
643
812
    }
644
 
    if(pcret == NULL){
645
 
      perror("inet_ntop");
646
 
    } else {
647
 
      if(strcmp(addrstr, ip) != 0){
648
 
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
649
 
      }
 
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);
650
819
    }
651
820
  }
652
821
  
653
822
  if(quit_now){
 
823
    errno = EINTR;
654
824
    goto mandos_end;
655
825
  }
656
826
  
657
827
  if(af == AF_INET6){
658
 
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
828
    ret = connect(tcp_sd, (struct sockaddr *)&to,
 
829
                  sizeof(struct sockaddr_in6));
659
830
  } else {
660
 
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
831
    ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
832
                  sizeof(struct sockaddr_in));
661
833
  }
662
834
  if(ret < 0){
663
 
    perror("connect");
664
 
    retval = -1;
 
835
    if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
836
      int e = errno;
 
837
      perror_plus("connect");
 
838
      errno = e;
 
839
    }
665
840
    goto mandos_end;
666
841
  }
667
842
  
668
843
  if(quit_now){
 
844
    errno = EINTR;
669
845
    goto mandos_end;
670
846
  }
671
847
  
674
850
  while(true){
675
851
    size_t out_size = strlen(out);
676
852
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
677
 
                                   out_size - written));
 
853
                                        out_size - written));
678
854
    if(ret == -1){
679
 
      perror("write");
680
 
      retval = -1;
 
855
      int e = errno;
 
856
      perror_plus("write");
 
857
      errno = e;
681
858
      goto mandos_end;
682
859
    }
683
860
    written += (size_t)ret;
693
870
    }
694
871
  
695
872
    if(quit_now){
 
873
      errno = EINTR;
696
874
      goto mandos_end;
697
875
    }
698
876
  }
699
877
  
700
878
  if(debug){
701
 
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
879
    fprintf_plus(stderr, "Establishing TLS session with %s\n", ip);
702
880
  }
703
881
  
704
882
  if(quit_now){
 
883
    errno = EINTR;
705
884
    goto mandos_end;
706
885
  }
707
886
  
708
 
  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);
709
892
  
710
893
  if(quit_now){
 
894
    errno = EINTR;
711
895
    goto mandos_end;
712
896
  }
713
897
  
714
898
  do {
715
899
    ret = gnutls_handshake(session);
716
900
    if(quit_now){
 
901
      errno = EINTR;
717
902
      goto mandos_end;
718
903
    }
719
904
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
720
905
  
721
906
  if(ret != GNUTLS_E_SUCCESS){
722
907
    if(debug){
723
 
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
908
      fprintf_plus(stderr, "*** GnuTLS Handshake failed ***\n");
724
909
      gnutls_perror(ret);
725
910
    }
726
 
    retval = -1;
 
911
    errno = EPROTO;
727
912
    goto mandos_end;
728
913
  }
729
914
  
730
915
  /* Read OpenPGP packet that contains the wanted password */
731
916
  
732
917
  if(debug){
733
 
    fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
734
 
            ip);
 
918
    fprintf_plus(stderr, "Retrieving OpenPGP encrypted password from"
 
919
                 " %s\n", ip);
735
920
  }
736
921
  
737
922
  while(true){
738
923
    
739
924
    if(quit_now){
 
925
      errno = EINTR;
740
926
      goto mandos_end;
741
927
    }
742
928
    
743
929
    buffer_capacity = incbuffer(&buffer, buffer_length,
744
 
                                   buffer_capacity);
 
930
                                buffer_capacity);
745
931
    if(buffer_capacity == 0){
746
 
      perror("incbuffer");
747
 
      retval = -1;
 
932
      int e = errno;
 
933
      perror_plus("incbuffer");
 
934
      errno = e;
748
935
      goto mandos_end;
749
936
    }
750
937
    
751
938
    if(quit_now){
 
939
      errno = EINTR;
752
940
      goto mandos_end;
753
941
    }
754
942
    
767
955
          ret = gnutls_handshake(session);
768
956
          
769
957
          if(quit_now){
 
958
            errno = EINTR;
770
959
            goto mandos_end;
771
960
          }
772
961
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
773
962
        if(ret < 0){
774
 
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
963
          fprintf_plus(stderr, "*** GnuTLS Re-handshake failed "
 
964
                       "***\n");
775
965
          gnutls_perror(ret);
776
 
          retval = -1;
 
966
          errno = EPROTO;
777
967
          goto mandos_end;
778
968
        }
779
969
        break;
780
970
      default:
781
 
        fprintf(stderr, "Unknown error while reading data from"
782
 
                " encrypted session with Mandos server\n");
783
 
        retval = -1;
 
971
        fprintf_plus(stderr, "Unknown error while reading data from"
 
972
                     " encrypted session with Mandos server\n");
784
973
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
974
        errno = EIO;
785
975
        goto mandos_end;
786
976
      }
787
977
    } else {
790
980
  }
791
981
  
792
982
  if(debug){
793
 
    fprintf(stderr, "Closing TLS session\n");
794
 
  }
795
 
  
796
 
  if(quit_now){
797
 
    goto mandos_end;
798
 
  }
799
 
  
800
 
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
801
 
  
802
 
  if(quit_now){
803
 
    goto mandos_end;
804
 
  }
 
983
    fprintf_plus(stderr, "Closing TLS session\n");
 
984
  }
 
985
  
 
986
  if(quit_now){
 
987
    errno = EINTR;
 
988
    goto mandos_end;
 
989
  }
 
990
  
 
991
  do {
 
992
    ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
993
    if(quit_now){
 
994
      errno = EINTR;
 
995
      goto mandos_end;
 
996
    }
 
997
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
805
998
  
806
999
  if(buffer_length > 0){
807
1000
    ssize_t decrypted_buffer_size;
808
 
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
809
 
                                               buffer_length,
810
 
                                               &decrypted_buffer);
 
1001
    decrypted_buffer_size = pgp_packet_decrypt(buffer, buffer_length,
 
1002
                                               &decrypted_buffer, mc);
811
1003
    if(decrypted_buffer_size >= 0){
812
1004
      
813
1005
      written = 0;
814
1006
      while(written < (size_t) decrypted_buffer_size){
815
1007
        if(quit_now){
 
1008
          errno = EINTR;
816
1009
          goto mandos_end;
817
1010
        }
818
1011
        
820
1013
                          (size_t)decrypted_buffer_size - written,
821
1014
                          stdout);
822
1015
        if(ret == 0 and ferror(stdout)){
 
1016
          int e = errno;
823
1017
          if(debug){
824
 
            fprintf(stderr, "Error writing encrypted data: %s\n",
825
 
                    strerror(errno));
 
1018
            fprintf_plus(stderr, "Error writing encrypted data: %s\n",
 
1019
                         strerror(errno));
826
1020
          }
827
 
          retval = -1;
828
 
          break;
 
1021
          errno = e;
 
1022
          goto mandos_end;
829
1023
        }
830
1024
        written += (size_t)ret;
831
1025
      }
832
 
      free(decrypted_buffer);
833
 
    } else {
834
 
      retval = -1;
 
1026
      retval = 0;
835
1027
    }
836
 
  } else {
837
 
    retval = -1;
838
1028
  }
839
1029
  
840
1030
  /* Shutdown procedure */
841
1031
  
842
1032
 mandos_end:
843
 
  free(buffer);
844
 
  if(tcp_sd >= 0){
845
 
    ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
846
 
  }
847
 
  if(ret == -1){
848
 
    perror("close");
849
 
  }
850
 
  gnutls_deinit(session);
851
 
  if(quit_now){
852
 
    retval = -1;
 
1033
  {
 
1034
    int e = errno;
 
1035
    free(decrypted_buffer);
 
1036
    free(buffer);
 
1037
    if(tcp_sd >= 0){
 
1038
      ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
 
1039
    }
 
1040
    if(ret == -1){
 
1041
      if(e == 0){
 
1042
        e = errno;
 
1043
      }
 
1044
      perror_plus("close");
 
1045
    }
 
1046
    gnutls_deinit(session);
 
1047
    errno = e;
 
1048
    if(quit_now){
 
1049
      errno = EINTR;
 
1050
      retval = -1;
 
1051
    }
853
1052
  }
854
1053
  return retval;
855
1054
}
856
1055
 
 
1056
__attribute__((nonnull))
857
1057
static void resolve_callback(AvahiSServiceResolver *r,
858
1058
                             AvahiIfIndex interface,
859
1059
                             AvahiProtocol proto,
867
1067
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
868
1068
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
869
1069
                             flags,
870
 
                             AVAHI_GCC_UNUSED void* userdata){
871
 
  assert(r);
 
1070
                             void *mc){
 
1071
  if(r == NULL){
 
1072
    return;
 
1073
  }
872
1074
  
873
1075
  /* Called whenever a service has been resolved successfully or
874
1076
     timed out */
875
1077
  
876
1078
  if(quit_now){
 
1079
    avahi_s_service_resolver_free(r);
877
1080
    return;
878
1081
  }
879
1082
  
880
1083
  switch(event){
881
1084
  default:
882
1085
  case AVAHI_RESOLVER_FAILURE:
883
 
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
884
 
            " of type '%s' in domain '%s': %s\n", name, type, domain,
885
 
            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)));
886
1091
    break;
887
1092
    
888
1093
  case AVAHI_RESOLVER_FOUND:
890
1095
      char ip[AVAHI_ADDRESS_STR_MAX];
891
1096
      avahi_address_snprint(ip, sizeof(ip), address);
892
1097
      if(debug){
893
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
894
 
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
895
 
                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);
896
1101
      }
897
 
      int ret = start_mandos_communication(ip, port, interface,
898
 
                                           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);
899
1106
      if(ret == 0){
900
 
        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
        }
901
1115
      }
902
1116
    }
903
1117
  }
913
1127
                            const char *domain,
914
1128
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
915
1129
                            flags,
916
 
                            AVAHI_GCC_UNUSED void* userdata){
917
 
  assert(b);
 
1130
                            void *mc){
 
1131
  if(b == NULL){
 
1132
    return;
 
1133
  }
918
1134
  
919
1135
  /* Called whenever a new services becomes available on the LAN or
920
1136
     is removed from the LAN */
927
1143
  default:
928
1144
  case AVAHI_BROWSER_FAILURE:
929
1145
    
930
 
    fprintf(stderr, "(Avahi browser) %s\n",
931
 
            avahi_strerror(avahi_server_errno(mc.server)));
932
 
    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);
933
1150
    return;
934
1151
    
935
1152
  case AVAHI_BROWSER_NEW:
938
1155
       the callback function is called the Avahi server will free the
939
1156
       resolver for us. */
940
1157
    
941
 
    if(avahi_s_service_resolver_new(mc.server, interface, protocol,
942
 
                                    name, type, domain, protocol, 0,
943
 
                                    resolve_callback, NULL) == NULL)
944
 
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
945
 
              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)));
946
1166
    break;
947
1167
    
948
1168
  case AVAHI_BROWSER_REMOVE:
951
1171
  case AVAHI_BROWSER_ALL_FOR_NOW:
952
1172
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
953
1173
    if(debug){
954
 
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
1174
      fprintf_plus(stderr, "No Mandos server found, still"
 
1175
                   " searching...\n");
955
1176
    }
956
1177
    break;
957
1178
  }
958
1179
}
959
1180
 
960
 
/* stop main loop after sigterm has been called */
 
1181
/* Signal handler that stops main loop after SIGTERM */
961
1182
static void handle_sigterm(int sig){
962
1183
  if(quit_now){
963
1184
    return;
965
1186
  quit_now = 1;
966
1187
  signal_received = sig;
967
1188
  int old_errno = errno;
968
 
  if(mc.simple_poll != NULL){
969
 
    avahi_simple_poll_quit(mc.simple_poll);
970
 
  }
971
 
  errno = old_errno;
 
1189
  /* set main loop to exit */
 
1190
  if(simple_poll != NULL){
 
1191
    avahi_simple_poll_quit(simple_poll);
 
1192
  }
 
1193
  errno = old_errno;
 
1194
}
 
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
 
 
1264
/* 
 
1265
 * This function determines if a directory entry in /sys/class/net
 
1266
 * corresponds to an acceptable network device.
 
1267
 * (This function is passed to scandir(3) as a filter function.)
 
1268
 */
 
1269
__attribute__((nonnull, warn_unused_result))
 
1270
int good_interface(const struct dirent *if_entry){
 
1271
  if(if_entry->d_name[0] == '.'){
 
1272
    return 0;
 
1273
  }
 
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)){
 
1809
      break;
 
1810
    }
 
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;
972
1895
}
973
1896
 
974
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 };
975
1902
  AvahiSServiceBrowser *sb = NULL;
976
 
  int error;
 
1903
  error_t ret_errno;
977
1904
  int ret;
978
1905
  intmax_t tmpmax;
979
1906
  char *tmp;
980
1907
  int exitcode = EXIT_SUCCESS;
981
 
  const char *interface = "eth0";
982
 
  struct ifreq network;
983
 
  int sd = -1;
984
 
  bool take_down_interface = false;
985
 
  uid_t uid;
986
 
  gid_t gid;
987
 
  char *connect_to = NULL;
988
 
  char tempdir[] = "/tmp/mandosXXXXXX";
989
 
  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;
990
1913
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
991
1914
  const char *seckey = PATHDIR "/" SECKEY;
992
1915
  const char *pubkey = PATHDIR "/" PUBKEY;
 
1916
  char *interfaces_hooks = NULL;
993
1917
  
994
1918
  bool gnutls_initialized = false;
995
1919
  bool gpgme_initialized = false;
996
1920
  float delay = 2.5f;
 
1921
  double retry_interval = 10; /* 10s between trying a server and
 
1922
                                 retrying the same server again */
997
1923
  
998
 
  struct sigaction old_sigterm_action;
 
1924
  struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
999
1925
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1000
1926
  
 
1927
  uid = getuid();
 
1928
  gid = getgid();
 
1929
  
 
1930
  /* Lower any group privileges we might have, just to be safe */
 
1931
  errno = 0;
 
1932
  ret = setgid(gid);
 
1933
  if(ret == -1){
 
1934
    perror_plus("setgid");
 
1935
  }
 
1936
  
 
1937
  /* Lower user privileges (temporarily) */
 
1938
  errno = 0;
 
1939
  ret = seteuid(uid);
 
1940
  if(ret == -1){
 
1941
    perror_plus("seteuid");
 
1942
  }
 
1943
  
 
1944
  if(quit_now){
 
1945
    goto end;
 
1946
  }
 
1947
  
1001
1948
  {
1002
1949
    struct argp_option options[] = {
1003
1950
      { .name = "debug", .key = 128,
1032
1979
        .arg = "SECONDS",
1033
1980
        .doc = "Maximum delay to wait for interface startup",
1034
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 },
 
1990
      /*
 
1991
       * These reproduce what we would get without ARGP_NO_HELP
 
1992
       */
 
1993
      { .name = "help", .key = '?',
 
1994
        .doc = "Give this help list", .group = -1 },
 
1995
      { .name = "usage", .key = -3,
 
1996
        .doc = "Give a short usage message", .group = -1 },
 
1997
      { .name = "version", .key = 'V',
 
1998
        .doc = "Print program version", .group = -1 },
1035
1999
      { .name = NULL }
1036
2000
    };
1037
2001
    
1038
2002
    error_t parse_opt(int key, char *arg,
1039
2003
                      struct argp_state *state){
 
2004
      errno = 0;
1040
2005
      switch(key){
1041
2006
      case 128:                 /* --debug */
1042
2007
        debug = true;
1045
2010
        connect_to = arg;
1046
2011
        break;
1047
2012
      case 'i':                 /* --interface */
1048
 
        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
        }
1049
2018
        break;
1050
2019
      case 's':                 /* --seckey */
1051
2020
        seckey = arg;
1058
2027
        tmpmax = strtoimax(arg, &tmp, 10);
1059
2028
        if(errno != 0 or tmp == arg or *tmp != '\0'
1060
2029
           or tmpmax != (typeof(mc.dh_bits))tmpmax){
1061
 
          fprintf(stderr, "Bad number of DH bits\n");
1062
 
          exit(EXIT_FAILURE);
 
2030
          argp_error(state, "Bad number of DH bits");
1063
2031
        }
1064
2032
        mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1065
2033
        break;
1070
2038
        errno = 0;
1071
2039
        delay = strtof(arg, &tmp);
1072
2040
        if(errno != 0 or tmp == arg or *tmp != '\0'){
1073
 
          fprintf(stderr, "Bad delay\n");
1074
 
          exit(EXIT_FAILURE);
1075
 
        }
1076
 
        break;
1077
 
      case ARGP_KEY_ARG:
1078
 
        argp_usage(state);
1079
 
      case ARGP_KEY_END:
 
2041
          argp_error(state, "Bad delay");
 
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;
 
2054
        break;
 
2055
        /*
 
2056
         * These reproduce what we would get without ARGP_NO_HELP
 
2057
         */
 
2058
      case '?':                 /* --help */
 
2059
        argp_state_help(state, state->out_stream,
 
2060
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
 
2061
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
2062
      case -3:                  /* --usage */
 
2063
        argp_state_help(state, state->out_stream,
 
2064
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
2065
      case 'V':                 /* --version */
 
2066
        fprintf_plus(state->out_stream, "%s\n", argp_program_version);
 
2067
        exit(argp_err_exit_status);
1080
2068
        break;
1081
2069
      default:
1082
2070
        return ARGP_ERR_UNKNOWN;
1083
2071
      }
1084
 
      return 0;
 
2072
      return errno;
1085
2073
    }
1086
2074
    
1087
2075
    struct argp argp = { .options = options, .parser = parse_opt,
1088
2076
                         .args_doc = "",
1089
2077
                         .doc = "Mandos client -- Get and decrypt"
1090
2078
                         " passwords from a Mandos server" };
1091
 
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
1092
 
    if(ret == ARGP_ERR_UNKNOWN){
1093
 
      fprintf(stderr, "Unknown error while parsing arguments\n");
1094
 
      exitcode = EXIT_FAILURE;
1095
 
      goto end;
1096
 
    }
 
2079
    ret = argp_parse(&argp, argc, argv,
 
2080
                     ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
 
2081
    switch(ret){
 
2082
    case 0:
 
2083
      break;
 
2084
    case ENOMEM:
 
2085
    default:
 
2086
      errno = ret;
 
2087
      perror_plus("argp_parse");
 
2088
      exitcode = EX_OSERR;
 
2089
      goto end;
 
2090
    case EINVAL:
 
2091
      exitcode = EX_USAGE;
 
2092
      goto end;
 
2093
    }
 
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);
1097
2189
  }
1098
2190
  
1099
2191
  if(not debug){
1104
2196
     from the signal handler */
1105
2197
  /* Initialize the pseudo-RNG for Avahi */
1106
2198
  srand((unsigned int) time(NULL));
1107
 
  mc.simple_poll = avahi_simple_poll_new();
1108
 
  if(mc.simple_poll == NULL){
1109
 
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1110
 
    exitcode = EXIT_FAILURE;
 
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");
 
2203
    exitcode = EX_UNAVAILABLE;
1111
2204
    goto end;
1112
2205
  }
1113
2206
  
1114
2207
  sigemptyset(&sigterm_action.sa_mask);
1115
2208
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1116
2209
  if(ret == -1){
1117
 
    perror("sigaddset");
1118
 
    exitcode = EXIT_FAILURE;
 
2210
    perror_plus("sigaddset");
 
2211
    exitcode = EX_OSERR;
1119
2212
    goto end;
1120
2213
  }
1121
2214
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1122
2215
  if(ret == -1){
1123
 
    perror("sigaddset");
1124
 
    exitcode = EXIT_FAILURE;
 
2216
    perror_plus("sigaddset");
 
2217
    exitcode = EX_OSERR;
1125
2218
    goto end;
1126
2219
  }
1127
2220
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1128
2221
  if(ret == -1){
1129
 
    perror("sigaddset");
1130
 
    exitcode = EXIT_FAILURE;
 
2222
    perror_plus("sigaddset");
 
2223
    exitcode = EX_OSERR;
1131
2224
    goto end;
1132
2225
  }
1133
2226
  /* Need to check if the handler is SIG_IGN before handling:
1136
2229
  */
1137
2230
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1138
2231
  if(ret == -1){
1139
 
    perror("sigaction");
1140
 
    return EXIT_FAILURE;
 
2232
    perror_plus("sigaction");
 
2233
    return EX_OSERR;
1141
2234
  }
1142
2235
  if(old_sigterm_action.sa_handler != SIG_IGN){
1143
2236
    ret = sigaction(SIGINT, &sigterm_action, NULL);
1144
2237
    if(ret == -1){
1145
 
      perror("sigaction");
1146
 
      exitcode = EXIT_FAILURE;
 
2238
      perror_plus("sigaction");
 
2239
      exitcode = EX_OSERR;
1147
2240
      goto end;
1148
2241
    }
1149
2242
  }
1150
2243
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1151
2244
  if(ret == -1){
1152
 
    perror("sigaction");
1153
 
    return EXIT_FAILURE;
 
2245
    perror_plus("sigaction");
 
2246
    return EX_OSERR;
1154
2247
  }
1155
2248
  if(old_sigterm_action.sa_handler != SIG_IGN){
1156
2249
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
1157
2250
    if(ret == -1){
1158
 
      perror("sigaction");
1159
 
      exitcode = EXIT_FAILURE;
 
2251
      perror_plus("sigaction");
 
2252
      exitcode = EX_OSERR;
1160
2253
      goto end;
1161
2254
    }
1162
2255
  }
1163
2256
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1164
2257
  if(ret == -1){
1165
 
    perror("sigaction");
1166
 
    return EXIT_FAILURE;
 
2258
    perror_plus("sigaction");
 
2259
    return EX_OSERR;
1167
2260
  }
1168
2261
  if(old_sigterm_action.sa_handler != SIG_IGN){
1169
2262
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
1170
2263
    if(ret == -1){
1171
 
      perror("sigaction");
1172
 
      exitcode = EXIT_FAILURE;
1173
 
      goto end;
1174
 
    }
1175
 
  }
1176
 
  
1177
 
  /* If the interface is down, bring it up */
1178
 
  if(interface[0] != '\0'){
1179
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1180
 
    if(if_index == 0){
1181
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1182
 
      exitcode = EXIT_FAILURE;
1183
 
      goto end;
1184
 
    }
1185
 
    
1186
 
    if(quit_now){
1187
 
      goto end;
1188
 
    }
1189
 
    
1190
 
#ifdef __linux__
1191
 
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1192
 
       messages to mess up the prompt */
1193
 
    ret = klogctl(8, NULL, 5);
1194
 
    bool restore_loglevel = true;
1195
 
    if(ret == -1){
1196
 
      restore_loglevel = false;
1197
 
      perror("klogctl");
1198
 
    }
1199
 
#endif  /* __linux__ */
1200
 
    
1201
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1202
 
    if(sd < 0){
1203
 
      perror("socket");
1204
 
      exitcode = EXIT_FAILURE;
1205
 
#ifdef __linux__
1206
 
      if(restore_loglevel){
1207
 
        ret = klogctl(7, NULL, 0);
1208
 
        if(ret == -1){
1209
 
          perror("klogctl");
1210
 
        }
1211
 
      }
1212
 
#endif  /* __linux__ */
1213
 
      goto end;
1214
 
    }
1215
 
    strcpy(network.ifr_name, interface);
1216
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
1217
 
    if(ret == -1){
1218
 
      perror("ioctl SIOCGIFFLAGS");
1219
 
#ifdef __linux__
1220
 
      if(restore_loglevel){
1221
 
        ret = klogctl(7, NULL, 0);
1222
 
        if(ret == -1){
1223
 
          perror("klogctl");
1224
 
        }
1225
 
      }
1226
 
#endif  /* __linux__ */
1227
 
      exitcode = EXIT_FAILURE;
1228
 
      goto end;
1229
 
    }
1230
 
    if((network.ifr_flags & IFF_UP) == 0){
1231
 
      network.ifr_flags |= IFF_UP;
1232
 
      take_down_interface = true;
1233
 
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
1234
 
      if(ret == -1){
1235
 
        take_down_interface = false;
1236
 
        perror("ioctl SIOCSIFFLAGS");
1237
 
        exitcode = EXIT_FAILURE;
1238
 
#ifdef __linux__
1239
 
        if(restore_loglevel){
1240
 
          ret = klogctl(7, NULL, 0);
1241
 
          if(ret == -1){
1242
 
            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;
1243
2321
          }
1244
2322
        }
1245
 
#endif  /* __linux__ */
1246
 
        goto end;
1247
 
      }
1248
 
    }
1249
 
    /* sleep checking until interface is running */
1250
 
    for(int i=0; i < delay * 4; i++){
1251
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1252
 
      if(ret == -1){
1253
 
        perror("ioctl SIOCGIFFLAGS");
1254
 
      } else if(network.ifr_flags & IFF_RUNNING){
1255
2323
        break;
1256
2324
      }
1257
 
      struct timespec sleeptime = { .tv_nsec = 250000000 };
1258
 
      ret = nanosleep(&sleeptime, NULL);
1259
 
      if(ret == -1 and errno != EINTR){
1260
 
        perror("nanosleep");
1261
 
      }
1262
 
    }
1263
 
    if(not take_down_interface){
1264
 
      /* We won't need the socket anymore */
1265
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1266
 
      if(ret == -1){
1267
 
        perror("close");
1268
 
      }
1269
 
    }
1270
 
#ifdef __linux__
1271
 
    if(restore_loglevel){
1272
 
      /* Restores kernel loglevel to default */
1273
 
      ret = klogctl(7, NULL, 0);
1274
 
      if(ret == -1){
1275
 
        perror("klogctl");
1276
 
      }
1277
 
    }
1278
 
#endif  /* __linux__ */
1279
 
  }
1280
 
  
1281
 
  if(quit_now){
1282
 
    goto end;
1283
 
  }
1284
 
  
1285
 
  uid = getuid();
1286
 
  gid = getgid();
1287
 
  
1288
 
  /* Drop any group privileges we might have, just to be safe */
1289
 
  errno = 0;
1290
 
  ret = setgid(gid);
1291
 
  if(ret == -1){
1292
 
    perror("setgid");
1293
 
  }
1294
 
  
1295
 
  /* Drop user privileges */
1296
 
  errno = 0;
1297
 
  /* Will we need privileges later? */
1298
 
  if(take_down_interface){
1299
 
    /* Drop user privileges temporarily */
1300
 
    ret = seteuid(uid);
1301
 
    if(ret == -1){
1302
 
      perror("seteuid");
1303
 
    }
1304
 
  } else {
1305
 
    /* Drop user privileges permanently */
1306
 
    ret = setuid(uid);
1307
 
    if(ret == -1){
1308
 
      perror("setuid");
1309
 
    }
1310
 
  }
1311
 
  
1312
 
  if(quit_now){
1313
 
    goto end;
1314
 
  }
1315
 
  
1316
 
  ret = init_gnutls_global(pubkey, seckey);
1317
 
  if(ret == -1){
1318
 
    fprintf(stderr, "init_gnutls_global failed\n");
1319
 
    exitcode = EXIT_FAILURE;
 
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);
 
2352
  }
 
2353
  
 
2354
  if(quit_now){
 
2355
    goto end;
 
2356
  }
 
2357
  
 
2358
  ret = init_gnutls_global(pubkey, seckey, &mc);
 
2359
  if(ret == -1){
 
2360
    fprintf_plus(stderr, "init_gnutls_global failed\n");
 
2361
    exitcode = EX_UNAVAILABLE;
1320
2362
    goto end;
1321
2363
  } else {
1322
2364
    gnutls_initialized = true;
1326
2368
    goto end;
1327
2369
  }
1328
2370
  
1329
 
  tempdir_created = true;
1330
 
  if(mkdtemp(tempdir) == NULL){
1331
 
    tempdir_created = false;
1332
 
    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");
1333
2382
    goto end;
1334
2383
  }
1335
2384
  
1337
2386
    goto end;
1338
2387
  }
1339
2388
  
1340
 
  if(not init_gpgme(pubkey, seckey, tempdir)){
1341
 
    fprintf(stderr, "init_gpgme failed\n");
1342
 
    exitcode = EXIT_FAILURE;
 
2389
  if(not init_gpgme(pubkey, seckey, tempdir, &mc)){
 
2390
    fprintf_plus(stderr, "init_gpgme failed\n");
 
2391
    exitcode = EX_UNAVAILABLE;
1343
2392
    goto end;
1344
2393
  } else {
1345
2394
    gpgme_initialized = true;
1353
2402
    /* Connect directly, do not use Zeroconf */
1354
2403
    /* (Mainly meant for debugging) */
1355
2404
    char *address = strrchr(connect_to, ':');
 
2405
    
1356
2406
    if(address == NULL){
1357
 
      fprintf(stderr, "No colon in address\n");
1358
 
      exitcode = EXIT_FAILURE;
 
2407
      fprintf_plus(stderr, "No colon in address\n");
 
2408
      exitcode = EX_USAGE;
1359
2409
      goto end;
1360
2410
    }
1361
2411
    
1363
2413
      goto end;
1364
2414
    }
1365
2415
    
1366
 
    uint16_t port;
 
2416
    in_port_t port;
1367
2417
    errno = 0;
1368
2418
    tmpmax = strtoimax(address+1, &tmp, 10);
1369
2419
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
1370
 
       or tmpmax != (uint16_t)tmpmax){
1371
 
      fprintf(stderr, "Bad port number\n");
1372
 
      exitcode = EXIT_FAILURE;
 
2420
       or tmpmax != (in_port_t)tmpmax){
 
2421
      fprintf_plus(stderr, "Bad port number\n");
 
2422
      exitcode = EX_USAGE;
1373
2423
      goto end;
1374
2424
    }
1375
 
  
 
2425
    
1376
2426
    if(quit_now){
1377
2427
      goto end;
1378
2428
    }
1379
2429
    
1380
 
    port = (uint16_t)tmpmax;
 
2430
    port = (in_port_t)tmpmax;
1381
2431
    *address = '\0';
1382
 
    address = connect_to;
1383
2432
    /* Colon in address indicates IPv6 */
1384
2433
    int af;
1385
 
    if(strchr(address, ':') != NULL){
 
2434
    if(strchr(connect_to, ':') != NULL){
1386
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
        }
1387
2442
    } else {
1388
2443
      af = AF_INET;
1389
2444
    }
 
2445
    address = connect_to;
1390
2446
    
1391
2447
    if(quit_now){
1392
2448
      goto end;
1393
2449
    }
1394
2450
    
1395
 
    ret = start_mandos_communication(address, port, if_index, af);
1396
 
    if(ret < 0){
1397
 
      exitcode = EXIT_FAILURE;
1398
 
    } else {
 
2451
    while(not quit_now){
 
2452
      ret = start_mandos_communication(address, port, if_index, af,
 
2453
                                       &mc);
 
2454
      if(quit_now or ret == 0){
 
2455
        break;
 
2456
      }
 
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){
1399
2465
      exitcode = EXIT_SUCCESS;
1400
2466
    }
 
2467
    
1401
2468
    goto end;
1402
2469
  }
1403
2470
  
1415
2482
    config.publish_domain = 0;
1416
2483
    
1417
2484
    /* Allocate a new server */
1418
 
    mc.server = avahi_server_new(avahi_simple_poll_get
1419
 
                                 (mc.simple_poll), &config, NULL,
1420
 
                                 NULL, &error);
 
2485
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
2486
                                 &config, NULL, NULL, &ret_errno);
1421
2487
    
1422
2488
    /* Free the Avahi configuration data */
1423
2489
    avahi_server_config_free(&config);
1425
2491
  
1426
2492
  /* Check if creating the Avahi server object succeeded */
1427
2493
  if(mc.server == NULL){
1428
 
    fprintf(stderr, "Failed to create Avahi server: %s\n",
1429
 
            avahi_strerror(error));
1430
 
    exitcode = EXIT_FAILURE;
 
2494
    fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
 
2495
                 avahi_strerror(ret_errno));
 
2496
    exitcode = EX_UNAVAILABLE;
1431
2497
    goto end;
1432
2498
  }
1433
2499
  
1438
2504
  /* Create the Avahi service browser */
1439
2505
  sb = avahi_s_service_browser_new(mc.server, if_index,
1440
2506
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1441
 
                                   NULL, 0, browse_callback, NULL);
 
2507
                                   NULL, 0, browse_callback,
 
2508
                                   (void *)&mc);
1442
2509
  if(sb == NULL){
1443
 
    fprintf(stderr, "Failed to create service browser: %s\n",
1444
 
            avahi_strerror(avahi_server_errno(mc.server)));
1445
 
    exitcode = EXIT_FAILURE;
 
2510
    fprintf_plus(stderr, "Failed to create service browser: %s\n",
 
2511
                 avahi_strerror(avahi_server_errno(mc.server)));
 
2512
    exitcode = EX_UNAVAILABLE;
1446
2513
    goto end;
1447
2514
  }
1448
2515
  
1453
2520
  /* Run the main loop */
1454
2521
  
1455
2522
  if(debug){
1456
 
    fprintf(stderr, "Starting Avahi loop search\n");
 
2523
    fprintf_plus(stderr, "Starting Avahi loop search\n");
1457
2524
  }
1458
2525
  
1459
 
  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
  }
1460
2532
  
1461
2533
 end:
1462
2534
  
1463
2535
  if(debug){
1464
 
    fprintf(stderr, "%s exiting\n", argv[0]);
 
2536
    fprintf_plus(stderr, "%s exiting\n", argv[0]);
1465
2537
  }
1466
2538
  
1467
2539
  /* Cleanup things */
 
2540
  free(mc.interfaces);
 
2541
  
1468
2542
  if(sb != NULL)
1469
2543
    avahi_s_service_browser_free(sb);
1470
2544
  
1471
2545
  if(mc.server != NULL)
1472
2546
    avahi_server_free(mc.server);
1473
2547
  
1474
 
  if(mc.simple_poll != NULL)
1475
 
    avahi_simple_poll_free(mc.simple_poll);
 
2548
  if(simple_poll != NULL)
 
2549
    avahi_simple_poll_free(simple_poll);
1476
2550
  
1477
2551
  if(gnutls_initialized){
1478
2552
    gnutls_certificate_free_credentials(mc.cred);
1484
2558
    gpgme_release(mc.ctx);
1485
2559
  }
1486
2560
  
1487
 
  /* Take down the network interface */
1488
 
  if(take_down_interface){
1489
 
    /* Re-raise priviliges */
1490
 
    errno = 0;
1491
 
    ret = seteuid(0);
1492
 
    if(ret == -1){
1493
 
      perror("seteuid");
1494
 
    }
1495
 
    if(geteuid() == 0){
1496
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
1497
 
      if(ret == -1){
1498
 
        perror("ioctl SIOCGIFFLAGS");
1499
 
      } else if(network.ifr_flags & IFF_UP) {
1500
 
        network.ifr_flags &= ~IFF_UP; /* clear flag */
1501
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
1502
 
        if(ret == -1){
1503
 
          perror("ioctl SIOCSIFFLAGS");
1504
 
        }
1505
 
      }
1506
 
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1507
 
      if(ret == -1){
1508
 
        perror("close");
1509
 
      }
1510
 
      /* Lower privileges, permanently this time */
1511
 
      errno = 0;
1512
 
      ret = setuid(uid);
1513
 
      if(ret == -1){
1514
 
        perror("setuid");
1515
 
      }
1516
 
    }
1517
 
  }
1518
 
  
1519
 
  /* Removes the temp directory used by GPGME */
1520
 
  if(tempdir_created){
1521
 
    DIR *d;
1522
 
    struct dirent *direntry;
1523
 
    d = opendir(tempdir);
1524
 
    if(d == NULL){
1525
 
      if(errno != ENOENT){
1526
 
        perror("opendir");
1527
 
      }
1528
 
    } else {
1529
 
      while(true){
1530
 
        direntry = readdir(d);
1531
 
        if(direntry == NULL){
1532
 
          break;
1533
 
        }
1534
 
        /* Skip "." and ".." */
1535
 
        if(direntry->d_name[0] == '.'
1536
 
           and (direntry->d_name[1] == '\0'
1537
 
                or (direntry->d_name[1] == '.'
1538
 
                    and direntry->d_name[2] == '\0'))){
1539
 
          continue;
1540
 
        }
1541
 
        char *fullname = NULL;
1542
 
        ret = asprintf(&fullname, "%s/%s", tempdir,
1543
 
                       direntry->d_name);
1544
 
        if(ret < 0){
1545
 
          perror("asprintf");
1546
 
          continue;
1547
 
        }
1548
 
        ret = remove(fullname);
1549
 
        if(ret == -1){
1550
 
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1551
 
                  strerror(errno));
1552
 
        }
1553
 
        free(fullname);
1554
 
      }
1555
 
      closedir(d);
1556
 
    }
1557
 
    ret = rmdir(tempdir);
1558
 
    if(ret == -1 and errno != ENOENT){
1559
 
      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));
1560
2663
    }
1561
2664
  }
1562
2665
  
1563
2666
  if(quit_now){
1564
2667
    sigemptyset(&old_sigterm_action.sa_mask);
1565
2668
    old_sigterm_action.sa_handler = SIG_DFL;
1566
 
    ret = sigaction(signal_received, &old_sigterm_action, NULL);
 
2669
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
 
2670
                                            &old_sigterm_action,
 
2671
                                            NULL));
1567
2672
    if(ret == -1){
1568
 
      perror("sigaction");
1569
 
    }
1570
 
    raise(signal_received);
 
2673
      perror_plus("sigaction");
 
2674
    }
 
2675
    do {
 
2676
      ret = raise(signal_received);
 
2677
    } while(ret != 0 and errno == EINTR);
 
2678
    if(ret != 0){
 
2679
      perror_plus("raise");
 
2680
      abort();
 
2681
    }
 
2682
    TEMP_FAILURE_RETRY(pause());
1571
2683
  }
1572
2684
  
1573
2685
  return exitcode;