/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: Björn Påhlsson
  • Date: 2011-07-25 18:46:19 UTC
  • mfrom: (237.7.35 trunk)
  • mto: (237.7.37 trunk)
  • mto: This revision was merged to the branch mainline in revision 284.
  • Revision ID: belorn@fukt.bsnet.se-20110725184619-l7vfsobr0bh9fc3l
merge

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