/mandos/trunk

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

« back to all changes in this revision

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

* plugins.d/mandos-client.c (good_interface): Use SIOCGIFFLAGS instead
                                              of reading
                                              /sys/class/net/*/flags.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Mandos client - get and decrypt data from a Mandos server
 
3
 * Mandos-client - get and decrypt data from a Mandos server
4
4
 *
5
5
 * This program is partly derived from an example program for an Avahi
6
6
 * service browser, downloaded from
8
8
 * includes the following functions: "resolve_callback",
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
 
 * Everything else is Copyright © 2007-2008 Teddy Hogeborn and Björn
12
 
 * Påhlsson.
 
11
 * Everything else is
 
12
 * Copyright © 2008-2011 Teddy Hogeborn
 
13
 * Copyright © 2008-2011 Björn Påhlsson
13
14
 * 
14
15
 * This program is free software: you can redistribute it and/or
15
16
 * modify it under the terms of the GNU General Public License as
25
26
 * along with this program.  If not, see
26
27
 * <http://www.gnu.org/licenses/>.
27
28
 * 
28
 
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
29
 
 * <https://www.fukt.bsnet.se/~teddy/>.
 
29
 * Contact the authors at <mandos@recompile.se>.
30
30
 */
31
31
 
32
 
#define _FORTIFY_SOURCE 2
33
 
 
 
32
/* Needed by GPGME, specifically gpgme_data_seek() */
 
33
#ifndef _LARGEFILE_SOURCE
34
34
#define _LARGEFILE_SOURCE
 
35
#endif
 
36
#ifndef _FILE_OFFSET_BITS
35
37
#define _FILE_OFFSET_BITS 64
36
 
 
37
 
#include <stdio.h>
38
 
#include <assert.h>
39
 
#include <stdlib.h>
40
 
#include <time.h>
41
 
#include <net/if.h>             /* if_nametoindex */
42
 
 
 
38
#endif
 
39
 
 
40
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
 
41
 
 
42
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
 
43
                                   stdout, ferror(), remove() */
 
44
#include <stdint.h>             /* uint16_t, uint32_t */
 
45
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
 
47
                                   strtof(), abort() */
 
48
#include <stdbool.h>            /* bool, false, true */
 
49
#include <string.h>             /* memset(), strcmp(), strlen(),
 
50
                                   strerror(), asprintf(), strcpy() */
 
51
#include <sys/ioctl.h>          /* ioctl */
 
52
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
 
53
                                   sockaddr_in6, PF_INET6,
 
54
                                   SOCK_STREAM, uid_t, gid_t, open(),
 
55
                                   opendir(), DIR */
 
56
#include <sys/stat.h>           /* open() */
 
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
58
                                   inet_pton(), connect() */
 
59
#include <fcntl.h>              /* open() */
 
60
#include <dirent.h>             /* opendir(), struct dirent, readdir()
 
61
                                 */
 
62
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
 
63
                                   strtoimax() */
 
64
#include <assert.h>             /* assert() */
 
65
#include <errno.h>              /* perror(), errno,
 
66
                                   program_invocation_short_name */
 
67
#include <time.h>               /* nanosleep(), time(), sleep() */
 
68
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
 
69
                                   SIOCSIFFLAGS, if_indextoname(),
 
70
                                   if_nametoindex(), IF_NAMESIZE */
 
71
#include <netinet/in.h>         /* IN6_IS_ADDR_LINKLOCAL,
 
72
                                   INET_ADDRSTRLEN, INET6_ADDRSTRLEN
 
73
                                */
 
74
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
 
75
                                   getuid(), getgid(), seteuid(),
 
76
                                   setgid(), pause() */
 
77
#include <arpa/inet.h>          /* inet_pton(), htons, inet_ntop() */
 
78
#include <iso646.h>             /* not, or, and */
 
79
#include <argp.h>               /* struct argp_option, error_t, struct
 
80
                                   argp_state, struct argp,
 
81
                                   argp_parse(), ARGP_KEY_ARG,
 
82
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
 
83
#include <signal.h>             /* sigemptyset(), sigaddset(),
 
84
                                   sigaction(), SIGTERM, sig_atomic_t,
 
85
                                   raise() */
 
86
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
 
87
                                   EX_NOHOST, EX_IOERR, EX_PROTOCOL */
 
88
 
 
89
#ifdef __linux__
 
90
#include <sys/klog.h>           /* klogctl() */
 
91
#endif  /* __linux__ */
 
92
 
 
93
/* Avahi */
 
94
/* All Avahi types, constants and functions
 
95
 Avahi*, avahi_*,
 
96
 AVAHI_* */
43
97
#include <avahi-core/core.h>
44
98
#include <avahi-core/lookup.h>
45
99
#include <avahi-core/log.h>
47
101
#include <avahi-common/malloc.h>
48
102
#include <avahi-common/error.h>
49
103
 
50
 
//mandos client part
51
 
#include <sys/types.h>          /* socket(), inet_pton() */
52
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
53
 
                                   struct in6_addr, inet_pton() */
54
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
55
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
56
 
 
57
 
#include <unistd.h>             /* close() */
58
 
#include <netinet/in.h>
59
 
#include <stdbool.h>            /* true */
60
 
#include <string.h>             /* memset */
61
 
#include <arpa/inet.h>          /* inet_pton() */
62
 
#include <iso646.h>             /* not */
63
 
 
64
 
// gpgme
65
 
#include <errno.h>              /* perror() */
66
 
#include <gpgme.h>
67
 
 
68
 
// getopt long
69
 
#include <getopt.h>
70
 
 
71
 
#ifndef CERT_ROOT
72
 
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
73
 
#endif
74
 
#define CERTFILE CERT_ROOT "openpgp-client.txt"
75
 
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
 
104
/* GnuTLS */
 
105
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and
 
106
                                   functions:
 
107
                                   gnutls_*
 
108
                                   init_gnutls_session(),
 
109
                                   GNUTLS_* */
 
110
#include <gnutls/openpgp.h>
 
111
                          /* gnutls_certificate_set_openpgp_key_file(),
 
112
                                   GNUTLS_OPENPGP_FMT_BASE64 */
 
113
 
 
114
/* GPGME */
 
115
#include <gpgme.h>              /* All GPGME types, constants and
 
116
                                   functions:
 
117
                                   gpgme_*
 
118
                                   GPGME_PROTOCOL_OpenPGP,
 
119
                                   GPG_ERR_NO_* */
 
120
 
76
121
#define BUFFER_SIZE 256
77
 
#define DH_BITS 1024
 
122
 
 
123
#define PATHDIR "/conf/conf.d/mandos"
 
124
#define SECKEY "seckey.txt"
 
125
#define PUBKEY "pubkey.txt"
78
126
 
79
127
bool debug = false;
80
 
 
 
128
static const char mandos_protocol_version[] = "1";
 
129
const char *argp_program_version = "mandos-client " VERSION;
 
130
const char *argp_program_bug_address = "<mandos@recompile.se>";
 
131
static const char sys_class_net[] = "/sys/class/net";
 
132
char *connect_to = NULL;
 
133
 
 
134
/* Doubly linked list that need to be circularly linked when used */
 
135
typedef struct server{
 
136
  const char *ip;
 
137
  uint16_t port;
 
138
  AvahiIfIndex if_index;
 
139
  int af;
 
140
  struct timespec last_seen;
 
141
  struct server *next;
 
142
  struct server *prev;
 
143
} server;
 
144
 
 
145
/* Used for passing in values through the Avahi callback functions */
81
146
typedef struct {
82
 
  gnutls_session_t session;
 
147
  AvahiSimplePoll *simple_poll;
 
148
  AvahiServer *server;
83
149
  gnutls_certificate_credentials_t cred;
 
150
  unsigned int dh_bits;
84
151
  gnutls_dh_params_t dh_params;
85
 
} encrypted_session;
86
 
 
87
 
 
88
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
89
 
                            char **new_packet, const char *homedir){
90
 
  gpgme_data_t dh_crypto, dh_plain;
 
152
  const char *priority;
91
153
  gpgme_ctx_t ctx;
 
154
  server *current_server;
 
155
} mandos_context;
 
156
 
 
157
/* global context so signal handler can reach it*/
 
158
mandos_context mc = { .simple_poll = NULL, .server = NULL,
 
159
                      .dh_bits = 1024, .priority = "SECURE256"
 
160
                      ":!CTYPE-X.509:+CTYPE-OPENPGP",
 
161
                      .current_server = NULL };
 
162
 
 
163
sig_atomic_t quit_now = 0;
 
164
int signal_received = 0;
 
165
 
 
166
/* Function to use when printing errors */
 
167
void perror_plus(const char *print_text){
 
168
  fprintf(stderr, "Mandos plugin %s: ",
 
169
          program_invocation_short_name);
 
170
  perror(print_text);
 
171
}
 
172
 
 
173
/*
 
174
 * Make additional room in "buffer" for at least BUFFER_SIZE more
 
175
 * bytes. "buffer_capacity" is how much is currently allocated,
 
176
 * "buffer_length" is how much is already used.
 
177
 */
 
178
size_t incbuffer(char **buffer, size_t buffer_length,
 
179
                  size_t buffer_capacity){
 
180
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
 
181
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
 
182
    if(buffer == NULL){
 
183
      return 0;
 
184
    }
 
185
    buffer_capacity += BUFFER_SIZE;
 
186
  }
 
187
  return buffer_capacity;
 
188
}
 
189
 
 
190
/* Add server to set of servers to retry periodically */
 
191
int add_server(const char *ip, uint16_t port,
 
192
                 AvahiIfIndex if_index,
 
193
                 int af){
 
194
  int ret;
 
195
  server *new_server = malloc(sizeof(server));
 
196
  if(new_server == NULL){
 
197
    perror_plus("malloc");
 
198
    return -1;
 
199
  }
 
200
  *new_server = (server){ .ip = strdup(ip),
 
201
                         .port = port,
 
202
                         .if_index = if_index,
 
203
                         .af = af };
 
204
  if(new_server->ip == NULL){
 
205
    perror_plus("strdup");
 
206
    return -1;
 
207
  }
 
208
  /* Special case of first server */
 
209
  if (mc.current_server == NULL){
 
210
    new_server->next = new_server;
 
211
    new_server->prev = new_server;
 
212
    mc.current_server = new_server;
 
213
  /* Place the new server last in the list */
 
214
  } else {
 
215
    new_server->next = mc.current_server;
 
216
    new_server->prev = mc.current_server->prev;
 
217
    new_server->prev->next = new_server;
 
218
    mc.current_server->prev = new_server;
 
219
  }
 
220
  ret = clock_gettime(CLOCK_MONOTONIC, &mc.current_server->last_seen);
 
221
  if(ret == -1){
 
222
    perror_plus("clock_gettime");
 
223
    return -1;
 
224
  }
 
225
  return 0;
 
226
}
 
227
 
 
228
/* 
 
229
 * Initialize GPGME.
 
230
 */
 
