/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/mandosclient.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-04 21:25:55 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080804212555-rm7xxjze65f8avy3
* server.py: Cosmetic changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
#define _LARGEFILE_SOURCE
33
33
#define _FILE_OFFSET_BITS 64
34
34
 
 
35
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY() */
 
36
 
35
37
#include <stdio.h>
36
38
#include <assert.h>
37
39
#include <stdlib.h>
38
40
#include <time.h>
39
41
#include <net/if.h>             /* if_nametoindex */
 
42
#include <sys/ioctl.h>          /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
 
43
                                   SIOCSIFFLAGS */
 
44
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
 
45
                                   SIOCSIFFLAGS */
40
46
 
41
47
#include <avahi-core/core.h>
42
48
#include <avahi-core/lookup.h>
45
51
#include <avahi-common/malloc.h>
46
52
#include <avahi-common/error.h>
47
53
 
48
 
//mandos client part
 
54
/* Mandos client part */
49
55
#include <sys/types.h>          /* socket(), inet_pton() */
50
56
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
51
57
                                   struct in6_addr, inet_pton() */
58
64
#include <string.h>             /* memset */
59
65
#include <arpa/inet.h>          /* inet_pton() */
60
66
#include <iso646.h>             /* not */
61
 
 
62
 
// gpgme
 
67
#include <net/if.h>             /* IF_NAMESIZE */
 
68
#include <argp.h>               /* struct argp_option,
 
69
                                   struct argp_state, struct argp,
 
70
                                   argp_parse() */
 
71
/* GPGME */
63
72
#include <errno.h>              /* perror() */
64
73
#include <gpgme.h>
65
74
 
66
 
// getopt long
67
 
#include <getopt.h>
68
 
 
69
75
#define BUFFER_SIZE 256
70
 
#define DH_BITS 1024
71
 
 
72
 
static const char *certdir = "/conf/conf.d/mandos";
73
 
static const char *certfile = "openpgp-client.txt";
74
 
static const char *certkey = "openpgp-client-key.txt";
75
76
 
76
77
bool debug = false;
 
78
static const char *keydir = "/conf/conf.d/mandos";
 
79
static const char mandos_protocol_version[] = "1";
 
80
const char *argp_program_version = "mandosclient 0.9";
 
81
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
77
82
 
 
83
/* Used for passing in values through the Avahi callback functions */
78
84
typedef struct {
79
 
  gnutls_session_t session;
 
85
  AvahiSimplePoll *simple_poll;
 
86
  AvahiServer *server;
80
87
  gnutls_certificate_credentials_t cred;
 
88
  unsigned int dh_bits;
81
89
  gnutls_dh_params_t dh_params;
82
 
} encrypted_session;
83
 
 
84
 
 
85
 
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
86
 
                                   char **new_packet,
 
90
  const char *priority;
 
91
} mandos_context;
 
92
 
 
93
/*
 
94
 * Make room in "buffer" for at least BUFFER_SIZE additional bytes.
 
95
 * "buffer_capacity" is how much is currently allocated,
 
96
 * "buffer_length" is how much is already used.
 
97
 */
 
98
size_t adjustbuffer(char **buffer, size_t buffer_length,
 
99
                  size_t buffer_capacity){
 
100
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
 
101
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
 
102
    if (buffer == NULL){
 
103
      return 0;
 
104
    }
 
105
    buffer_capacity += BUFFER_SIZE;
 
106
  }
 
107
  return buffer_capacity;
 
108
}
 
109
 
 
110
/* 
 
111
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
 
112
 * Returns -1 on error
 
113
 */
 
114
static ssize_t pgp_packet_decrypt (const char *cryptotext,
 
115
                                   size_t crypto_size,
 
116
                                   char **plaintext,
87
117
                                   const char *homedir){
88
118
  gpgme_data_t dh_crypto, dh_plain;
89
119
  gpgme_ctx_t ctx;
90
120
  gpgme_error_t rc;
91
121
  ssize_t ret;
92
 
  ssize_t new_packet_capacity = 0;
93
 
  ssize_t new_packet_length = 0;
 
122
  size_t plaintext_capacity = 0;
 
123
  ssize_t plaintext_length = 0;
94
124
  gpgme_engine_info_t engine_info;
95
 
 
 
125
  
96
126
  if (debug){
97
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
127
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
98
128
  }
99
129
  
100
130
  /* Init GPGME */
106
136
    return -1;
107
137
  }
108
138
  
109
 
  /* Set GPGME home directory */
 
139
  /* Set GPGME home directory for the OpenPGP engine only */
110
140
  rc = gpgme_get_engine_info (&engine_info);
111
141
  if (rc != GPG_ERR_NO_ERROR){
112
142
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
122
152
    engine_info = engine_info->next;
123
153
  }
124
154
  if(engine_info == NULL){
125
 
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
 
155
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
126
156
    return -1;
127
157
  }
128
158
  
129
 
  /* Create new GPGME data buffer from packet buffer */
130
 
  rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
 
159
  /* Create new GPGME data buffer from memory cryptotext */
 
160
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
 
161
                               0);
131
162
  if (rc != GPG_ERR_NO_ERROR){
132
163
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
133
164
            gpgme_strsource(rc), gpgme_strerror(rc));
139
170
  if (rc != GPG_ERR_NO_ERROR){
140
171
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
141
172
            gpgme_strsource(rc), gpgme_strerror(rc));
 
173
    gpgme_data_release(dh_crypto);
142
174
    return -1;
143
175
  }
144
176
  
147
179
  if (rc != GPG_ERR_NO_ERROR){
148
180
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
149
181
            gpgme_strsource(rc), gpgme_strerror(rc));
