/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-08-03 16:05:52 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080803160552-mvqy5klry3wn57x1
* plugins.d/mandosclient.c (initgnutls): Moved "err" variable into its
                                         own code block.
  (start_mandos_communication): Moved call to "initgnutls" to
                                beginning.  Renamed label "exit" to
                                "mandos_end".  Bug fix: set return
                                code if failure to realloc buffer.
                                Close TLS session as early as
                                possible.
  (resolve_callback): Also print interface number when debugging.
  (main): Moved "debug_int" and "config" into their own respective
          code blocks.

Show diffs side-by-side

added added

removed removed

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