231
static bool init_gpgme(const char *seckey,
 
232
                       const char *pubkey, const char *tempdir){
92
233
  gpgme_error_t rc;
93
 
  ssize_t ret;
94
 
  ssize_t new_packet_capacity = 0;
95
 
  ssize_t new_packet_length = 0;
96
234
  gpgme_engine_info_t engine_info;
97
 
 
98
 
  if (debug){
99
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
235
  
 
236
  
 
237
  /*
 
238
   * Helper function to insert pub and seckey to the engine keyring.
 
239
   */
 
240
  bool import_key(const char *filename){
 
241
    int ret;
 
242
    int fd;
 
243
    gpgme_data_t pgp_data;
 
244
    
 
245
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
 
246
    if(fd == -1){
 
247
      perror_plus("open");
 
248
      return false;
 
249
    }
 
250
    
 
251
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
 
252
    if(rc != GPG_ERR_NO_ERROR){
 
253
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
 
254
              gpgme_strsource(rc), gpgme_strerror(rc));
 
255
      return false;
 
256
    }
 
257
    
 
258
    rc = gpgme_op_import(mc.ctx, pgp_data);
 
259
    if(rc != GPG_ERR_NO_ERROR){
 
260
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
 
261
              gpgme_strsource(rc), gpgme_strerror(rc));
 
262
      return false;
 
263
    }
 
264
    
 
265
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
 
266
    if(ret == -1){
 
267
      perror_plus("close");
 
268
    }
 
269
    gpgme_data_release(pgp_data);
 
270
    return true;
 
271
  }
 
272
  
 
273
  if(debug){
 
274
    fprintf(stderr, "Initializing GPGME\n");
100
275
  }
101
276
  
102
277
  /* Init GPGME */
103
278
  gpgme_check_version(NULL);
104
 
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
279
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
280
  if(rc != GPG_ERR_NO_ERROR){
 
281
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
 
282
            gpgme_strsource(rc), gpgme_strerror(rc));
 
283
    return false;
 
284
  }
105
285
  
106
 
  /* Set GPGME home directory */
107
 
  rc = gpgme_get_engine_info (&engine_info);
108
 
  if (rc != GPG_ERR_NO_ERROR){
 
286
  /* Set GPGME home directory for the OpenPGP engine only */
 
287
  rc = gpgme_get_engine_info(&engine_info);
 
288
  if(rc != GPG_ERR_NO_ERROR){
109
289
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
110
290
            gpgme_strsource(rc), gpgme_strerror(rc));
111
 
    return -1;
 
291
    return false;
112
292
  }
113
293
  while(engine_info != NULL){
114
294
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
115
295
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
116
 
                            engine_info->file_name, homedir);
 
296
                            engine_info->file_name, tempdir);
117
297
      break;
118
298
    }
119
299
    engine_info = engine_info->next;
120
300
  }
121
301
  if(engine_info == NULL){
122
 
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
123
 
    return -1;
124
 
  }
125
 
  
126
 
  /* Create new GPGME data buffer from packet buffer */
127
 
  rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
128
 
  if (rc != GPG_ERR_NO_ERROR){
 
302
    fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
 
303
    return false;
 
304
  }
 
305
  
 
306
  /* Create new GPGME "context" */
 
307
  rc = gpgme_new(&(mc.ctx));
 
308
  if(rc != GPG_ERR_NO_ERROR){
 
309
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
 
310
            gpgme_strsource(rc), gpgme_strerror(rc));
 
311
    return false;
 
312
  }
 
313
  
 
314
  if(not import_key(pubkey) or not import_key(seckey)){
 
315
    return false;
 
316
  }
 
317
  
 
318
  return true;
 
319
}
 
320
 
 
321
/* 
 
322
 * Decrypt OpenPGP data.
 
323
 * Returns -1 on error
 
324
 */
 
325
static ssize_t pgp_packet_decrypt(const char *cryptotext,
 
326
                                  size_t crypto_size,
 
327
                                  char **plaintext){
 
328
  gpgme_data_t dh_crypto, dh_plain;
 
329
  gpgme_error_t rc;
 
330
  ssize_t ret;
 
331
  size_t plaintext_capacity = 0;
 
332
  ssize_t plaintext_length = 0;
 
333
  
 
334
  if(debug){
 
335
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
336
  }
 
337
  
 
338
  /* Create new GPGME data buffer from memory cryptotext */
 
339
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
 
340
                               0);
 
341
  if(rc != GPG_ERR_NO_ERROR){
129
342
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
130
343
            gpgme_strsource(rc), gpgme_strerror(rc));
131
344
    return -1;
133
346
  
134
347
  /* Create new empty GPGME data buffer for the plaintext */
135
348
  rc = gpgme_data_new(&dh_plain);
136
 
  if (rc != GPG_ERR_NO_ERROR){
 
349
  if(rc != GPG_ERR_NO_ERROR){
137
350
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
138
351
            gpgme_strsource(rc), gpgme_strerror(rc));
139
 
    return -1;
140
 
  }
141
 
  
142
 
  /* Create new GPGME "context" */
143
 
  rc = gpgme_new(&ctx);
144
 
  if (rc != GPG_ERR_NO_ERROR){
145
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
146
 
            gpgme_strsource(rc), gpgme_strerror(rc));
147
 
    return -1;
148
 
  }
149
 
  
150
 
  /* Decrypt data from the FILE pointer to the plaintext data
151
 
     buffer */
152
 
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
153
 
  if (rc != GPG_ERR_NO_ERROR){
 
352
    gpgme_data_release(dh_crypto);
 
353
    return -1;
 
354
  }
 
355
  
 
356
  /* Decrypt data from the cryptotext data buffer to the plaintext
 
357
     data buffer */
 
358
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
359
  if(rc != GPG_ERR_NO_ERROR){
154
360
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
155
361
            gpgme_strsource(rc), gpgme_strerror(rc));
156
 
    return -1;
157
 
  }
158
 
 
159
 
  if(debug){
160
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
161
 
  }
162
 
 
163
 
  if (debug){
164
 
    gpgme_decrypt_result_t result;
165
 
    result = gpgme_op_decrypt_result(ctx);
166
 
    if (result == NULL){
167
 
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
168
 
    } else {
169
 
      fprintf(stderr, "Unsupported algorithm: %s\n",
170
 
              result->unsupported_algorithm);
171
 
      fprintf(stderr, "Wrong key usage: %d\n",
172
 
              result->wrong_key_usage);
173
 
      if(result->file_name != NULL){
174
 
        fprintf(stderr, "File name: %s\n", result->file_name);
175
 
      }
176
 
      gpgme_recipient_t recipient;
177
 
      recipient = result->recipients;
178
 
      if(recipient){
 
362
    plaintext_length = -1;
 
363
    if(debug){
 
364
      gpgme_decrypt_result_t result;
 
365
      result = gpgme_op_decrypt_result(mc.ctx);
 
366
      if(result == NULL){
 
367
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
368
      } else {
 
369
        fprintf(stderr, "Unsupported algorithm: %s\n",
 
370
                result->unsupported_algorithm);
 
371
        fprintf(stderr, "Wrong key usage: %u\n",
 
372
                result->wrong_key_usage);
 
373
        if(result->file_name != NULL){
 
374
          fprintf(stderr, "File name: %s\n", result->file_name);
 
375
        }
 
376
        gpgme_recipient_t recipient;
 
377
        recipient = result->recipients;
179
378
        while(recipient != NULL){
180
379
          fprintf(stderr, "Public key algorithm: %s\n",
181
380
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
187
386
        }
188
387
      }
189
388
    }
 
389
    goto decrypt_end;
190
390
  }
191
391
  
192
 
  /* Delete the GPGME FILE pointer cryptotext data buffer */
193
 
  gpgme_data_release(dh_crypto);
 
392
  if(debug){
 
393
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
 
394
  }
194
395
  
195
396
  /* Seek back to the beginning of the GPGME plaintext data buffer */
196
 
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
197
 
 
198
 
  *new_packet = 0;
 
397
  if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
 
398
    perror_plus("gpgme_data_seek");
 
399
    plaintext_length = -1;
 
400
    goto decrypt_end;
 
401
  }
 
402
  
 
403
  *plaintext = NULL;
199
404
  while(true){
200
 
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
201
 
      *new_packet = realloc(*new_packet,
202
 
                            (unsigned int)new_packet_capacity
203
 
                            + BUFFER_SIZE);
204
 
      if (*new_packet == NULL){
205
 
        perror("realloc");
206
 
        return -1;
207
 
      }
208
 
      new_packet_capacity += BUFFER_SIZE;
 
405
    plaintext_capacity = incbuffer(plaintext,
 
406
                                      (size_t)plaintext_length,
 
407
                                      plaintext_capacity);
 
408
    if(plaintext_capacity == 0){
 
409
        perror_plus("incbuffer");
 
410
        plaintext_length = -1;
 
411
        goto decrypt_end;
209
412
    }
210
413
    
211
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
414
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
212
415
                          BUFFER_SIZE);
213
416
    /* Print the data, if any */
214
 
    if (ret == 0){
 
417
    if(ret == 0){
 
418
      /* EOF */
215
419
      break;
216
420
    }
217
421
    if(ret < 0){
218
 
      perror("gpgme_data_read");
219
 
      return -1;
220
 
    }
221
 
    new_packet_length += ret;
222
 
  }
223
 
 
224
 
  /* FIXME: check characters before printing to screen so to not print
225
 
     terminal control characters */
226
 
  /*   if(debug){ */
227
 
  /*     fprintf(stderr, "decrypted password is: "); */
228
 
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
229
 
  /*     fprintf(stderr, "\n"); */
230
 
  /*   } */
 
422
      perror_plus("gpgme_data_read");
 
423
      plaintext_length = -1;
 
424
      goto decrypt_end;
 
425
    }
 
426
    plaintext_length += ret;
 
427
  }
 
428
  
 
429
  if(debug){
 
430
    fprintf(stderr, "Decrypted password is: ");
 
431
    for(ssize_t i = 0; i < plaintext_length; i++){
 
432
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
 
433
    }
 
434
    fprintf(stderr, "\n");
 
435
  }
 
436
  
 
437
 decrypt_end:
 
438
  
 
439
  /* Delete the GPGME cryptotext data buffer */
 
440
  gpgme_data_release(dh_crypto);
231
441
  
232
442
  /* Delete the GPGME plaintext data buffer */
233
443
  gpgme_data_release(dh_plain);
234
 
  return new_packet_length;
 
444
  return plaintext_length;
235
445
}
236
446
 
237
 
