/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugins.d/mandosclient.c

merge +
mandosclient
        Added a adjustbuffer function.

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