150
 
    return -1;
 
182
    plaintext_length = -1;
 
183
    goto decrypt_end;
151
184
  }
152
185
  
153
 
  /* Decrypt data from the FILE pointer to the plaintext data
154
 
     buffer */
 
186
  /* Decrypt data from the cryptotext data buffer to the plaintext
 
187
     data buffer */
155
188
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
156
189
  if (rc != GPG_ERR_NO_ERROR){
157
190
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
158
191
            gpgme_strsource(rc), gpgme_strerror(rc));
159
 
    return -1;
 
192
    plaintext_length = -1;
 
193
    goto decrypt_end;
160
194
  }
161
 
 
 
195
  
162
196
  if(debug){
163
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
 
197
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
164
198
  }
165
 
 
 
199
  
166
200
  if (debug){
167
201
    gpgme_decrypt_result_t result;
168
202
    result = gpgme_op_decrypt_result(ctx);
192
226
    }
193
227
  }
194
228
  
195
 
  /* Delete the GPGME FILE pointer cryptotext data buffer */
196
 
  gpgme_data_release(dh_crypto);
197
 
  
198
229
  /* Seek back to the beginning of the GPGME plaintext data buffer */
199
230
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
200
231
    perror("pgpme_data_seek");
 
232
    plaintext_length = -1;
 
233
    goto decrypt_end;
201
234
  }
202
235
  
203
 
  *new_packet = 0;
 
236
  *plaintext = NULL;
204
237
  while(true){
205
 
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
206
 
      *new_packet = realloc(*new_packet,
207
 
                            (unsigned int)new_packet_capacity
208
 
                            + BUFFER_SIZE);
209
 
      if (*new_packet == NULL){
210
 
        perror("realloc");
211
 
        return -1;
212
 
      }
213
 
      new_packet_capacity += BUFFER_SIZE;
 
238
    plaintext_capacity = adjustbuffer(plaintext,
 
239
                                      (size_t)plaintext_length,
 
240
                                      plaintext_capacity);
 
241
    if (plaintext_capacity == 0){
 
242
        perror("adjustbuffer");
 
243
        plaintext_length = -1;
 
244
        goto decrypt_end;
214
245
    }
215
246
    
216
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
247
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
217
248
                          BUFFER_SIZE);
218
249
    /* Print the data, if any */
219
250
    if (ret == 0){
 
251
      /* EOF */
220
252
      break;
221
253
    }
222
254
    if(ret < 0){
223
255
      perror("gpgme_data_read");
224
 
      return -1;
 
256
      plaintext_length = -1;
 
257
      goto decrypt_end;
225
258
    }
226
 
    new_packet_length += ret;
 
259
    plaintext_length += ret;
227
260
  }
228
261
 
229
 
  /* FIXME: check characters before printing to screen so to not print
230
 
     terminal control characters */
231
 
  /*   if(debug){ */
232
 
  /*     fprintf(stderr, "decrypted password is: "); */
233
 
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
234
 
  /*     fprintf(stderr, "\n"); */
235
 
  /*   } */
 
262
  if(debug){
 
263
    fprintf(stderr, "Decrypted password is: ");
 
264
    for(ssize_t i = 0; i < plaintext_length; i++){
 
265
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
 
266
    }
 
267
    fprintf(stderr, "\n");
 
268
  }
 
269
  
 
270
 decrypt_end:
 
271
  
 
272
  /* Delete the GPGME cryptotext data buffer */
 
273
  gpgme_data_release(dh_crypto);
236
274
  
237
275
  /* Delete the GPGME plaintext data buffer */
238
276
  gpgme_data_release(dh_plain);
239
 
  return new_packet_length;
 
277
  return plaintext_length;
240
278
}
241
279
 
242
280
static const char * safer_gnutls_strerror (int value) {
246
284
  return ret;
247
285
}
248
286
 
 
287
/* GnuTLS log function callback */
249
288
static void debuggnutls(__attribute__((unused)) int level,
250
289
                        const char* string){
251
 
  fprintf(stderr, "%s", string);
 
290
  fprintf(stderr, "GnuTLS: %s", string);
252
291
}
253
292
 
254
 
static int initgnutls(encrypted_session *es){
255
 
  const char *err;
 
293
static int init_gnutls_global(mandos_context *mc,
 
294
                              const char *pubkeyfile,
 
295
                              const char *seckeyfile){
256
296
  int ret;
257
297
  
258
298
  if(debug){
261
301
 
262
302
  if ((ret = gnutls_global_init ())
263
303
      != GNUTLS_E_SUCCESS) {
264
 
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
 
304
    fprintf (stderr, "GnuTLS global_init: %s\n",
 
305
             safer_gnutls_strerror(ret));
265
306
    return -1;
266
307
  }
267
 
 
 
308
  
268
309
  if (debug){
 
310
    /* "Use a log level over 10 to enable all debugging options."
 
311
     * - GnuTLS manual
 
312
     */
269
313
    gnutls_global_set_log_level(11);
270
314
    gnutls_global_set_log_function(debuggnutls);
271
315
  }
272
316
  
273
 
  /* openpgp credentials */
274
 
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
 
317
  /* OpenPGP credentials */
 
318
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
275
319
      != GNUTLS_E_SUCCESS) {
276
 
    fprintf (stderr, "memory error: %s\n",
 
320
    fprintf (stderr, "GnuTLS memory error: %s\n",
277
321
             safer_gnutls_strerror(ret));
278
322
    return -1;
279
323
  }
280
324
  
281
325
  if(debug){
282
326
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
283
 
            " and keyfile %s as GnuTLS credentials\n", certfile,
284
 
            certkey);
 
327
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
 
328
            seckeyfile);
285
329
  }
286
330
  
287
331
  ret = gnutls_certificate_set_openpgp_key_file
288
 
    (es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
 
332
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
289
333
  if (ret != GNUTLS_E_SUCCESS) {
290
 
    fprintf
291
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
292
 
       " '%s')\n",
293
 
       ret, certfile, certkey);
294
 
    fprintf(stdout, "The Error is: %s\n",
 
334
    fprintf(stderr,
 
335
            "Error[%d] while reading the OpenPGP key pair ('%s',"
 
336
            " '%s')\n", ret, pubkeyfile, seckeyfile);
 
337
    fprintf(stdout, "The GnuTLS error is: %s\n",
295
338
            safer_gnutls_strerror(ret));
296
339
    return -1;
297
340
  }
298
341
  
299
 
  //GnuTLS server initialization
300
 
  if ((ret = gnutls_dh_params_init (&es->dh_params))
301
 
      != GNUTLS_E_SUCCESS) {
302
 
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
303
 
             safer_gnutls_strerror(ret));
304
 
    return -1;
305
 
  }
306
 
  
307
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
308
 
      != GNUTLS_E_SUCCESS) {
309
 
    fprintf (stderr, "Error in prime generation: %s\n",
310
 
             safer_gnutls_strerror(ret));
311
 
    return -1;
312
 
  }