static const char * safer_gnutls_strerror (int value) {
238
 
  const char *ret = gnutls_strerror (value);
239
 
  if (ret == NULL)
 
447
static const char * safer_gnutls_strerror(int value){
 
448
  const char *ret = gnutls_strerror(value); /* Spurious warning from
 
449
                                               -Wunreachable-code */
 
450
  if(ret == NULL)
240
451
    ret = "(unknown)";
241
452
  return ret;
242
453
}
243
454
 
244
 
void debuggnutls(__attribute__((unused)) int level,
245
 
                 const char* string){
246
 
  fprintf(stderr, "%s", string);
 
455
/* GnuTLS log function callback */
 
456
static void debuggnutls(__attribute__((unused)) int level,
 
457
                        const char* string){
 
458
  fprintf(stderr, "GnuTLS: %s", string);
247
459
}
248
460
 
249
 
int initgnutls(encrypted_session *es){
250
 
  const char *err;
 
461
static int init_gnutls_global(const char *pubkeyfilename,
 
462
                              const char *seckeyfilename){
251
463
  int ret;
252
464
  
253
465
  if(debug){
254
466
    fprintf(stderr, "Initializing GnuTLS\n");
255
467
  }
256
468
  
257
 
  if ((ret = gnutls_global_init ())
258
 
      != GNUTLS_E_SUCCESS) {
259
 
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
 
469
  ret = gnutls_global_init();
 
470
  if(ret != GNUTLS_E_SUCCESS){
 
471
    fprintf(stderr, "GnuTLS global_init: %s\n",
 
472
            safer_gnutls_strerror(ret));
260
473
    return -1;
261
474
  }
262
 
 
263
 
  if (debug){
 
475
  
 
476
  if(debug){
 
477
    /* "Use a log level over 10 to enable all debugging options."
 
478
     * - GnuTLS manual
 
479
     */
264
480
    gnutls_global_set_log_level(11);
265
481
    gnutls_global_set_log_function(debuggnutls);
266
482
  }
267
483
  
268
 
  /* openpgp credentials */
269
 
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
270
 
      != GNUTLS_E_SUCCESS) {
271
 
    fprintf (stderr, "memory error: %s\n",
272
 
             safer_gnutls_strerror(ret));
 
484
  /* OpenPGP credentials */
 
485
  ret = gnutls_certificate_allocate_credentials(&mc.cred);
 
486
  if(ret != GNUTLS_E_SUCCESS){
 
487
    fprintf(stderr, "GnuTLS memory error: %s\n",
 
488
            safer_gnutls_strerror(ret));
 
489
    gnutls_global_deinit();
273
490
    return -1;
274
491
  }
275
492
  
276
493
  if(debug){
277
 
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
278
 
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
279
 
            KEYFILE);
 
494
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
 
495
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
 
496
            seckeyfilename);
280
497
  }
281
498
  
282
499
  ret = gnutls_certificate_set_openpgp_key_file
283
 
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
284
 
  if (ret != GNUTLS_E_SUCCESS) {
285
 
    fprintf
286
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
287
 
       " '%s')\n",
288
 
       ret, CERTFILE, KEYFILE);
289
 
    fprintf(stdout, "The Error is: %s\n",
290
 
            safer_gnutls_strerror(ret));
291
 
    return -1;
292
 
  }
293
 
  
294
 
  //GnuTLS server initialization
295
 
  if ((ret = gnutls_dh_params_init (&es->dh_params))
296
 
      != GNUTLS_E_SUCCESS) {
297
 
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
298
 
             safer_gnutls_strerror(ret));
299
 
    return -1;
300
 
  }
301
 
  
302
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
303
 
      != GNUTLS_E_SUCCESS) {
304
 
    fprintf (stderr, "Error in prime generation: %s\n",
305
 
             safer_gnutls_strerror(ret));
306
 
    return -1;
307
 
  }
308
 
  
309
 
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
310
 
  
311
 
  // GnuTLS session creation
312
 
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
313
 
      != GNUTLS_E_SUCCESS){
 
500
    (mc.cred, pubkeyfilename, seckeyfilename,
 
501
     GNUTLS_OPENPGP_FMT_BASE64);
 
502
  if(ret != GNUTLS_E_SUCCESS){
 
503
    fprintf(stderr,
 
504
            "Error[%d] while reading the OpenPGP key pair ('%s',"
 
505
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
 
506
    fprintf(stderr, "The GnuTLS error is: %s\n",
 
507
            safer_gnutls_strerror(ret));
 
508
    goto globalfail;
 
509
  }
 
510
  
 
511
  /* GnuTLS server initialization */
 
512
  ret = gnutls_dh_params_init(&mc.dh_params);
 
513
  if(ret != GNUTLS_E_SUCCESS){
 
514
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
 
515
            " %s\n", safer_gnutls_strerror(ret));
 
516
    goto globalfail;
 
517
  }
 
518
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
519
  if(ret != GNUTLS_E_SUCCESS){
 
520
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
 
521
            safer_gnutls_strerror(ret));
 
522
    goto globalfail;
 
523
  }
 
524
  
 
525
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
526
  
 
527
  return 0;
 
528
  
 
529
 globalfail:
 
530
  
 
531
  gnutls_certificate_free_credentials(mc.cred);
 
532
  gnutls_global_deinit();
 
533
  gnutls_dh_params_deinit(mc.dh_params);
 
534
  return -1;
 
535
}
 
536
 
 
537
static int init_gnutls_session(gnutls_session_t *session){
 
538
  int ret;
 
539
  /* GnuTLS session creation */
 
540
  do {
 
541
    ret = gnutls_init(session, GNUTLS_SERVER);
 
542
    if(quit_now){
 
543
      return -1;
 
544
    }
 
545
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
 
546
  if(ret != GNUTLS_E_SUCCESS){
314
547
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
315
548
            safer_gnutls_strerror(ret));
316
549
  }
317
550
  
318
 
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
319
 
      != GNUTLS_E_SUCCESS) {
320
 
    fprintf(stderr, "Syntax error at: %s\n", err);
321
 
    fprintf(stderr, "GnuTLS error: %s\n",
322
 
            safer_gnutls_strerror(ret));
323
 
    return -1;
 
551
  {
 
552
    const char *err;
 
553
    do {
 
554
      ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
555
      if(quit_now){
 
556
        gnutls_deinit(*session);
 
557
        return -1;
 
558
      }
 
559
    } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
 
560
    if(ret != GNUTLS_E_SUCCESS){
 
561
      fprintf(stderr, "Syntax error at: %s\n", err);
 
562
      fprintf(stderr, "GnuTLS error: %s\n",
 
563
              safer_gnutls_strerror(ret));
 
564
      gnutls_deinit(*session);
 
565
      return -1;
 
566
    }
324
567
  }
325
568
  
326
 
  if ((ret = gnutls_credentials_set
327
 
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
328
 
      != GNUTLS_E_SUCCESS) {
329
 
    fprintf(stderr, "Error setting a credentials set: %s\n",
 
569
  do {
 
570
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
571
                                 mc.cred);
 
572
    if(quit_now){
 
573
      gnutls_deinit(*session);
 
574
      return -1;
 
575
    }
 
576
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
 
577
  if(ret != GNUTLS_E_SUCCESS){
 
578
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
330
579
            safer_gnutls_strerror(ret));
 
580
    gnutls_deinit(*session);
331
581
    return -1;
332
582
  }
333
583
  
334
584
  /* ignore client certificate if any. */
335
 
  gnutls_certificate_server_set_request (es->session,
336
 
                                         GNUTLS_CERT_IGNORE);
 
585
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
337
586
  
338
 
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
 
587
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
339
588
  
340
589
  return 0;
341
590
}
342
591
 
343
 
void empty_log(__attribute__((unused)) AvahiLogLevel level,
344
 
               __attribute__((unused)) const char *txt){}
 
592
/* Avahi log function callback */
 
593
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
594
                      __attribute__((unused)) const char *txt){}
345
595
 
346
 
int start_mandos_communication(const char *ip, uint16_t port,
347
 
                               unsigned int if_index){
348
 
  int ret, tcp_sd;
349
 
  struct sockaddr_in6 to;
350
 
  encrypted_session es;
 
596
/* Called when a Mandos server is found */
 
597
static int start_mandos_communication(const char *ip, uint16_t port,
 
598
                                      AvahiIfIndex if_index,
 
599
                                      int af){
 
600
  int ret, tcp_sd = -1;
 
601
  ssize_t sret;
 
602
  union {
 
603
    struct sockaddr_in in;
 
604
    struct sockaddr_in6 in6;
 
605
  } to;
351
606
  char *buffer = NULL;
352
 
  char *decrypted_buffer;
 
607
  char *decrypted_buffer = NULL;
353
608
  size_t buffer_length = 0;
354
609
  size_t buffer_capacity = 0;
355
 
  ssize_t decrypted_buffer_size;
356
 
  size_t written = 0;
357
 
  int retval = 0;
358
 
  char interface[IF_NAMESIZE];
359
 
  
360
 
  if(debug){
361
 
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
362
 
  }
363
 
  
364
 
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
365
 
  if(tcp_sd < 0) {
366
 
    perror("socket");
367
 
    return -1;
368
 
  }
369
 
  
370
 
  if(if_indextoname(if_index, interface) == NULL){
371
 
    if(debug){
372
 
      perror("if_indextoname");
373
 
    }
374
 
    return -1;
375
 
  }
376
 
  
377
 
  if(debug){
378
 
    fprintf(stderr, "Binding to interface %s\n", interface);
379
 
  }
380
 
  
381
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
382
 
  to.sin6_family = AF_INET6;
383
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
384
 
  if (ret < 0 ){
385
 
    perror("inet_pton");
386
 
    return -1;
387
 
  }  
 
610
  size_t written;
 
611
  int retval = -1;
 
612
  gnutls_session_t session;
 
613
  int pf;                       /* Protocol family */
 
614
  
 
615
  errno = 0;
 
616
  
 
617
  if(quit_now){
 
618
    errno = EINTR;
 
619
    return -1;
 
620
  }
 
621
  
 
622
  switch(af){
 
623
  case AF_INET6:
 
624
    pf = PF_INET6;
 
625
    break;
 
626
  case AF_INET:
 
627
    pf = PF_INET;
 
628
    break;
 
629
  default:
 
630
    fprintf(stderr, "Bad address family: %d\n", af);
 
631
    errno = EINVAL;
 
632
    return -1;
 
633
  }
 
634
  
 
635
  ret = init_gnutls_session(&session);
 
636
  if(ret != 0){
 
637
    return -1;
 
638
  }
 
639
  
 
640
  if(debug){
 
641
    fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
 
642
            "\n", ip, port);
 
643
  }
 
644
  
 
645
  tcp_sd = socket(pf, SOCK_STREAM, 0);
 
646
  if(tcp_sd < 0){
 
647
    int e = errno;
 
648
    perror_plus("socket");
 
649
    errno = e;
 
650
    goto mandos_end;
 
651
  }
 
652
  
 
653
  if(quit_now){
 
654
    errno = EINTR;
 
655
    goto mandos_end;
 
656
  }
 
657
  
 
658
  memset(&to, 0, sizeof(to));
 
659
  if(af == AF_INET6){
 
660
    to.in6.sin6_family = (sa_family_t)af;
 
661
    ret = inet_pton(af, ip, &to.in6.sin6_addr);
 
662
  } else {                      /* IPv4 */
 
663
    to.in.sin_family = (sa_family_t)af;
 
664
    ret = inet_pton(af, ip, &to.in.sin_addr);
 
665
  }
 
666
  if(ret < 0 ){
 
667
    int e = errno;
 
668
    perror_plus("inet_pton");
 
669
    errno = e;
 
670
    goto mandos_end;
 
671
  }
388
672
  if(ret == 0){
 
673
    int e = errno;
389
674
    fprintf(stderr, "Bad address: %s\n", ip);
390
 
    return -1;
391
 
  }
392
 
  to.sin6_port = htons(port);   /* Spurious warning */
 
675
    errno = e;
 
676
    goto mandos_end;
 
677
  }
 
678
  if(af == AF_INET6){
 
679
    to.in6.sin6_port = htons(port); /* Spurious warnings from
 
680
                                       -Wconversion and
 
681
                                       -Wunreachable-code */
 
682
    
 
683
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
 
684
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
 
685
                              -Wunreachable-code*/
 
686
      if(if_index == AVAHI_IF_UNSPEC){
 
687
        fprintf(stderr, "An IPv6 link-local address is incomplete"
 
688
                " without a network interface\n");
 
689
        errno = EINVAL;
 
690
        goto mandos_end;
 
691
      }
 
692
      /* Set the network interface number as scope */
 
693
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
694
    }
 
695
  } else {
 
696
    to.in.sin_port = htons(port); /* Spurious warnings from
 
697
                                     -Wconversion and
 
698
                                     -Wunreachable-code */
 
699
  }
