/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

  • Committer: Teddy Hogeborn
  • Date: 2008-07-31 19:51:44 UTC
  • mfrom: (24.1.5 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080731195144-yb37wz2sr1e6b3m4
Merge.

Show diffs side-by-side

added added

removed removed

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