313
 
  
314
 
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
315
 
  
316
 
  // GnuTLS session creation
317
 
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
318
 
      != GNUTLS_E_SUCCESS){
 
342
  /* GnuTLS server initialization */
 
343
  ret = gnutls_dh_params_init(&mc->dh_params);
 
344
  if (ret != GNUTLS_E_SUCCESS) {
 
345
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
 
346
             " %s\n", safer_gnutls_strerror(ret));
 
347
    return -1;
 
348
  }
 
349
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
350
  if (ret != GNUTLS_E_SUCCESS) {
 
351
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
 
352
             safer_gnutls_strerror(ret));
 
353
    return -1;
 
354
  }
 
355
  
 
356
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
 
357
 
 
358
  return 0;
 
359
}
 
360
 
 
361
static int init_gnutls_session(mandos_context *mc,
 
362
                               gnutls_session_t *session){
 
363
  int ret;
 
364
  /* GnuTLS session creation */
 
365
  ret = gnutls_init(session, GNUTLS_SERVER);
 
366
  if (ret != GNUTLS_E_SUCCESS){
319
367
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
320
368
            safer_gnutls_strerror(ret));
321
369
  }
322
370
  
323
 
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
324
 
      != GNUTLS_E_SUCCESS) {
325
 
    fprintf(stderr, "Syntax error at: %s\n", err);
326
 
    fprintf(stderr, "GnuTLS error: %s\n",
327
 
            safer_gnutls_strerror(ret));
328
 
    return -1;
 
371
  {
 
372
    const char *err;
 
373
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
 
374
    if (ret != GNUTLS_E_SUCCESS) {
 
375
      fprintf(stderr, "Syntax error at: %s\n", err);
 
376
      fprintf(stderr, "GnuTLS error: %s\n",
 
377
              safer_gnutls_strerror(ret));
 
378
      return -1;
 
379
    }
329
380
  }
330
381
  
331
 
  if ((ret = gnutls_credentials_set
332
 
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
333
 
      != GNUTLS_E_SUCCESS) {
334
 
    fprintf(stderr, "Error setting a credentials set: %s\n",
 
382
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
383
                               mc->cred);
 
384
  if (ret != GNUTLS_E_SUCCESS) {
 
385
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
335
386
            safer_gnutls_strerror(ret));
336
387
    return -1;
337
388
  }
338
389
  
339
390
  /* ignore client certificate if any. */
340
 
  gnutls_certificate_server_set_request (es->session,
 
391
  gnutls_certificate_server_set_request (*session,
341
392
                                         GNUTLS_CERT_IGNORE);
342
393
  
343
 
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
 
394
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
344
395
  
345
396
  return 0;
346
397
}
347
398
 
 
399
/* Avahi log function callback */
348
400
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
349
401
                      __attribute__((unused)) const char *txt){}
350
402
 
 
403
/* Called when a Mandos server is found */
351
404
static int start_mandos_communication(const char *ip, uint16_t port,
352
 
                                      AvahiIfIndex if_index){
 
405
                                      AvahiIfIndex if_index,
 
406
                                      mandos_context *mc){
353
407
  int ret, tcp_sd;
354
 
  struct sockaddr_in6 to;
355
 
  encrypted_session es;
 
408
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
356
409
  char *buffer = NULL;
357
410
  char *decrypted_buffer;
358
411
  size_t buffer_length = 0;
359
412
  size_t buffer_capacity = 0;
360
413
  ssize_t decrypted_buffer_size;
361
 
  size_t written = 0;
 
414
  size_t written;
362
415
  int retval = 0;
363
416
  char interface[IF_NAMESIZE];
 
417
  gnutls_session_t session;
 
418
  
 
419
  ret = init_gnutls_session (mc, &session);
 
420
  if (ret != 0){
 
421
    return -1;
 
422
  }
364
423
  
365
424
  if(debug){
366
425
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
372
431
    perror("socket");
373
432
    return -1;
374
433
  }
375
 
  
376
 
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
377
 
    if(debug){
 
434
 
 
435
  if(debug){
 
436
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
378
437
      perror("if_indextoname");
 
438
      return -1;
379
439
    }
380
 
    return -1;
381
 
  }
382
 
  
383
 
  if(debug){
384
440
    fprintf(stderr, "Binding to interface %s\n", interface);
385
441
  }
386
442
  
387
443
  memset(&to,0,sizeof(to));     /* Spurious warning */
388
 
  to.sin6_family = AF_INET6;
389
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
444
  to.in6.sin6_family = AF_INET6;
 
445
  /* It would be nice to have a way to detect if we were passed an
 
446
     IPv4 address here.   Now we assume an IPv6 address. */
 
447
  ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
390
448
  if (ret < 0 ){
391
449
    perror("inet_pton");
392
450
    return -1;
393
 
  }  
 
451
  }
394
452
  if(ret == 0){
395
453
    fprintf(stderr, "Bad address: %s\n", ip);
396
454
    return -1;
397
455
  }
398
 
  to.sin6_port = htons(port);   /* Spurious warning */
 
456
  to.in6.sin6_port = htons(port);       /* Spurious warning */
399
457
  
400
 
  to.sin6_scope_id = (uint32_t)if_index;
 
458
  to.in6.sin6_scope_id = (uint32_t)if_index;
401
459
  
402
460
  if(debug){
403
461
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
404
 
/*     char addrstr[INET6_ADDRSTRLEN]; */
405
 
/*     if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
406
 
/*               sizeof(addrstr)) == NULL){ */
407
 
/*       perror("inet_ntop"); */
408
 
/*     } else { */
409
 
/*       fprintf(stderr, "Really connecting to: %s, port %d\n", */
410
 
/*            addrstr, ntohs(to.sin6_port)); */
411
 
/*     } */
 
462
    char addrstr[INET6_ADDRSTRLEN] = "";
 
463
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
 
464
                 sizeof(addrstr)) == NULL){
 
465
      perror("inet_ntop");
 
466
    } else {
 
467
      if(strcmp(addrstr, ip) != 0){
 
468
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
 
469
      }
 
470
    }