393
700
  
394
 
  to.sin6_scope_id = (uint32_t)if_index;
 
701
  if(quit_now){
 
702
    errno = EINTR;
 
703
    goto mandos_end;
 
704
  }
395
705
  
396
706
  if(debug){
397
 
    fprintf(stderr, "Connection to: %s\n", ip);
398
 
  }
399
 
  
400
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
401
 
  if (ret < 0){
402
 
    perror("connect");
403
 
    return -1;
404
 
  }
405
 
  
406
 
  ret = initgnutls (&es);
407
 
  if (ret != 0){
408
 
    retval = -1;
409
 
    return -1;
410
 
  }
411
 
  
412
 
  gnutls_transport_set_ptr (es.session,
413
 
                            (gnutls_transport_ptr_t) tcp_sd);
 
707
    if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
 
708
      char interface[IF_NAMESIZE];
 
709
      if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
710
        perror_plus("if_indextoname");
 
711
      } else {
 
712
        fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
 
713
                ip, interface, port);
 
714
      }
 
715
    } else {
 
716
      fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
717
              port);
 
718
    }
 
719
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
 
720
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
 
721
    const char *pcret;
 
722
    if(af == AF_INET6){
 
723
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
 
724
                        sizeof(addrstr));
 
725
    } else {
 
726
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
 
727
                        sizeof(addrstr));
 
728
    }
 
729
    if(pcret == NULL){
 
730
      perror_plus("inet_ntop");
 
731
    } else {
 
732
      if(strcmp(addrstr, ip) != 0){
 
733
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
 
734
      }
 
735
    }
 
736
  }
 
737
  
 
738
  if(quit_now){
 
739
    errno = EINTR;
 
740
    goto mandos_end;
 
741
  }
 
742
  
 
743
  if(af == AF_INET6){
 
744
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
745
  } else {
 
746
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
747
  }
 
748
  if(ret < 0){
 
749
    if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
750
      int e = errno;
 
751
      perror_plus("connect");
 
752
      errno = e;
 
753
    }
 
754
    goto mandos_end;
 
755
  }
 
756
  
 
757
  if(quit_now){
 
758
    errno = EINTR;
 
759
    goto mandos_end;
 
760
  }
 
761
  
 
762
  const char *out = mandos_protocol_version;
 
763
  written = 0;
 
764
  while(true){
 
765
    size_t out_size = strlen(out);
 
766
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
767
                                   out_size - written));
 
768
    if(ret == -1){
 
769
      int e = errno;
 
770
      perror_plus("write");
 
771
      errno = e;
 
772
      goto mandos_end;
 
773
    }
 
774
    written += (size_t)ret;
 
775
    if(written < out_size){
 
776
      continue;
 
777
    } else {
 
778
      if(out == mandos_protocol_version){
 
779
        written = 0;
 
780
        out = "\r\n";
 
781
      } else {
 
782
        break;
 
783
      }
 
784
    }
 
785
  
 
786
    if(quit_now){
 
787
      errno = EINTR;
 
788
      goto mandos_end;
 
789
    }
 
790
  }
414
791
  
415
792
  if(debug){
416
793
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
417
794
  }
418
795
  
419
 
  ret = gnutls_handshake (es.session);
420
 
  
421
 
  if (ret != GNUTLS_E_SUCCESS){
 
796
  if(quit_now){
 
797
    errno = EINTR;
 
798
    goto mandos_end;
 
799
  }
 
800
  
 
801
  /* Spurious warning from -Wint-to-pointer-cast */
 
802
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
803
  
 
804
  if(quit_now){
 
805
    errno = EINTR;
 
806
    goto mandos_end;
 
807
  }
 
808
  
 
809
  do {
 
810
    ret = gnutls_handshake(session);
 
811
    if(quit_now){
 
812
      errno = EINTR;
 
813
      goto mandos_end;
 
814
    }
 
815
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
816
  
 
817
  if(ret != GNUTLS_E_SUCCESS){
422
818
    if(debug){
423
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
424
 
      gnutls_perror (ret);
 
819
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
820
      gnutls_perror(ret);
425
821
    }
426
 
    retval = -1;
427
 
    goto exit;
 
822
    errno = EPROTO;
 
823
    goto mandos_end;
428
824
  }
429
825
  
430
 
  //Retrieve OpenPGP packet that contains the wanted password
 
826
  /* Read OpenPGP packet that contains the wanted password */
431
827
  
432
828
  if(debug){
433
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
829
    fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
434
830
            ip);
435
831
  }
436
 
 
 
832
  
437
833
  while(true){
438
 
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
439
 
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
440
 
      if (buffer == NULL){
441
 
        perror("realloc");
442
 
        goto exit;
443
 
      }
444
 
      buffer_capacity += BUFFER_SIZE;
445
 
    }
446
 
    
447
 
    ret = gnutls_record_recv
448
 
      (es.session, buffer+buffer_length, BUFFER_SIZE);
449
 
    if (ret == 0){
 
834
    
 
835
    if(quit_now){
 
836
      errno = EINTR;
 
837
      goto mandos_end;
 
838
    }
 
839
    
 
840
    buffer_capacity = incbuffer(&buffer, buffer_length,
 
841
                                   buffer_capacity);
 
842
    if(buffer_capacity == 0){
 
843
      int e = errno;
 
844
      perror_plus("incbuffer");
 
845
      errno = e;
 
846
      goto mandos_end;
 
847
    }
 
848
    
 
849
    if(quit_now){
 
850
      errno = EINTR;
 
851
      goto mandos_end;
 
852
    }
 
853
    
 
854
    sret = gnutls_record_recv(session, buffer+buffer_length,
 
855
                              BUFFER_SIZE);
 
856
    if(sret == 0){
450
857
      break;
451
858
    }
452
 
    if (ret < 0){
453
 
      switch(ret){
 
859
    if(sret < 0){
 
860
      switch(sret){
454
861
      case GNUTLS_E_INTERRUPTED:
455
862
      case GNUTLS_E_AGAIN:
456
863
        break;
457
864
      case GNUTLS_E_REHANDSHAKE:
458
 
        ret = gnutls_handshake (es.session);
459
 
        if (ret < 0){
460
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
461
 
          gnutls_perror (ret);
462
 
          retval = -1;
463
 
          goto exit;
 
865
        do {
 
866
          ret = gnutls_handshake(session);
 
867
          
 
868
          if(quit_now){
 
869
            errno = EINTR;
 
870
            goto mandos_end;
 
871
          }
 
872
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
873
        if(ret < 0){
 
874
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
875
          gnutls_perror(ret);
 
876
          errno = EPROTO;
 
877
          goto mandos_end;
464
878
        }
465
879
        break;
466
880
      default:
467
881
        fprintf(stderr, "Unknown error while reading data from"
468
 
                " encrypted session with mandos server\n");
469
 
        retval = -1;
470
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
471
 
        goto exit;
 
882
                " encrypted session with Mandos server\n");
 
883
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
884
        errno = EIO;
 
885
        goto mandos_end;
472
886
      }
473
887
    } else {
474
 
      buffer_length += (size_t) ret;
475
 
    }
476
 
  }
477
 
  
478
 
  if (buffer_length > 0){
 
888
      buffer_length += (size_t) sret;
 
889
    }
 
890
  }
 
891
  
 
892
  if(debug){
 
893
    fprintf(stderr, "Closing TLS session\n");
 
894
  }
 
895
  
 
896
  if(quit_now){
 
897
    errno = EINTR;
 
898
    goto mandos_end;
 
899
  }
 
900
  
 
901
  do {
 
902
    ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
903
    if(quit_now){
 
904
      errno = EINTR;
 
905
      goto mandos_end;
 
906
    }
 
907
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
908
  
 
909
  if(buffer_length > 0){
 
910
    ssize_t decrypted_buffer_size;
479
911
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
480
912
                                               buffer_length,
481
 
                                               &decrypted_buffer,
482
 
                                               CERT_ROOT);
483
 
    if (decrypted_buffer_size >= 0){
484
 
      while(written < decrypted_buffer_size){
485
 
        ret = (int)fwrite (decrypted_buffer + written, 1,
486
 
                           (size_t)decrypted_buffer_size - written,
487
 
                           stdout);
 
913
                                               &decrypted_buffer);
 
914
    if(decrypted_buffer_size >= 0){
 
915
      
 
916
      written = 0;
 
917
      while(written < (size_t) decrypted_buffer_size){
 
918
        if(quit_now){
 
919
          errno = EINTR;
 
920
          goto mandos_end;
 
921
        }
 
922
        
 
923
        ret = (int)fwrite(decrypted_buffer + written, 1,
 
924
                          (size_t)decrypted_buffer_size - written,
 
925
                          stdout);
488
926
        if(ret == 0 and ferror(stdout)){
 
927
          int e = errno;
489
928
          if(debug){
490
929
            fprintf(stderr, "Error writing encrypted data: %s\n",
491
930
                    strerror(errno));
492
931
          }
493
 
          retval = -1;
494
 
          break;
 
932
          errno = e;
 
933
          goto mandos_end;
495
934
        }
496
935
        written += (size_t)ret;
497
936
      }
498
 
      free(decrypted_buffer);
499
 
    } else {
 
937
      retval = 0;
 
938
    }
 
939
  }
 
940
  
 
941
  /* Shutdown procedure */
 
942
  
 
943
 mandos_end:
 
944
  {
 
945
    int e = errno;
 
946
    free(decrypted_buffer);
 
947
    free(buffer);
 
948
    if(tcp_sd >= 0){
 
949
      ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
 
950
    }
 
951
    if(ret == -1){
 
952
      if(e == 0){
 
953
        e = errno;
 
954
      }
 
955
      perror_plus("close");
 
956
    }
 
957
    gnutls_deinit(session);
 
958
    errno = e;
 
959
    if(quit_now){
 
960
      errno = EINTR;
500
961
      retval = -1;
501
962
    }
502
963
  }
503
 
 
504
 
  //shutdown procedure
505
 
 
506
 
  if(debug){
507
 
    fprintf(stderr, "Closing TLS session\n");
508
 
  }
509
 
 
510
 
  free(buffer);
511
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
512
 
 exit:
513
 
  close(tcp_sd);
514
 
  gnutls_deinit (es.session);
515
 
  gnutls_certificate_free_credentials (es.cred);
516
 
  gnutls_global_deinit ();
517
964
  return retval;
518
965
}
519
966
 
520
 
static AvahiSimplePoll *simple_poll = NULL;
521
 
static AvahiServer *server = NULL;
522
 
 
523
 
static void resolve_callback(
524
 
    AvahiSServiceResolver *r,
525
 
    AvahiIfIndex interface,
526
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
527
 
    AvahiResolverEvent event,
528
 
    const char *name,
529
 
    const char *type,
530
 
    const char *domain,
531
 
    const char *host_name,
532
 
    const AvahiAddress *address,
533
 
    uint16_t port,
534
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
535
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
536
 
    AVAHI_GCC_UNUSED void* userdata) {
537
 
    
538
 
  assert(r);                    /* Spurious warning */
 
967
static void resolve_callback(AvahiSServiceResolver *r,
 
968
                             AvahiIfIndex interface,
 
969
                             AvahiProtocol proto,
 
970
                             AvahiResolverEvent event,
 
971
                             const char *name,
 
972
                             const char *type,
 
973
                             const char *domain,
 
974
                             const char *host_name,
 
975
                             const AvahiAddress *address,
 
976
                             uint16_t port,
 
977
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
 
978
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
979
                             flags,
 
980
                             AVAHI_GCC_UNUSED void* userdata){
 
981
  assert(r);
539
982
  
540
983
  /* Called whenever a service has been resolved successfully or
541
984
     timed out */
542
985
  
543
 
  switch (event) {
 
986
  if(quit_now){
 
987
    return;
 
988
  }
 
989
  
 
990
  switch(event){
544
991
  default:
545
992
  case AVAHI_RESOLVER_FAILURE:
546
 
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
547
 
            " type '%s' in domain '%s': %s\n", name, type, domain,
548
 
            avahi_strerror(avahi_server_errno(server)));
 
993
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
 
994
            " of type '%s' in domain '%s': %s\n", name, type, domain,
 
995
            avahi_strerror(avahi_server_errno(mc.server)));
549
996
    break;
550
997
    
551
998
  case AVAHI_RESOLVER_FOUND:
553
1000
      char ip[AVAHI_ADDRESS_STR_MAX];
554
1001
      avahi_address_snprint(ip, sizeof(ip), address);
555
1002
      if(debug){
556
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
557
 
                " port %d\n", name, host_name, ip, port);
 
1003
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
 
1004
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
 
1005
                ip, (intmax_t)interface, port);
558
1006
      }
559
 
      int ret = start_mandos_communication(ip, port,
560
 
                                           (unsigned int) interface);
561
 
      if (ret == 0){
562
 
        exit(EXIT_SUCCESS);
 
1007
      int ret = start_mandos_communication(ip, port, interface,
 
1008
                                           avahi_proto_to_af(proto));
 
1009
      if(ret == 0){
 
1010
        avahi_simple_poll_quit(mc.simple_poll);
 
1011
      } else {
 
1012
        ret = add_server(ip, port, interface,
 
1013
                         avahi_proto_to_af(proto));
563
1014
      }
564
1015
    }
565
1016
  }
566
1017
  avahi_s_service_resolver_free(r);
567
1018
}
568
1019
 
569
 
static void browse_callback(
570
 
    AvahiSServiceBrowser *b,
571
 
    AvahiIfIndex interface,
572
 
    AvahiProtocol protocol,
573
 
    AvahiBrowserEvent event,
574
 
    const char *name,
575
 
    const char *type,
576
 
    const char *domain,
577
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
578
 
    void* userdata) {
579
 
    
580
 
    AvahiServer *s = userdata;
581
 
    assert(b);                  /* Spurious warning */
582
 
    
583
 
    /* Called whenever a new services becomes available on the LAN or
584
 
       is removed from the LAN */
585
 
    
586
 
    switch (event) {
 
1020
static void browse_callback(AvahiSServiceBrowser *b,
 
1021
                            AvahiIfIndex interface,
 
1022
                            AvahiProtocol protocol,
 
1023
                            AvahiBrowserEvent event,
 
1024
                            const char *name,
 
1025
                            const char *type,
 
1026
                            const char *domain,
 
1027
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
1028
                            flags,
 
1029
                            AVAHI_GCC_UNUSED void* userdata){
 
1030
  assert(b);
 
1031
  
 
1032
  /* Called whenever a new services becomes available on the LAN or
 
1033
     is removed from the LAN */
 
1034
  
 
1035
  if(quit_now){
 
1036
    return;
 
1037
  }
 
1038
  
 
1039
  switch(event){
 
1040
  default:
 
1041
  case AVAHI_BROWSER_FAILURE:
 
1042
    
 
1043
    fprintf(stderr, "(Avahi browser) %s\n",
 
1044
            avahi_strerror(avahi_server_errno(mc.server)));
 
1045
    avahi_simple_poll_quit(mc.simple_poll);
 
1046
    return;
 
1047
    
 
1048
  case AVAHI_BROWSER_NEW:
 
1049
    /* We ignore the returned Avahi resolver object. In the callback
 
1050
       function we free it. If the Avahi server is terminated before
 
1051
       the callback function is called the Avahi server will free the
 
1052
       resolver for us. */
 
1053
    
 
1054
    if(avahi_s_service_resolver_new(mc.server, interface, protocol,
 
1055
                                    name, type, domain, protocol, 0,
 
1056
                                    resolve_callback, NULL) == NULL)
 
1057
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
 
1058
              name, avahi_strerror(avahi_server_errno(mc.server)));
 
1059
    break;
 
1060
    
 
1061
  case AVAHI_BROWSER_REMOVE:
 
1062
    break;
 
1063
    
 
1064
  case AVAHI_BROWSER_ALL_FOR_NOW:
 
1065
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
1066
    if(debug){
 
1067
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
1068
    }
 
1069
    break;
 
1070
  }
 
1071
}
 
1072
 
 
1073
/* Signal handler that stops main loop after SIGTERM */
 
1074
static void handle_sigterm(int sig){
 
1075
  if(quit_now){
 
1076
    return;
 
1077
  }
 
1078
  quit_now = 1;
 
1079
  signal_received = sig;
 
1080
  int old_errno = errno;
 
1081
  /* set main loop to exit */
 
1082
  if(mc.simple_poll != NULL){
 
1083
    avahi_simple_poll_quit(mc.simple_poll);
 
1084
  }
 
1085
  errno = old_errno;
 
1086
}
 
1087
 
 
1088
bool get_flags(const char *ifname, struct ifreq *ifr){
 
1089
  int ret;
 
1090
  
 
1091
  int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1092
  if(s < 0){
 
1093
    perror_plus("socket");
 
1094
    return false;
 
1095
  }
 
1096
  strcpy(ifr->ifr_name, ifname);
 
1097
  ret = ioctl(s, SIOCGIFFLAGS, ifr);
 
1098
  if(ret == -1){
 
1099
    if(debug){
 
1100
      perror_plus("ioctl SIOCGIFFLAGS");
 
1101
    }
 
1102
    return false;
 
1103
  }
 
1104
  return true;
 
1105
}
 
1106
 
 
1107
bool good_flags(const char *ifname, const struct ifreq *ifr){
 
1108
  
 
1109
  /* Reject the loopback device */
 
1110
  if(ifr->ifr_flags & IFF_LOOPBACK){
 
1111
    if(debug){
 
1112
      fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
 
1113
              ifname);
 
1114
    }
 
1115
    return false;
 
1116
  }
 
1117
  /* Accept point-to-point devices only if connect_to is specified */
 
1118
  if(connect_to != NULL and (ifr->ifr_flags & IFF_POINTOPOINT)){
 
1119
    if(debug){
 
1120
      fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
 
1121
              ifname);
 
1122
    }
 
1123
    return true;
 
1124
  }
 
1125
  /* Otherwise, reject non-broadcast-capable devices */
 
1126
  if(not (ifr->ifr_flags & IFF_BROADCAST)){
 
1127
    if(debug){
 
1128
      fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
 
1129
              ifname);
 
1130
    }
 
1131
    return false;
 
1132
  }
 
