/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugins.d/mandosclient.c

merge

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