412
471
  }
413
472
  
414
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
 
473
  ret = connect(tcp_sd, &to.in, sizeof(to));
415
474
  if (ret < 0){
416
475
    perror("connect");
417
476
    return -1;
418
477
  }
419
 
  
420
 
  ret = initgnutls (&es);
421
 
  if (ret != 0){
422
 
    retval = -1;
423
 
    return -1;
 
478
 
 
479
  const char *out = mandos_protocol_version;
 
480
  written = 0;
 
481
  while (true){
 
482
    size_t out_size = strlen(out);
 
483
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
484
                                   out_size - written));
 
485
    if (ret == -1){
 
486
      perror("write");
 
487
      retval = -1;
 
488
      goto mandos_end;
 
489
    }
 
490
    written += (size_t)ret;
 
491
    if(written < out_size){
 
492
      continue;
 
493
    } else {
 
494
      if (out == mandos_protocol_version){
 
495
        written = 0;
 
496
        out = "\r\n";
 
497
      } else {
 
498
        break;
 
499
      }
 
500
    }
424
501
  }
425
 
  
426
 
  gnutls_transport_set_ptr (es.session,
427
 
                            (gnutls_transport_ptr_t) tcp_sd);
428
 
  
 
502
 
429
503
  if(debug){
430
504
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
431
505
  }
432
506
  
433
 
  ret = gnutls_handshake (es.session);
 
507
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
 
508
  
 
509
  ret = gnutls_handshake (session);
434
510
  
435
511
  if (ret != GNUTLS_E_SUCCESS){
436
512
    if(debug){
437
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
513
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
438
514
      gnutls_perror (ret);
439
515
    }
440
516
    retval = -1;
441
 
    goto exit;
 
517
    goto mandos_end;
442
518
  }
443
519
  
444
 
  //Retrieve OpenPGP packet that contains the wanted password
 
520
  /* Read OpenPGP packet that contains the wanted password */
445
521
  
446
522
  if(debug){
447
523
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
449
525
  }
450
526
 
451
527
  while(true){
452
 
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
453
 
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
454
 
      if (buffer == NULL){
455
 
        perror("realloc");
456
 
        goto exit;
457
 
      }
458
 
      buffer_capacity += BUFFER_SIZE;
 
528
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
 
529
                                   buffer_capacity);
 
530
    if (buffer_capacity == 0){
 
531
      perror("adjustbuffer");
 
532
      retval = -1;
 
533
      goto mandos_end;
459
534
    }
460
535
    
461
 
    ret = gnutls_record_recv
462
 
      (es.session, buffer+buffer_length, BUFFER_SIZE);
 
536
    ret = gnutls_record_recv(session, buffer+buffer_length,
 
537
                             BUFFER_SIZE);
463
538
    if (ret == 0){
464
539
      break;
465
540
    }
469
544
      case GNUTLS_E_AGAIN:
470
545
        break;
471
546
      case GNUTLS_E_REHANDSHAKE:
472
 
        ret = gnutls_handshake (es.session);
 
547
        ret = gnutls_handshake (session);
473
548
        if (ret < 0){
474
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
 
549
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
475
550
          gnutls_perror (ret);
476
551
          retval = -1;
477
 
          goto exit;
 
552
          goto mandos_end;
478
553
        }
479
554
        break;
480
555
      default:
481
556
        fprintf(stderr, "Unknown error while reading data from"
482
 
                " encrypted session with mandos server\n");
 
557
                " encrypted session with Mandos server\n");
483
558
        retval = -1;
484
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
485
 
        goto exit;
 
559
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
560
        goto mandos_end;
486
561
      }
487
562
    } else {
488
563
      buffer_length += (size_t) ret;
489
564
    }
490
565
  }
491
566
  
 
567
  if(debug){
 
568
    fprintf(stderr, "Closing TLS session\n");
 
569
  }
 