1133
  /* Reject non-ARP interfaces (including dummy interfaces) */
 
1134
  if(ifr->ifr_flags & IFF_NOARP){
 
1135
    if(debug){
 
1136
      fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n", ifname);
 
1137
    }
 
1138
    return false;
 
1139
  }
 
1140
  
 
1141
  /* Accept this device */
 
1142
  if(debug){
 
1143
    fprintf(stderr, "Interface \"%s\" is good\n", ifname);
 
1144
  }
 
1145
  return true;
 
1146
}
 
1147
 
 
1148
/* 
 
1149
 * This function determines if a directory entry in /sys/class/net
 
1150
 * corresponds to an acceptable network device.
 
1151
 * (This function is passed to scandir(3) as a filter function.)
 
1152
 */
 
1153
int good_interface(const struct dirent *if_entry){
 
1154
  int ret;
 
1155
  if(if_entry->d_name[0] == '.'){
 
1156
    return 0;
 
1157
  }
 
1158
  struct ifreq ifr;
 
1159
 
 
1160
  if(not get_flags(if_entry->d_name, &ifr)){
 
1161
    return 0;
 
1162
  }
 
1163
  
 
1164
  if(not good_flags(if_entry->d_name, &ifr)){
 
1165
    return 0;
 
1166
  }
 
1167
  return 1;
 
1168
}
 
1169
 
 
1170
int notdotentries(const struct dirent *direntry){
 
1171
  /* Skip "." and ".." */
 
1172
  if(direntry->d_name[0] == '.'
 
1173
     and (direntry->d_name[1] == '\0'
 
1174
          or (direntry->d_name[1] == '.'
 
1175
              and direntry->d_name[2] == '\0'))){
 
1176
    return 0;
 
1177
  }
 
1178
  return 1;
 
1179
}
 
1180
 
 
1181
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval){
 
1182
  int ret;
 
1183
  struct timespec now;
 
1184
  struct timespec waited_time;
 
1185
  intmax_t block_time;
 
1186
  
 
1187
  while(true){
 
1188
    if(mc.current_server == NULL){
 
1189
      if (debug){
 
1190
        fprintf(stderr,
 
1191
                "Wait until first server is found. No timeout!\n");
 
1192
      }
 
1193
      ret = avahi_simple_poll_iterate(s, -1);
 
1194
    } else {
 
1195
      if (debug){
 
1196
        fprintf(stderr, "Check current_server if we should run it,"
 
1197
                " or wait\n");
 
1198
      }
 
1199
      /* the current time */
 
1200
      ret = clock_gettime(CLOCK_MONOTONIC, &now);
 
1201
      if(ret == -1){
 
1202
        perror_plus("clock_gettime");
 
1203
        return -1;
 
1204
      }
 
1205
      /* Calculating in ms how long time between now and server
 
1206
         who we visted longest time ago. Now - last seen.  */
 
1207
      waited_time.tv_sec = (now.tv_sec
 
1208
                            - mc.current_server->last_seen.tv_sec);
 
1209
      waited_time.tv_nsec = (now.tv_nsec
 
1210
                             - mc.current_server->last_seen.tv_nsec);
 
1211
      /* total time is 10s/10,000ms.
 
1212
         Converting to s from ms by dividing by 1,000,
 
1213
         and ns to ms by dividing by 1,000,000. */
 
1214
      block_time = ((retry_interval
 
1215
                     - ((intmax_t)waited_time.tv_sec * 1000))
 
1216
                    - ((intmax_t)waited_time.tv_nsec / 1000000));
 
1217
      
 
1218
      if (debug){
 
1219
        fprintf(stderr, "Blocking for %" PRIdMAX " ms\n", block_time);
 
1220
      }
 
1221
      
 
1222
      if(block_time <= 0){
 
1223
        ret = start_mandos_communication(mc.current_server->ip,
 
1224
                                         mc.current_server->port,
 
1225
                                         mc.current_server->if_index,
 
1226
                                         mc.current_server->af);
 
1227
        if(ret == 0){
 
1228
          avahi_simple_poll_quit(mc.simple_poll);
 
1229
          return 0;
 
1230
        }
 
1231
        ret = clock_gettime(CLOCK_MONOTONIC,
 
1232
                            &mc.current_server->last_seen);
 
1233
        if(ret == -1){
 
1234
          perror_plus("clock_gettime");
 
1235
          return -1;
 
1236
        }
 
1237
        mc.current_server = mc.current_server->next;
 
1238
        block_time = 0;         /* Call avahi to find new Mandos
 
1239
                                   servers, but don't block */
 
1240
      }
 
1241
      
 
1242
      ret = avahi_simple_poll_iterate(s, (int)block_time);
 
1243
    }
 
1244
    if(ret != 0){
 
1245
      if (ret > 0 or errno != EINTR) {
 
1246
        return (ret != 1) ? ret : 0;
 
1247
      }
 
1248
    }
 
1249
  }
 
1250
}
 
