/mandos/release

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

« back to all changes in this revision

Viewing changes to plugins.d/mandosclient.c

  • Committer: Björn Påhlsson
  • Date: 2008-08-03 14:57:46 UTC
  • mto: (237.7.1 mandos) (24.1.154 mandos)
  • mto: This revision was merged to the branch mainline in revision 41.
  • Revision ID: belorn@braxen-20080803145746-4boahihngi1uwjap
merge commit

Show diffs side-by-side

added added

removed removed

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