570
  
 
571
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
572
  
492
573
  if (buffer_length > 0){
493
574
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
494
575
                                               buffer_length,
495
576
                                               &decrypted_buffer,
496
 
                                               certdir);
 
577
                                               keydir);
497
578
    if (decrypted_buffer_size >= 0){
 
579
      written = 0;
498
580
      while(written < (size_t) decrypted_buffer_size){
499
581
        ret = (int)fwrite (decrypted_buffer + written, 1,
500
582
                           (size_t)decrypted_buffer_size - written,
514
596
      retval = -1;
515
597
    }
516
598
  }
517
 
 
518
 
  //shutdown procedure
519
 
 
520
 
  if(debug){
521
 
    fprintf(stderr, "Closing TLS session\n");
522
 
  }
523
 
 
 
599
  
 
600
  /* Shutdown procedure */
 
601
  
 
602
 mandos_end:
524
603
  free(buffer);
525
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
526
 
 exit:
527
604
  close(tcp_sd);
528
 
  gnutls_deinit (es.session);
529
 
  gnutls_certificate_free_credentials (es.cred);
 
605
  gnutls_deinit (session);
 
606
  gnutls_certificate_free_credentials (mc->cred);
530
607
  gnutls_global_deinit ();
531
608
  return retval;
532
609
}
533
610
 
534
 
static AvahiSimplePoll *simple_poll = NULL;
535
 
static AvahiServer *server = NULL;
536
 
 
537
 
static void resolve_callback(
538
 
    AvahiSServiceResolver *r,
539
 
    AvahiIfIndex interface,
540
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
541
 
    AvahiResolverEvent event,
542
 
    const char *name,
543
 
    const char *type,
544
 
    const char *domain,
545
 
    const char *host_name,
546
 
    const AvahiAddress *address,
547
 
    uint16_t port,
548
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
549
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
550
 
    AVAHI_GCC_UNUSED void* userdata) {
551
 
    
 
611
static void resolve_callback(AvahiSServiceResolver *r,
 
612
                             AvahiIfIndex interface,
 
613
                             AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
614
                             AvahiResolverEvent event,
 
615
                             const char *name,
 
616
                             const char *type,
 
617
                             const char *domain,
 
618
                             const char *host_name,
 
619
                             const AvahiAddress *address,
 
620
                             uint16_t port,
 
621
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
 
622
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
623
                             flags,
 
624
                             void* userdata) {
 
625
  mandos_context *mc = userdata;
552
626
  assert(r);                    /* Spurious warning */
553
627
  
554
628
  /* Called whenever a service has been resolved successfully or
557
631
  switch (event) {
558
632
  default:
559
633
  case AVAHI_RESOLVER_FAILURE:
560
 
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
561
 
            " type '%s' in domain '%s': %s\n", name, type, domain,
562
 
            avahi_strerror(avahi_server_errno(server)));
 
634
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
 
635
            " of type '%s' in domain '%s': %s\n", name, type, domain,
 
636
            avahi_strerror(avahi_server_errno(mc->server)));
563
637
    break;
564
638
    
565
639
  case AVAHI_RESOLVER_FOUND:
567
641
      char ip[AVAHI_ADDRESS_STR_MAX];
568
642
      avahi_address_snprint(ip, sizeof(ip), address);
569
643
      if(debug){
570
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
571
 
                " port %d\n", name, host_name, ip, port);
 
644
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %d) on"
 
645
                " port %d\n", name, host_name, ip, interface, port);
572
646
      }
573
 
      int ret = start_mandos_communication(ip, port, interface);
 
647
      int ret = start_mandos_communication(ip, port, interface, mc);
574
648
      if (ret == 0){
575
649
        exit(EXIT_SUCCESS);
576
650
      }
579
653
  avahi_s_service_resolver_free(r);
580
654
}
581
655
 
582
 
static void browse_callback(
583
 
    AvahiSServiceBrowser *b,
584
 
    AvahiIfIndex interface,
585
 
    AvahiProtocol protocol,
586
 
    AvahiBrowserEvent event,
587
 
    const char *name,
588
 
    const char *type,
589
 
    const char *domain,
590
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
591
 
    void* userdata) {
592
 
    
593
 
    AvahiServer *s = userdata;
594
 
    assert(b);                  /* Spurious warning */
595
 
    
596
 
    /* Called whenever a new services becomes available on the LAN or
597
 
       is removed from the LAN */
598
 
    
599
 
    switch (event) {
600
 
    default:
601
 
    case AVAHI_BROWSER_FAILURE:
602
 
      
603
 
      fprintf(stderr, "(Browser) %s\n",
604
 
              avahi_strerror(avahi_server_errno(server)));
605
 
      avahi_simple_poll_quit(simple_poll);
606
 
      return;
607
 
      
608
 
    case AVAHI_BROWSER_NEW:
609
 
      /* We ignore the returned resolver object. In the callback
610
 
         function we free it. If the server is terminated before
611
 
         the callback function is called the server will free
612
 
         the resolver for us. */
613
 
      
614
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
615
 
                                         type, domain,
616
 
                                         AVAHI_PROTO_INET6, 0,
617
 
                                         resolve_callback, s)))
618
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
619
 
                avahi_strerror(avahi_server_errno(s)));
620
 
      break;
621
 
      
622
 
    case AVAHI_BROWSER_REMOVE:
623
 
      break;
624
 
      
625
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
626
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
627
 
      break;
 