1251
 
 
1252
int main(int argc, char *argv[]){
 
1253
  AvahiSServiceBrowser *sb = NULL;
 
1254
  int error;
 
1255
  int ret;
 
1256
  intmax_t tmpmax;
 
1257
  char *tmp;
 
1258
  int exitcode = EXIT_SUCCESS;
 
1259
  const char *interface = "";
 
1260
  struct ifreq network;
 
1261
  int sd = -1;
 
1262
  bool take_down_interface = false;
 
1263
  uid_t uid;
 
1264
  gid_t gid;
 
1265
  char tempdir[] = "/tmp/mandosXXXXXX";
 
1266
  bool tempdir_created = false;
 
1267
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
1268
  const char *seckey = PATHDIR "/" SECKEY;
 
1269
  const char *pubkey = PATHDIR "/" PUBKEY;
 
1270
  
 
1271
  bool gnutls_initialized = false;
 
1272
  bool gpgme_initialized = false;
 
1273
  float delay = 2.5f;
 
1274
  double retry_interval = 10; /* 10s between trying a server and
 
1275
                                 retrying the same server again */
 
1276
  
 
1277
  struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
 
1278
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
 
1279
  
 
1280
  uid = getuid();
 
1281
  gid = getgid();
 
1282
  
 
1283
  /* Lower any group privileges we might have, just to be safe */
 
1284
  errno = 0;
 
1285
  ret = setgid(gid);
 
1286
  if(ret == -1){
 
1287
    perror_plus("setgid");
 
1288
  }
 
1289
  
 
1290
  /* Lower user privileges (temporarily) */
 
1291
  errno = 0;
 
1292
  ret = seteuid(uid);
 
1293
  if(ret == -1){
 
1294
    perror_plus("seteuid");
 
1295
  }
 
1296
  
 
1297
  if(quit_now){
 
1298
    goto end;
 
1299
  }
 
1300
  
 
1301
  {
 
1302
    struct argp_option options[] = {
 
1303
      { .name = "debug", .key = 128,
 
1304
        .doc = "Debug mode", .group = 3 },
 
1305
      { .name = "connect", .key = 'c',
 
1306
        .arg = "ADDRESS:PORT",
 
1307
        .doc = "Connect directly to a specific Mandos server",
 
1308
        .group = 1 },
 
1309
      { .name = "interface", .key = 'i',
 
1310
        .arg = "NAME",
 
1311
        .doc = "Network interface that will be used to search for"
 
1312
        " Mandos servers",
 
1313
        .group = 1 },
 
1314
      { .name = "seckey", .key = 's',
 
1315
        .arg = "FILE",
 
1316
        .doc = "OpenPGP secret key file base name",
 
1317
        .group = 1 },
 
1318
      { .name = "pubkey", .key = 'p',
 
1319
        .arg = "FILE",
 
1320
        .doc = "OpenPGP public key file base name",
 
1321
        .group = 2 },
 
1322
      { .name = "dh-bits", .key = 129,
 
1323
        .arg = "BITS",
 
1324
        .doc = "Bit length of the prime number used in the"
 
1325
        " Diffie-Hellman key exchange",
 
1326
        .group = 2 },
 
1327
      { .name = "priority", .key = 130,
 
1328
        .arg = "STRING",
 
1329
        .doc = "GnuTLS priority string for the TLS handshake",
 
1330
        .group = 1 },
 
1331
      { .name = "delay", .key = 131,
 
1332
        .arg = "SECONDS",
 
1333
        .doc = "Maximum delay to wait for interface startup",
 
1334
        .group = 2 },
 
1335
      { .name = "retry", .key = 132,
 
1336
        .arg = "SECONDS",
 
1337
        .doc = "Retry interval used when denied by the mandos server",
 
1338
        .group = 2 },
 
1339
      /*
 
1340
       * These reproduce what we would get without ARGP_NO_HELP
 
1341
       */
 
1342
      { .name = "help", .key = '?',
 
1343
        .doc = "Give this help list", .group = -1 },
 
1344
      { .name = "usage", .key = -3,
 
1345
        .doc = "Give a short usage message", .group = -1 },
 
1346
      { .name = "version", .key = 'V',
 
1347
        .doc = "Print program version", .group = -1 },
 
1348
      { .name = NULL }
 
1349
    };
 
1350
    
 
1351
    error_t parse_opt(int key, char *arg,
 
1352
                      struct argp_state *state){
 
1353
      errno = 0;
 
1354
      switch(key){
 
1355
      case 128:                 /* --debug */
 
1356
        debug = true;
 
1357
        break;
 
1358
      case 'c':                 /* --connect */
 
1359
        connect_to = arg;
 
1360
        break;
 
1361
      case 'i':                 /* --interface */
 
1362
        interface = arg;
 
1363
        break;
 
1364
      case 's':                 /* --seckey */
 
1365
        seckey = arg;
 
1366
        break;
 
1367
      case 'p':                 /* --pubkey */
 
1368
        pubkey = arg;
 
1369
        break;
 
1370
      case 129:                 /* --dh-bits */
 
1371
        errno = 0;
 
1372
        tmpmax = strtoimax(arg, &tmp, 10);
 
1373
        if(errno != 0 or tmp == arg or *tmp != '\0'
 
1374
           or tmpmax != (typeof(mc.dh_bits))tmpmax){
 
1375
          argp_error(state, "Bad number of DH bits");
 
1376
        }
 
1377
        mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
 
1378
        break;
 
1379
      case 130:                 /* --priority */
 
1380
        mc.priority = arg;
 
1381
        break;
 
1382
      case 131:                 /* --delay */
 
1383
        errno = 0;
 
1384
        delay = strtof(arg, &tmp);
 
1385
        if(errno != 0 or tmp == arg or *tmp != '\0'){
 
1386
          argp_error(state, "Bad delay");
 
1387
        }
 
1388
      case 132:                 /* --retry */
 
1389
        errno = 0;
 
1390
        retry_interval = strtod(arg, &tmp);
 
1391
        if(errno != 0 or tmp == arg or *tmp != '\0'
 
1392
           or (retry_interval * 1000) > INT_MAX
 
1393
           or retry_interval < 0){
 
1394
          argp_error(state, "Bad retry interval");
 
1395
        }
 
1396
        break;
 
1397
        /*
 
1398
         * These reproduce what we would get without ARGP_NO_HELP
 
1399
         */
 
1400
      case '?':                 /* --help */
 
1401
        argp_state_help(state, state->out_stream,
 
1402
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
 
1403
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
1404
      case -3:                  /* --usage */
 
1405
        argp_state_help(state, state->out_stream,
 
1406
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
1407
      case 'V':                 /* --version */
 
1408
        fprintf(state->out_stream, "%s\n", argp_program_version);
 
1409
        exit(argp_err_exit_status);
 
1410
        break;
 
1411
      default:
 
1412
        return ARGP_ERR_UNKNOWN;
 
1413
      }
 
1414
      return errno;
 
1415
    }
 
1416
    
 
1417
    struct argp argp = { .options = options, .parser = parse_opt,
 
1418
                         .args_doc = "",
 
1419
                         .doc = "Mandos client -- Get and decrypt"
 
1420
                         " passwords from a Mandos server" };
 
1421
    ret = argp_parse(&argp, argc, argv,
 
1422
                     ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
 
1423
    switch(ret){
 
1424
    case 0:
 
1425
      break;
 
1426
    case ENOMEM:
587
1427
    default:
588
 
    case AVAHI_BROWSER_FAILURE:
589
 
      
590
 
      fprintf(stderr, "(Browser) %s\n",
591
 
              avahi_strerror(avahi_server_errno(server)));
592
 
      avahi_simple_poll_quit(simple_poll);
593
 
      return;
594
 
      
595
 
    case AVAHI_BROWSER_NEW:
596
 
      /* We ignore the returned resolver object. In the callback
597
 
         function we free it. If the server is terminated before
598
 
         the callback function is called the server will free
599
 
         the resolver for us. */
600
 
      
601
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
602
 
                                         type, domain,
603
 
                                         AVAHI_PROTO_INET6, 0,
604
 
                                         resolve_callback, s)))
605
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
606
 
                avahi_strerror(avahi_server_errno(s)));
607
 
      break;
608
 
      
609
 
    case AVAHI_BROWSER_REMOVE:
610
 
      break;
611
 
      
612
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
613
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
614
 
      break;
615
 
    }
616
 
}
617
 
 
618
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
 
1428
      errno = ret;
 
1429
      perror_plus("argp_parse");
 
1430
      exitcode = EX_OSERR;
 
1431
      goto end;
 
1432
    case EINVAL:
 
1433
      exitcode = EX_USAGE;
 
1434
      goto end;
 
1435
    }
 
1436
  }
 
1437
    
 
1438
  {
 
1439
    /* Work around Debian bug #633582:
 
1440
       <http://bugs.debian.org/633582> */
 
1441
    struct stat st;
 
1442
    
 
1443
    /* Re-raise priviliges */
 
1444
    errno = 0;
 
1445
    ret = seteuid(0);
 
1446
    if(ret == -1){
 
1447
      perror_plus("seteuid");
 
1448
    }
 
1449
    
 
1450
    if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
 
1451
      int seckey_fd = open(seckey, O_RDONLY);
 
1452
      if(seckey_fd == -1){
 
1453
        perror_plus("open");
 
1454
      } else {
 
1455
        ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
 
1456
        if(ret == -1){
 
1457
          perror_plus("fstat");
 
1458
        } else {
 
1459
          if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
 
1460
            ret = fchown(seckey_fd, uid, gid);
 
1461
            if(ret == -1){
 
1462
              perror_plus("fchown");
 
1463
            }
 
1464
          }
 
1465
        }
 
1466
        TEMP_FAILURE_RETRY(close(seckey_fd));
 
1467
      }
 
1468
    }
 
1469
    
 
1470
    if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){
 
1471
      int pubkey_fd = open(pubkey, O_RDONLY);
 
1472
      if(pubkey_fd == -1){
 
1473
        perror_plus("open");
 
1474
      } else {
 
1475
        ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
 
1476
        if(ret == -1){
 
1477
          perror_plus("fstat");
 
1478
        } else {
 
1479
          if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
 
1480
            ret = fchown(pubkey_fd, uid, gid);
 
1481
            if(ret == -1){
 
1482
              perror_plus("fchown");
 
1483
            }
 
1484
          }
 
1485
        }
 
1486
        TEMP_FAILURE_RETRY(close(pubkey_fd));
 
1487
      }
 
1488
    }
 
1489
    
 
1490
    /* Lower privileges */
 
1491
    errno = 0;
 
1492
    ret = seteuid(uid);
 
1493
    if(ret == -1){
 
1494
      perror_plus("seteuid");
 
1495
    }
 
1496
  }
 
1497
  
 
1498
  if(not debug){
 
1499
    avahi_set_log_function(empty_log);
 
1500
  }
 