656
static void browse_callback( AvahiSServiceBrowser *b,
 
657
                             AvahiIfIndex interface,
 
658
                             AvahiProtocol protocol,
 
659
                             AvahiBrowserEvent event,
 
660
                             const char *name,
 
661
                             const char *type,
 
662
                             const char *domain,
 
663
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
664
                             flags,
 
665
                             void* userdata) {
 
666
  mandos_context *mc = userdata;
 
667
  assert(b);                    /* Spurious warning */
 
668
  
 
669
  /* Called whenever a new services becomes available on the LAN or
 
670
     is removed from the LAN */
 
671
  
 
672
  switch (event) {
 
673
  default:
 
674
  case AVAHI_BROWSER_FAILURE:
 
675
    
 
676
    fprintf(stderr, "(Avahi browser) %s\n",
 
677
            avahi_strerror(avahi_server_errno(mc->server)));
 
678
    avahi_simple_poll_quit(mc->simple_poll);
 
679
    return;
 
680
    
 
681
  case AVAHI_BROWSER_NEW:
 
682
    /* We ignore the returned Avahi resolver object. In the callback
 
683
       function we free it. If the Avahi server is terminated before
 
684
       the callback function is called the Avahi server will free the
 
685
       resolver for us. */
 
686
    
 
687
    if (!(avahi_s_service_resolver_new(mc->server, interface,
 
688
                                       protocol, name, type, domain,
 
689
                                       AVAHI_PROTO_INET6, 0,
 
690
                                       resolve_callback, mc)))
 
691
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
 
692
              name, avahi_strerror(avahi_server_errno(mc->server)));
 
693
    break;
 
694
    
 
695
  case AVAHI_BROWSER_REMOVE:
 
696
    break;
 
697
    
 
698
  case AVAHI_BROWSER_ALL_FOR_NOW:
 
699
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
700
    if(debug){
 
701
      fprintf(stderr, "No Mandos server found, still searching...\n");
628
702
    }
 
703
    break;
 
704
  }
629
705
}
630
706
 
631
707
/* Combines file name and path and returns the malloced new
638
714
    return NULL;
639
715
  }
640
716
  if(f_len > 0){
641
 
    memcpy(tmp, first, f_len);
 
717
    memcpy(tmp, first, f_len);  /* Spurious warning */
642
718
  }
643
719
  tmp[f_len] = '/';
644
720
  if(s_len > 0){
645
 
    memcpy(tmp + f_len + 1, second, s_len);
 
721
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
646
722
  }
647
723
  tmp[f_len + 1 + s_len] = '\0';
648
724
  return tmp;
649
725
}
650
726
 
651
727
 
652
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
653
 
    AvahiServerConfig config;
 