1501
 
 
1502
  if(interface[0] == '\0'){
 
1503
    struct dirent **direntries;
 
1504
    ret = scandir(sys_class_net, &direntries, good_interface,
 
1505
                  alphasort);
 
1506
    if(ret >= 1){
 
1507
      /* Pick the first good interface */
 
1508
      interface = strdup(direntries[0]->d_name);
 
1509
      if(debug){
 
1510
        fprintf(stderr, "Using interface \"%s\"\n", interface);
 
1511
      }
 
1512
      if(interface == NULL){
 
1513
        perror_plus("malloc");
 
1514
        free(direntries);
 
1515
        exitcode = EXIT_FAILURE;
 
1516
        goto end;
 
1517
      }
 
1518
      free(direntries);
 
1519
    } else {
 
1520
      free(direntries);
 
1521
      fprintf(stderr, "Could not find a network interface\n");
 
1522
      exitcode = EXIT_FAILURE;
 
1523
      goto end;
 
1524
    }
 
1525
  }
 
1526
  
 
1527
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
 
1528
     from the signal handler */
 
1529
  /* Initialize the pseudo-RNG for Avahi */
 
1530
  srand((unsigned int) time(NULL));
 
1531
  mc.simple_poll = avahi_simple_poll_new();
 
1532
  if(mc.simple_poll == NULL){
 
1533
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
 
1534
    exitcode = EX_UNAVAILABLE;
 
1535
    goto end;
 
1536
  }
 
1537
  
 
1538
  sigemptyset(&sigterm_action.sa_mask);
 
1539
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
 
1540
  if(ret == -1){
 
1541
    perror_plus("sigaddset");
 
1542
    exitcode = EX_OSERR;
 
1543
    goto end;
 
1544
  }
 
1545
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
 
1546
  if(ret == -1){
 
1547
    perror_plus("sigaddset");
 
1548
    exitcode = EX_OSERR;
 
1549
    goto end;
 
1550
  }
 
1551
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
 
1552
  if(ret == -1){
 
1553
    perror_plus("sigaddset");
 
1554
    exitcode = EX_OSERR;
 
1555
    goto end;
 
1556
  }
 
1557
  /* Need to check if the handler is SIG_IGN before handling:
 
1558
     | [[info:libc:Initial Signal Actions]] |
 
1559
     | [[info:libc:Basic Signal Handling]]  |
 
1560
  */
 
1561
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
 
1562
  if(ret == -1){
 
1563
    perror_plus("sigaction");
 
1564
    return EX_OSERR;
 
1565
  }
 
1566
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
1567
    ret = sigaction(SIGINT, &sigterm_action, NULL);
 
1568
    if(ret == -1){
 
1569
      perror_plus("sigaction");
 
1570
      exitcode = EX_OSERR;
 
1571
      goto end;
 
1572
    }
 
1573
  }
 
1574
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
 
1575
  if(ret == -1){
 
1576
    perror_plus("sigaction");
 
1577
    return EX_OSERR;
 
1578
  }
 
1579
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
1580
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
 
1581
    if(ret == -1){
 
1582
      perror_plus("sigaction");
 
1583
      exitcode = EX_OSERR;
 
1584
      goto end;
 
1585
    }
 
1586
  }
 
1587
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
 
1588
  if(ret == -1){
 
1589
    perror_plus("sigaction");
 
1590
    return EX_OSERR;
 
1591
  }
 
1592
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
1593
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
 
1594
    if(ret == -1){
 
1595
      perror_plus("sigaction");
 
1596
      exitcode = EX_OSERR;
 
1597
      goto end;
 
1598
    }
 
1599
  }
 
1600
  
 
1601
  /* If the interface is down, bring it up */
 
1602
  if(strcmp(interface, "none") != 0){
 
1603
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
1604
    if(if_index == 0){
 
1605
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
1606
      exitcode = EX_UNAVAILABLE;
 
1607
      goto end;
 
1608
    }
 
1609
    
 
1610
    if(quit_now){
 
1611
      goto end;
 
1612
    }
 
1613
    
 
1614
    /* Re-raise priviliges */
 
1615
    errno = 0;
 
1616
    ret = seteuid(0);
 
1617
    if(ret == -1){
 
1618
      perror_plus("seteuid");
 
1619
    }
 
1620
    
 
1621
#ifdef __linux__
 
1622
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1623
       messages about the network interface to mess up the prompt */
 
1624
    ret = klogctl(8, NULL, 5);
 
1625
    bool restore_loglevel = true;
 
1626
    if(ret == -1){
 
1627
      restore_loglevel = false;
 
1628
      perror_plus("klogctl");
 
1629
    }
 
1630
#endif  /* __linux__ */
 
1631
    
 
1632
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1633
    if(sd < 0){
 
1634
      perror_plus("socket");
 
1635
      exitcode = EX_OSERR;
 
1636
#ifdef __linux__
 
1637
      if(restore_loglevel){
 
1638
        ret = klogctl(7, NULL, 0);
 
1639
        if(ret == -1){
 
1640
          perror_plus("klogctl");
 
1641
        }
 
1642
      }
 
1643
#endif  /* __linux__ */
 
1644
      /* Lower privileges */
 
1645
      errno = 0;
 
1646
      ret = seteuid(uid);
 
1647
      if(ret == -1){
 
1648
        perror_plus("seteuid");
 
1649
      }
 
1650
      goto end;
 
1651
    }
 
1652
    strcpy(network.ifr_name, interface);
 
1653
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1654
    if(ret == -1){
 
1655
      perror_plus("ioctl SIOCGIFFLAGS");
 
1656
#ifdef __linux__
 
1657
      if(restore_loglevel){
 
1658
        ret = klogctl(7, NULL, 0);
 
1659
        if(ret == -1){
 
1660
          perror_plus("klogctl");
 
1661
        }
 
1662
      }
 
1663
#endif  /* __linux__ */
 
1664
      exitcode = EX_OSERR;
 
1665
      /* Lower privileges */
 
1666
      errno = 0;
 
1667
      ret = seteuid(uid);
 
1668
      if(ret == -1){
 
1669
        perror_plus("seteuid");
 
1670
      }
 
1671
      goto end;
 
1672
    }
 
1673
    if((network.ifr_flags & IFF_UP) == 0){
 
1674
      network.ifr_flags |= IFF_UP;
 
1675
      take_down_interface = true;
 
1676
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
1677
      if(ret == -1){
 
1678
        take_down_interface = false;
 
1679
        perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
 
1680
        exitcode = EX_OSERR;
 
1681
#ifdef __linux__
 
1682
        if(restore_loglevel){
 
1683
          ret = klogctl(7, NULL, 0);
 
1684
          if(ret == -1){
 
1685
            perror_plus("klogctl");
 
1686
          }
 
1687
        }
 
1688
#endif  /* __linux__ */
 
1689
        /* Lower privileges */
 
1690
        errno = 0;
 
1691
        ret = seteuid(uid);
 
1692
        if(ret == -1){
 
1693
          perror_plus("seteuid");
 
1694
        }
 
1695
        goto end;
 
1696
      }
 
1697
    }
 
1698
    /* Sleep checking until interface is running.
 
1699
       Check every 0.25s, up to total time of delay */
 
1700
    for(int i=0; i < delay * 4; i++){
 
1701
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1702
      if(ret == -1){
 
1703
        perror_plus("ioctl SIOCGIFFLAGS");
 
1704
      } else if(network.ifr_flags & IFF_RUNNING){
 
1705
        break;
 
1706
      }
 
1707
      struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1708
      ret = nanosleep(&sleeptime, NULL);
 
1709
      if(ret == -1 and errno != EINTR){
 
1710
        perror_plus("nanosleep");
 
1711
      }
 
1712
    }
 
1713
    if(not take_down_interface){
 
1714
      /* We won't need the socket anymore */
 
1715
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1716
      if(ret == -1){
 
1717
        perror_plus("close");
 
1718
      }
 
1719
    }
 
1720
#ifdef __linux__
 
1721
    if(restore_loglevel){
 
1722
      /* Restores kernel loglevel to default */
 
1723
      ret = klogctl(7, NULL, 0);
 
1724
      if(ret == -1){
 
1725
        perror_plus("klogctl");
 
1726
      }
 
1727
    }
 
1728
#endif  /* __linux__ */
 
1729
    /* Lower privileges */
 
1730
    errno = 0;
 
1731
    if(take_down_interface){
 
1732
      /* Lower privileges */
 
1733
      ret = seteuid(uid);
 
1734
      if(ret == -1){
 
1735
        perror_plus("seteuid");
 
1736
      }
 
1737
    } else {
 
1738
      /* Lower privileges permanently */
 
1739
      ret = setuid(uid);
 
1740
      if(ret == -1){
 
1741
        perror_plus("setuid");
 
1742
      }
 
1743
    }
 
1744
  }
 
1745
  
 
1746
  if(quit_now){
 
1747
    goto end;
 
1748
  }
 
1749
  
 
1750
  ret = init_gnutls_global(pubkey, seckey);
 
1751
  if(ret == -1){
 
1752
    fprintf(stderr, "init_gnutls_global failed\n");
 
1753
    exitcode = EX_UNAVAILABLE;
 
1754
    goto end;
 
1755
  } else {
 
1756
    gnutls_initialized = true;
 
1757
  }
 
1758
  
 
1759
  if(quit_now){
 
1760
    goto end;
 
1761
  }
 
1762
  
 
1763
  if(mkdtemp(tempdir) == NULL){
 
1764
    perror_plus("mkdtemp");
 
1765
    goto end;
 
1766
  }
 
1767
  tempdir_created = true;
 
1768
  
 
1769
  if(quit_now){
 
1770
    goto end;
 
1771
  }
 
1772
  
 
1773
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
1774
    fprintf(stderr, "init_gpgme failed\n");
 
1775
    exitcode = EX_UNAVAILABLE;
 
1776
    goto end;
 
1777
  } else {
 
1778
    gpgme_initialized = true;
 
1779
  }
 
1780
  
 
1781
  if(quit_now){
 
1782
    goto end;
 
1783
  }
 
1784
  
 
1785
  if(connect_to != NULL){
 
1786
    /* Connect directly, do not use Zeroconf */
 
1787
    /* (Mainly meant for debugging) */
 
1788
    char *address = strrchr(connect_to, ':');
 
1789
    if(address == NULL){
 
1790
      fprintf(stderr, "No colon in address\n");
 
1791
      exitcode = EX_USAGE;
 
1792
      goto end;
 
1793
    }
 
1794
    
 
1795
    if(quit_now){
 
1796
      goto end;
 
1797
    }
 
1798
    
 
1799
    uint16_t port;
 
1800
    errno = 0;
 
1801
    tmpmax = strtoimax(address+1, &tmp, 10);
 
1802
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
 
1803
       or tmpmax != (uint16_t)tmpmax){
 
1804
      fprintf(stderr, "Bad port number\n");
 
1805
      exitcode = EX_USAGE;
 
1806
      goto end;
 
1807
    }
 
1808
  
 
1809
    if(quit_now){
 
1810
      goto end;
 
1811
    }
 
1812
    
 
1813
    port = (uint16_t)tmpmax;
 
1814
    *address = '\0';
 
1815
    /* Colon in address indicates IPv6 */
 
1816
    int af;
 
1817
    if(strchr(connect_to, ':') != NULL){
 
1818
      af = AF_INET6;
 
1819
      /* Accept [] around IPv6 address - see RFC 5952 */
 
1820
      if(connect_to[0] == '[' and address[-1] == ']')
 
1821
        {
 
1822
          connect_to++;
 
1823
          address[-1] = '\0';
 
1824
        }
 
1825
    } else {
 
1826
      af = AF_INET;
 
1827
    }
 