728
int main(int argc, char *argv[]){
654
729
    AvahiSServiceBrowser *sb = NULL;
655
730
    int error;
656
731
    int ret;
657
 
    int returncode = EXIT_SUCCESS;
658
 
    const char *interface = NULL;
 
732
    int exitcode = EXIT_SUCCESS;
 
733
    const char *interface = "eth0";
 
734
    struct ifreq network;
 
735
    int sd;
 
736
    uid_t uid;
 
737
    gid_t gid;
 
738
    char *connect_to = NULL;
659
739
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
660
 
    char *connect_to = NULL;
661
 
    
662
 
    while (true){
663
 
      static struct option long_options[] = {
664
 
        {"debug", no_argument, (int *)&debug, 1},
665
 
        {"connect", required_argument, 0, 'C'},
666
 
        {"interface", required_argument, 0, 'i'},
667
 
        {"certdir", required_argument, 0, 'd'},
668
 
        {"certkey", required_argument, 0, 'c'},
669
 
        {"certfile", required_argument, 0, 'k'},
670
 
        {0, 0, 0, 0} };
671
 
      
672
 
      int option_index = 0;
673
 
      ret = getopt_long (argc, argv, "i:", long_options,
674
 
                         &option_index);
675
 
      
676
 
      if (ret == -1){
677
 
        break;
678
 
      }
679
 
      
680
 
      switch(ret){
681
 
      case 0:
682
 
        break;
683
 
      case 'i':
684
 
        interface = optarg;
685
 
        break;
686
 
      case 'C':
687
 
        connect_to = optarg;
688
 
        break;
689
 
      case 'd':
690
 
        certdir = optarg;
691
 
        break;
692
 
      case 'c':
693
 
        certfile = optarg;
694
 
        break;
695
 
      case 'k':
696
 
        certkey = optarg;
697
 
        break;
698
 
      default:
699
 
        exit(EXIT_FAILURE);
700
 
      }
701
 
    }
702
 
    
703
 
    certfile = combinepath(certdir, certfile);
704
 
    if (certfile == NULL){
705
 
      perror("combinepath");
706
 
      goto exit;
707
 
    }
708
 
    
709
 
    if(interface != NULL){
710
 
      if_index = (AvahiIfIndex) if_nametoindex(interface);
711
 
      if(if_index == 0){
712
 
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
713
 
        exit(EXIT_FAILURE);
714
 
      }
 
740
    const char *pubkeyfile = "pubkey.txt";
 
741
    const char *seckeyfile = "seckey.txt";
 
742
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
 
743
                          .dh_bits = 1024, .priority = "SECURE256"};
 
744
    
 
745
    {
 
746
      struct argp_option options[] = {
 
747
        { .name = "debug", .key = 128,
 
748
          .doc = "Debug mode", .group = 3 },
 
749
        { .name = "connect", .key = 'c',
 
750
          .arg = "IP",
 
751
          .doc = "Connect directly to a sepcified mandos server",
 
752
          .group = 1 },
 
753
        { .name = "interface", .key = 'i',
 
754
          .arg = "INTERFACE",
 
755
          .doc = "Interface that Avahi will conntect through",
 
756
          .group = 1 },
 
757
        { .name = "keydir", .key = 'd',
 
758
          .arg = "KEYDIR",
 
759
          .doc = "Directory where the openpgp keyring is",
 
760
          .group = 1 },
 
761
        { .name = "seckey", .key = 's',
 
762
          .arg = "SECKEY",
 
763
          .doc = "Secret openpgp key for gnutls authentication",
 
764
          .group = 1 },
 
765
        { .name = "pubkey", .key = 'p',
 
766
          .arg = "PUBKEY",
 
767
          .doc = "Public openpgp key for gnutls authentication",
 
768
          .group = 2 },
 
769
        { .name = "dh-bits", .key = 129,
 
770
          .arg = "BITS",
 
771
          .doc = "dh-bits to use in gnutls communication",
 
772
          .group = 2 },
 
773
        { .name = "priority", .key = 130,
 
774
          .arg = "PRIORITY",
 
775
          .doc = "GNUTLS priority", .group = 1 },
 
776
        { .name = NULL }
 
777
      };
 
778
 
 
779
      
 
780
      error_t parse_opt (int key, char *arg,
 
781
                         struct argp_state *state) {
 
782
        /* Get the INPUT argument from `argp_parse', which we know is
 
783
           a pointer to our plugin list pointer. */
 
784
        switch (key) {
 
785
        case 128:
 
786
          debug = true;
 
787
          break;
 
788
        case 'c':
 
789
          connect_to = arg;
 
790
          break;
 
791
        case 'i':
 
792
          interface = arg;
 
793
          break;
 
794
        case 'd':
 
795
          keydir = arg;
 
796
          break;
 
797
        case 's':
 
798
          seckeyfile = arg;
 
799
          break;
 
800
        case 'p':
 
801
          pubkeyfile = arg;
 
802
          break;
 
803
        case 129:
 
804
          errno = 0;
 
805
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
806
          if (errno){
 
807
            perror("strtol");
 
808
            exit(EXIT_FAILURE);
 
809
          }
 
810
          break;
 
811
        case 130:
 
812
          mc.priority = arg;
 
813
          break;
 
814
        case ARGP_KEY_ARG:
 
815
          argp_usage (state);
 
816
          break;
 
817
          case ARGP_KEY_END:
 
818
            break;
 
819
        default:
 
820
          return ARGP_ERR_UNKNOWN;
 
821
        }
 
822
        return 0;
 
823
      }
 
824
 
 
825
      struct argp argp = { .options = options, .parser = parse_opt,
 
826
                           .args_doc = "",
 
827
                           .doc = "Mandos client -- Get and decrypt"
 
828
                           " passwords from mandos server" };
 
829
      argp_parse (&argp, argc, argv, 0, 0, NULL);
 
830
    }
 
831
      
 
832
    pubkeyfile = combinepath(keydir, pubkeyfile);
 
833
    if (pubkeyfile == NULL){
 
834
      perror("combinepath");
 
835
      exitcode = EXIT_FAILURE;
 
836
      goto end;
 
837
    }
 
838
    
 
839
    seckeyfile = combinepath(keydir, seckeyfile);
 
840
    if (seckeyfile == NULL){
 
841
      perror("combinepath");
 
842
      goto end;
 
843
    }
 
844
 
 
845
    ret = init_gnutls_global(&mc, pubkeyfile, seckeyfile);
 
846
    if (ret == -1){
 
847
      fprintf(stderr, "init_gnutls_global\n");
 
848
      goto end;
 
849
    }
 
850
 
 
851
    uid = getuid();
 
852
    gid = getgid();
 
853
 
 
854
    ret = setuid(uid);
 
855
    if (ret == -1){
 
856
      perror("setuid");
 
857
    }
 
858
    
 
859
    setgid(gid);
 
860
    if (ret == -1){
 
861
      perror("setgid");
 
862
    }
 
863
    
 
864
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
865
    if(if_index == 0){
 
866
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
867
      exit(EXIT_FAILURE);
715
868
    }
716
869
    
717
870
    if(connect_to != NULL){
720
873
      char *address = strrchr(connect_to, ':');
721
874
      if(address == NULL){
722
875
        fprintf(stderr, "No colon in address\n");
723
 
        exit(EXIT_FAILURE);
 
876
        exitcode = EXIT_FAILURE;
 
877
        goto end;
724
878
      }
725
879
      errno = 0;
726
880
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
727
881
      if(errno){
728
882
        perror("Bad port number");
729
 
        exit(EXIT_FAILURE);
 
883
        exitcode = EXIT_FAILURE;
 
884
        goto end;
730
885
      }
731
886
      *address = '\0';
732
887
      address = connect_to;
733
 
      ret = start_mandos_communication(address, port, if_index);
 
888
      ret = start_mandos_communication(address, port, if_index, &mc);
734
889
      if(ret < 0){
735
 
        exit(EXIT_FAILURE);
 
890
        exitcode = EXIT_FAILURE;
736
891
      } else {
737
 
        exit(EXIT_SUCCESS);
 
892
        exitcode = EXIT_SUCCESS;
738
893
      }
 
894
      goto end;
739
895
    }
740
896
    
741
 
    certkey = combinepath(certdir, certkey);
742
 
    if (certkey == NULL){
743
 
      perror("combinepath");
744
 
      goto exit;
 
897
    /* If the interface is down, bring it up */
 
898
    {
 
899
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
900
      if(sd < 0) {
 
901
        perror("socket");
 
902
        exitcode = EXIT_FAILURE;
 
903
        goto end;
 
904
      }
 
905
      strcpy(network.ifr_name, interface); /* Spurious warning */
 
906
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
907
      if(ret == -1){
 
908
        perror("ioctl SIOCGIFFLAGS");
 
909
        exitcode = EXIT_FAILURE;
 
910
        goto end;
 
911
      }
 
912
      if((network.ifr_flags & IFF_UP) == 0){
 
913
        network.ifr_flags |= IFF_UP;
 
914
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
915
        if(ret == -1){
 
916
          perror("ioctl SIOCSIFFLAGS");
 
917
          exitcode = EXIT_FAILURE;
 
918
          goto end;
 
919
        }
 
920
      }
 
921
      close(sd);
745
922
    }
746
923
    
747
924
    if (not debug){
748
925
      avahi_set_log_function(empty_log);
749
926
    }
750
927
    
751
 
    /* Initialize the psuedo-RNG */
 
928
    /* Initialize the pseudo-RNG for Avahi */
752
929
    srand((unsigned int) time(NULL));
753
 
 
754
 
    /* Allocate main loop object */
755
 
    if (!(simple_poll = avahi_simple_poll_new())) {
756
 
        fprintf(stderr, "Failed to create simple poll object.\n");
757
 
        
758
 
        goto exit;
759
 
    }
760
 
 
761
 
    /* Do not publish any local records */
762
 
    avahi_server_config_init(&config);
763
 
    config.publish_hinfo = 0;
764
 
    config.publish_addresses = 0;
765
 
    config.publish_workstation = 0;
766
 
    config.publish_domain = 0;
767
 
 
768
 
    /* Allocate a new server */
769
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
770
 
                              &config, NULL, NULL, &error);
771
 
 
772
 
    /* Free the configuration data */
773
 
    avahi_server_config_free(&config);
774
 
 
775
 
    /* Check if creating the server object succeeded */
776
 
    if (!server) {
777
 
        fprintf(stderr, "Failed to create server: %s\n",
 
930
    
 
931
    /* Allocate main Avahi loop object */
 
932
    mc.simple_poll = avahi_simple_poll_new();
 
933
    if (mc.simple_poll == NULL) {
 
934
        fprintf(stderr, "Avahi: Failed to create simple poll"
 
935
                " object.\n");
 
936
        exitcode = EXIT_FAILURE;
 
937
        goto end;
 
938
    }
 
939
 
 
940
    {
 
941
      AvahiServerConfig config;
 
942
      /* Do not publish any local Zeroconf records */
 
943
      avahi_server_config_init(&config);
 
944
      config.publish_hinfo = 0;
 
945
      config.publish_addresses = 0;
 
946
      config.publish_workstation = 0;
 
947
      config.publish_domain = 0;
 
948
 
 
949
      /* Allocate a new server */
 
950
      mc.server = avahi_server_new(avahi_simple_poll_get
 
951
                                   (mc.simple_poll), &config, NULL,
 
952
                                   NULL, &error);
 
953
    
 
954
      /* Free the Avahi configuration data */
 
955
      avahi_server_config_free(&config);
 
956
    }
 
957
    
 
958
    /* Check if creating the Avahi server object succeeded */
 
959
    if (mc.server == NULL) {
 
960
        fprintf(stderr, "Failed to create Avahi server: %s\n",
778
961
                avahi_strerror(error));
779
 
        returncode = EXIT_FAILURE;
780
 
        goto exit;
 
962
        exitcode = EXIT_FAILURE;
 
963
        goto end;
781
964
    }
782
965
    
783
 
    /* Create the service browser */
784
 
    sb = avahi_s_service_browser_new(server, if_index,
 
966
    /* Create the Avahi service browser */
 
967
    sb = avahi_s_service_browser_new(mc.server, if_index,
785
968
                                     AVAHI_PROTO_INET6,
786
969
                                     "_mandos._tcp", NULL, 0,
787
 
                                     browse_callback, server);
788
 
    if (!sb) {
 
970
                                     browse_callback, &mc);
 
971
    if (sb == NULL) {
789
972
        fprintf(stderr, "Failed to create service browser: %s\n",
790
 
                avahi_strerror(avahi_server_errno(server)));
791
 
        returncode = EXIT_FAILURE;
792
 
        goto exit;
 
973
                avahi_strerror(avahi_server_errno(mc.server)));
 
974
        exitcode = EXIT_FAILURE;
 
975
        goto end;
793
976
    }
794
977
    
795
978
    /* Run the main loop */
796
979
 
797
980
    if (debug){
798
 
      fprintf(stderr, "Starting avahi loop search\n");
 
981
      fprintf(stderr, "Starting Avahi loop search\n");
799
982
    }
800
983
    
801
 
    avahi_simple_poll_loop(simple_poll);
 
984
    avahi_simple_poll_loop(mc.simple_poll);
802
985
    
803
 
 exit:
 
986
 end:
804
987
 
805
988
    if (debug){
806
989
      fprintf(stderr, "%s exiting\n", argv[0]);
807
990
    }
808
991
    
809
992
    /* Cleanup things */
810
 
    if (sb)
 
993
    if (sb != NULL)
811
994
        avahi_s_service_browser_free(sb);
812
995
    
813
 
    if (server)
814
 
        avahi_server_free(server);
 
996
    if (mc.server != NULL)
 
997
        avahi_server_free(mc.server);
815
998
 
816
 
    if (simple_poll)
817
 
        avahi_simple_poll_free(simple_poll);
818
 
    free(certfile);
819
 
    free(certkey);
 
999
    if (mc.simple_poll != NULL)
 
1000
        avahi_simple_poll_free(mc.simple_poll);
 
1001
    free(pubkeyfile);
 
1002
    free(seckeyfile);
820
1003
    
821
 
    return returncode;
 
1004
    return exitcode;
822
1005
}