1828
    address = connect_to;
 
1829
    
 
1830
    if(quit_now){
 
1831
      goto end;
 
1832
    }
 
1833
    
 
1834
    while(not quit_now){
 
1835
      ret = start_mandos_communication(address, port, if_index, af);
 
1836
      if(quit_now or ret == 0){
 
1837
        break;
 
1838
      }
 
1839
      if(debug){
 
1840
        fprintf(stderr, "Retrying in %d seconds\n",
 
1841
                (int)retry_interval);
 
1842
      }
 
1843
      sleep((int)retry_interval);
 
1844
    }
 
1845
    
 
1846
    if (not quit_now){
 
1847
      exitcode = EXIT_SUCCESS;
 
1848
    }
 
1849
 
 
1850
    goto end;
 
1851
  }
 
1852
  
 
1853
  if(quit_now){
 
1854
    goto end;
 
1855
  }
 
1856
  
 
1857
  {
619
1858
    AvahiServerConfig config;
620
 
    AvahiSServiceBrowser *sb = NULL;
621
 
    int error;
622
 
    int ret;
623
 
    int returncode = EXIT_SUCCESS;
624
 
    const char *interface = "eth0";
625
 
    
626
 
    while (true){
627
 
      static struct option long_options[] = {
628
 
        {"debug", no_argument, (int *)&debug, 1},
629
 
        {"interface", required_argument, 0, 'i'},
630
 
        {0, 0, 0, 0} };
631
 
      
632
 
      int option_index = 0;
633
 
      ret = getopt_long (argc, argv, "i:", long_options,
634
 
                         &option_index);
635
 
      
636
 
      if (ret == -1){
637
 
        break;
638
 
      }
639
 
      
640
 
      switch(ret){
641
 
      case 0:
642
 
        break;
643
 
      case 'i':
644
 
        interface = optarg;
645
 
        break;
646
 
      default:
647
 
        exit(EXIT_FAILURE);
648
 
      }
649
 
    }
650
 
    
651
 
    if (not debug){
652
 
      avahi_set_log_function(empty_log);
653
 
    }
654
 
    
655
 
    /* Initialize the psuedo-RNG */
656
 
    srand((unsigned int) time(NULL));
657
 
 
658
 
    /* Allocate main loop object */
659
 
    if (!(simple_poll = avahi_simple_poll_new())) {
660
 
        fprintf(stderr, "Failed to create simple poll object.\n");
661
 
        
662
 
        goto exit;
663
 
    }
664
 
 
665
 
    /* Do not publish any local records */
 
1859
    /* Do not publish any local Zeroconf records */
666
1860
    avahi_server_config_init(&config);
667
1861
    config.publish_hinfo = 0;
668
1862
    config.publish_addresses = 0;
669
1863
    config.publish_workstation = 0;
670
1864
    config.publish_domain = 0;
671
 
 
 
1865
    
672
1866
    /* Allocate a new server */
673
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
674
 
                              &config, NULL, NULL, &error);
675
 
 
676
 
    /* Free the configuration data */
 
1867
    mc.server = avahi_server_new(avahi_simple_poll_get
 
1868
                                 (mc.simple_poll), &config, NULL,
 
1869
                                 NULL, &error);
 
1870
    
 
1871
    /* Free the Avahi configuration data */
677
1872
    avahi_server_config_free(&config);
678
 
 
679
 
    /* Check if creating the server object succeeded */
680
 
    if (!server) {
681
 
        fprintf(stderr, "Failed to create server: %s\n",
682
 
                avahi_strerror(error));
683
 
        returncode = EXIT_FAILURE;
684
 
        goto exit;
685
 
    }
686
 
    
687
 
    /* Create the service browser */
688
 
    sb = avahi_s_service_browser_new(server,
689
 
                                     (AvahiIfIndex)
690
 
                                     if_nametoindex(interface),
691
 
                                     AVAHI_PROTO_INET6,
692
 
                                     "_mandos._tcp", NULL, 0,
693
 
                                     browse_callback, server);
694
 
    if (!sb) {
695
 
        fprintf(stderr, "Failed to create service browser: %s\n",
696
 
                avahi_strerror(avahi_server_errno(server)));
697
 
        returncode = EXIT_FAILURE;
698
 
        goto exit;
699
 
    }
700
 
    
701
 
    /* Run the main loop */
702
 
 
703
 
    if (debug){
704
 
      fprintf(stderr, "Starting avahi loop search\n");
705
 
    }
706
 
    
707
 
    avahi_simple_poll_loop(simple_poll);
708
 
    
709
 
 exit:
710
 
 
711
 
    if (debug){
712
 
      fprintf(stderr, "%s exiting\n", argv[0]);
713
 
    }
714
 
    
715
 
    /* Cleanup things */
716
 
    if (sb)
717
 
        avahi_s_service_browser_free(sb);
718
 
    
719
 
    if (server)
720
 
        avahi_server_free(server);
721
 
 
722
 
    if (simple_poll)
723
 
        avahi_simple_poll_free(simple_poll);
724
 
 
725
 
    return returncode;
 
1873
  }
 
1874
  
 
1875
  /* Check if creating the Avahi server object succeeded */
 
1876
  if(mc.server == NULL){
 
1877
    fprintf(stderr, "Failed to create Avahi server: %s\n",
 
1878
            avahi_strerror(error));
 
1879
    exitcode = EX_UNAVAILABLE;
 
1880
    goto end;
 
1881
  }
 
1882
  
 
1883
  if(quit_now){
 
1884
    goto end;
 
1885
  }
 
1886
  
 
1887
  /* Create the Avahi service browser */
 
1888
  sb = avahi_s_service_browser_new(mc.server, if_index,
 
1889
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
 
1890
                                   NULL, 0, browse_callback, NULL);
 
1891
  if(sb == NULL){
 
1892
    fprintf(stderr, "Failed to create service browser: %s\n",
 
1893
            avahi_strerror(avahi_server_errno(mc.server)));
 
1894
    exitcode = EX_UNAVAILABLE;
 
1895
    goto end;
 
1896
  }
 
1897
  
 
1898
  if(quit_now){
 
1899
    goto end;
 
1900
  }
 
1901
  
 
1902
  /* Run the main loop */
 
1903
  
 
1904
  if(debug){
 
1905
    fprintf(stderr, "Starting Avahi loop search\n");
 
1906
  }
 
1907
 
 
1908
  ret = avahi_loop_with_timeout(mc.simple_poll,
 
1909
                                (int)(retry_interval * 1000));
 
1910
  if(debug){
 
1911
    fprintf(stderr, "avahi_loop_with_timeout exited %s\n",
 
1912
            (ret == 0) ? "successfully" : "with error");
 
1913
  }
 
1914
  
 
1915
 end:
 
1916
  
 
1917
  if(debug){
 
1918
    fprintf(stderr, "%s exiting\n", argv[0]);
 
1919
  }
 
1920
  
 
1921
  /* Cleanup things */
 
1922
  if(sb != NULL)
 
1923
    avahi_s_service_browser_free(sb);
 
1924
  
 
1925
  if(mc.server != NULL)
 
1926
    avahi_server_free(mc.server);
 
1927
  
 
1928
  if(mc.simple_poll != NULL)
 
1929
    avahi_simple_poll_free(mc.simple_poll);
 
1930
  
 
1931
  if(gnutls_initialized){
 
1932
    gnutls_certificate_free_credentials(mc.cred);
 
1933
    gnutls_global_deinit();
 
1934
    gnutls_dh_params_deinit(mc.dh_params);
 
1935
  }
 
1936
  
 
1937
  if(gpgme_initialized){
 
1938
    gpgme_release(mc.ctx);
 
1939
  }
 
1940
 
 
1941
  /* Cleans up the circular linked list of Mandos servers the client
 
1942
     has seen */
 
1943
  if(mc.current_server != NULL){
 
1944
    mc.current_server->prev->next = NULL;
 
1945
    while(mc.current_server != NULL){
 
1946
      server *next = mc.current_server->next;
 
1947
      free(mc.current_server);
 
1948
      mc.current_server = next;
 
1949
    }
 
1950
  }
 
1951
  
 
1952
  /* Take down the network interface */
 
1953
  if(take_down_interface){
 
1954
    /* Re-raise priviliges */
 
1955
    errno = 0;
 
1956
    ret = seteuid(0);
 
1957
    if(ret == -1){
 
1958
      perror_plus("seteuid");
 
1959
    }
 
1960
    if(geteuid() == 0){
 
1961
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1962
      if(ret == -1){
 
1963
        perror_plus("ioctl SIOCGIFFLAGS");
 
1964
      } else if(network.ifr_flags & IFF_UP) {
 
1965
        network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
 
1966
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
1967
        if(ret == -1){
 
1968
          perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
 
1969
        }
 
1970
      }
 
1971
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1972
      if(ret == -1){
 
1973
        perror_plus("close");
 
1974
      }
 
1975
      /* Lower privileges permanently */
 
1976
      errno = 0;
 
1977
      ret = setuid(uid);
 
1978
      if(ret == -1){
 
1979
        perror_plus("setuid");
 
1980
      }
 
1981
    }
 
1982
  }
 
1983
  
 
1984
  /* Removes the GPGME temp directory and all files inside */
 
1985
  if(tempdir_created){
 
1986
    struct dirent **direntries = NULL;
 
1987
    struct dirent *direntry = NULL;
 
1988
    int numentries = scandir(tempdir, &direntries, notdotentries,
 
1989
                             alphasort);
 
1990
    if (numentries > 0){
 
1991
      for(int i = 0; i < numentries; i++){
 
1992
        direntry = direntries[i];
 
1993
        char *fullname = NULL;
 
1994
        ret = asprintf(&fullname, "%s/%s", tempdir,
 
1995
                       direntry->d_name);
 
1996
        if(ret < 0){
 
1997
          perror_plus("asprintf");
 
1998
          continue;
 
1999
        }
 
2000
        ret = remove(fullname);
 
2001
        if(ret == -1){
 
2002
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
 
2003
                  strerror(errno));
 
2004
        }
 
2005
        free(fullname);
 
2006
      }
 
2007
    }
 
2008
 
 
2009
    /* need to clean even if 0 because man page doesn't specify */
 
2010
    free(direntries);
 
2011
    if (numentries == -1){
 
2012
      perror_plus("scandir");
 
2013
    }
 
2014
    ret = rmdir(tempdir);
 
2015
    if(ret == -1 and errno != ENOENT){
 
2016
      perror_plus("rmdir");
 
2017
    }
 
2018
  }
 
2019
  
 
2020
  if(quit_now){
 
2021
    sigemptyset(&old_sigterm_action.sa_mask);
 
2022
    old_sigterm_action.sa_handler = SIG_DFL;
 
2023
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
 
2024
                                            &old_sigterm_action,
 
2025
                                            NULL));
 
2026
    if(ret == -1){
 
2027
      perror_plus("sigaction");
 
2028
    }
 
2029
    do {
 
2030
      ret = raise(signal_received);
 
2031
    } while(ret != 0 and errno == EINTR);
 
2032
    if(ret != 0){
 
2033
      perror_plus("raise");
 
2034
      abort();
 
2035
    }
 
2036
    TEMP_FAILURE_RETRY(pause());
 
2037
  }
 
2038
  
 
2039
  return exitcode;
726
2040
}