58
64
#include <string.h>             /* memset */
 
59
65
#include <arpa/inet.h>          /* inet_pton() */
 
60
66
#include <iso646.h>             /* not */
 
 
67
#include <net/if.h>             /* IF_NAMESIZE */
 
 
68
#include <argp.h>               /* struct argp_option,
 
 
69
                                   struct argp_state, struct argp,
 
63
72
#include <errno.h>              /* perror() */
 
69
75
#define BUFFER_SIZE 256
 
71
 
static int dh_bits = 1024;
 
73
78
static const char *keydir = "/conf/conf.d/mandos";
 
74
 
static const char *pubkeyfile = "pubkey.txt";
 
75
 
static const char *seckeyfile = "seckey.txt";
 
 
79
static const char mandos_protocol_version[] = "1";
 
 
80
const char *argp_program_version = "mandosclient 0.9";
 
 
81
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
 
83
/* Used for passing in values through the Avahi callback functions */
 
81
 
  gnutls_session_t session;
 
 
85
  AvahiSimplePoll *simple_poll;
 
82
87
  gnutls_certificate_credentials_t cred;
 
83
89
  gnutls_dh_params_t dh_params;
 
87
 
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
 
94
 * Make room in "buffer" for at least BUFFER_SIZE additional bytes.
 
 
95
 * "buffer_capacity" is how much is currently allocated,
 
 
96
 * "buffer_length" is how much is already used.
 
 
98
size_t adjustbuffer(char **buffer, size_t buffer_length,
 
 
99
                  size_t buffer_capacity){
 
 
100
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
 
 
101
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
 
 
105
    buffer_capacity += BUFFER_SIZE;
 
 
107
  return buffer_capacity;
 
 
111
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
 
 
112
 * Returns -1 on error
 
 
114
static ssize_t pgp_packet_decrypt (const char *cryptotext,
 
89
117
                                   const char *homedir){
 
90
118
  gpgme_data_t dh_crypto, dh_plain;
 
94
 
  ssize_t new_packet_capacity = 0;
 
95
 
  ssize_t new_packet_length = 0;
 
 
122
  size_t plaintext_capacity = 0;
 
 
123
  ssize_t plaintext_length = 0;
 
96
124
  gpgme_engine_info_t engine_info;
 
99
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
 
127
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
 
149
179
  if (rc != GPG_ERR_NO_ERROR){
 
150
180
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
 
151
181
            gpgme_strsource(rc), gpgme_strerror(rc));
 
 
182
    plaintext_length = -1;
 
155
 
  /* Decrypt data from the FILE pointer to the plaintext data
 
 
186
  /* Decrypt data from the cryptotext data buffer to the plaintext
 
157
188
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
 
158
189
  if (rc != GPG_ERR_NO_ERROR){
 
159
190
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
 
160
191
            gpgme_strsource(rc), gpgme_strerror(rc));
 
 
192
    plaintext_length = -1;
 
165
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
 
 
197
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
 
169
201
    gpgme_decrypt_result_t result;
 
170
202
    result = gpgme_op_decrypt_result(ctx);
 
 
197
 
  /* Delete the GPGME FILE pointer cryptotext data buffer */
 
198
 
  gpgme_data_release(dh_crypto);
 
200
229
  /* Seek back to the beginning of the GPGME plaintext data buffer */
 
201
230
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
 
202
231
    perror("pgpme_data_seek");
 
 
232
    plaintext_length = -1;
 
207
 
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
 
208
 
      *new_packet = realloc(*new_packet,
 
209
 
                            (unsigned int)new_packet_capacity
 
211
 
      if (*new_packet == NULL){
 
215
 
      new_packet_capacity += BUFFER_SIZE;
 
 
238
    plaintext_capacity = adjustbuffer(plaintext,
 
 
239
                                      (size_t)plaintext_length,
 
 
241
    if (plaintext_capacity == 0){
 
 
242
        perror("adjustbuffer");
 
 
243
        plaintext_length = -1;
 
218
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
 
247
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
 
220
249
    /* Print the data, if any */
 
225
255
      perror("gpgme_data_read");
 
 
256
      plaintext_length = -1;
 
228
 
    new_packet_length += ret;
 
 
259
    plaintext_length += ret;
 
231
 
  /* FIXME: check characters before printing to screen so to not print
 
232
 
     terminal control characters */
 
234
 
  /*     fprintf(stderr, "decrypted password is: "); */
 
235
 
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
 
236
 
  /*     fprintf(stderr, "\n"); */
 
 
263
    fprintf(stderr, "Decrypted password is: ");
 
 
264
    for(ssize_t i = 0; i < plaintext_length; i++){
 
 
265
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
 
 
267
    fprintf(stderr, "\n");
 
 
272
  /* Delete the GPGME cryptotext data buffer */
 
 
273
  gpgme_data_release(dh_crypto);
 
239
275
  /* Delete the GPGME plaintext data buffer */
 
240
276
  gpgme_data_release(dh_plain);
 
241
 
  return new_packet_length;
 
 
277
  return plaintext_length;
 
244
280
static const char * safer_gnutls_strerror (int value) {
 
 
264
302
  if ((ret = gnutls_global_init ())
 
265
303
      != GNUTLS_E_SUCCESS) {
 
266
 
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
 
 
304
    fprintf (stderr, "GnuTLS global_init: %s\n",
 
 
305
             safer_gnutls_strerror(ret));
 
 
310
    /* "Use a log level over 10 to enable all debugging options."
 
271
313
    gnutls_global_set_log_level(11);
 
272
314
    gnutls_global_set_log_function(debuggnutls);
 
275
 
  /* openpgp credentials */
 
276
 
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
 
 
317
  /* OpenPGP credentials */
 
 
318
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
 
277
319
      != GNUTLS_E_SUCCESS) {
 
278
 
    fprintf (stderr, "memory error: %s\n",
 
 
320
    fprintf (stderr, "GnuTLS memory error: %s\n",
 
279
321
             safer_gnutls_strerror(ret));
 
 
322
    gnutls_global_deinit ();
 
 
289
332
  ret = gnutls_certificate_set_openpgp_key_file
 
290
 
    (es->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
 
333
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
291
334
  if (ret != GNUTLS_E_SUCCESS) {
 
293
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
 
295
 
       ret, pubkeyfile, seckeyfile);
 
296
 
    fprintf(stdout, "The Error is: %s\n",
 
 
336
            "Error[%d] while reading the OpenPGP key pair ('%s',"
 
 
337
            " '%s')\n", ret, pubkeyfile, seckeyfile);
 
 
338
    fprintf(stdout, "The GnuTLS error is: %s\n",
 
297
339
            safer_gnutls_strerror(ret));
 
301
 
  //GnuTLS server initialization
 
302
 
  if ((ret = gnutls_dh_params_init (&es->dh_params))
 
303
 
      != GNUTLS_E_SUCCESS) {
 
304
 
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
 
305
 
             safer_gnutls_strerror(ret));
 
309
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, dh_bits))
 
310
 
      != GNUTLS_E_SUCCESS) {
 
311
 
    fprintf (stderr, "Error in prime generation: %s\n",
 
312
 
             safer_gnutls_strerror(ret));
 
316
 
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
 
318
 
  // GnuTLS session creation
 
319
 
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
 
320
 
      != GNUTLS_E_SUCCESS){
 
 
343
  /* GnuTLS server initialization */
 
 
344
  ret = gnutls_dh_params_init(&mc->dh_params);
 
 
345
  if (ret != GNUTLS_E_SUCCESS) {
 
 
346
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
 
 
347
             " %s\n", safer_gnutls_strerror(ret));
 
 
350
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
 
351
  if (ret != GNUTLS_E_SUCCESS) {
 
 
352
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
 
 
353
             safer_gnutls_strerror(ret));
 
 
357
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
 
 
363
  gnutls_certificate_free_credentials (mc->cred);
 
 
364
  gnutls_global_deinit ();
 
 
369
static int init_gnutls_session(mandos_context *mc,
 
 
370
                               gnutls_session_t *session){
 
 
372
  /* GnuTLS session creation */
 
 
373
  ret = gnutls_init(session, GNUTLS_SERVER);
 
 
374
  if (ret != GNUTLS_E_SUCCESS){
 
321
375
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
 
322
376
            safer_gnutls_strerror(ret));
 
325
 
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
 
326
 
      != GNUTLS_E_SUCCESS) {
 
327
 
    fprintf(stderr, "Syntax error at: %s\n", err);
 
328
 
    fprintf(stderr, "GnuTLS error: %s\n",
 
329
 
            safer_gnutls_strerror(ret));
 
 
381
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
 
 
382
    if (ret != GNUTLS_E_SUCCESS) {
 
 
383
      fprintf(stderr, "Syntax error at: %s\n", err);
 
 
384
      fprintf(stderr, "GnuTLS error: %s\n",
 
 
385
              safer_gnutls_strerror(ret));
 
 
386
      gnutls_deinit (*session);
 
333
 
  if ((ret = gnutls_credentials_set
 
334
 
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
 
335
 
      != GNUTLS_E_SUCCESS) {
 
336
 
    fprintf(stderr, "Error setting a credentials set: %s\n",
 
 
391
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
 
393
  if (ret != GNUTLS_E_SUCCESS) {
 
 
394
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
 
337
395
            safer_gnutls_strerror(ret));
 
 
396
    gnutls_deinit (*session);
 
341
400
  /* ignore client certificate if any. */
 
342
 
  gnutls_certificate_server_set_request (es->session,
 
 
401
  gnutls_certificate_server_set_request (*session,
 
343
402
                                         GNUTLS_CERT_IGNORE);
 
345
 
  gnutls_dh_set_prime_bits (es->session, dh_bits);
 
 
404
  gnutls_dh_set_prime_bits (*session, mc->dh_bits);
 
 
409
/* Avahi log function callback */
 
350
410
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
351
411
                      __attribute__((unused)) const char *txt){}
 
 
413
/* Called when a Mandos server is found */
 
353
414
static int start_mandos_communication(const char *ip, uint16_t port,
 
354
 
                                      AvahiIfIndex if_index){
 
 
415
                                      AvahiIfIndex if_index,
 
356
 
  struct sockaddr_in6 to;
 
357
 
  encrypted_session es;
 
 
418
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
 
358
419
  char *buffer = NULL;
 
359
420
  char *decrypted_buffer;
 
360
421
  size_t buffer_length = 0;
 
361
422
  size_t buffer_capacity = 0;
 
362
423
  ssize_t decrypted_buffer_size;
 
365
426
  char interface[IF_NAMESIZE];
 
 
427
  gnutls_session_t session;
 
 
429
  ret = init_gnutls_session (mc, &session);
 
368
435
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
 
 
374
441
    perror("socket");
 
378
 
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
 
446
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
380
447
      perror("if_indextoname");
 
386
450
    fprintf(stderr, "Binding to interface %s\n", interface);
 
389
453
  memset(&to,0,sizeof(to));     /* Spurious warning */
 
390
 
  to.sin6_family = AF_INET6;
 
391
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
 
 
454
  to.in6.sin6_family = AF_INET6;
 
 
455
  /* It would be nice to have a way to detect if we were passed an
 
 
456
     IPv4 address here.   Now we assume an IPv6 address. */
 
 
457
  ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
 
393
459
    perror("inet_pton");
 
397
463
    fprintf(stderr, "Bad address: %s\n", ip);
 
400
 
  to.sin6_port = htons(port);   /* Spurious warning */
 
 
466
  to.in6.sin6_port = htons(port);       /* Spurious warning */
 
402
 
  to.sin6_scope_id = (uint32_t)if_index;
 
 
468
  to.in6.sin6_scope_id = (uint32_t)if_index;
 
405
471
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
 
406
472
    char addrstr[INET6_ADDRSTRLEN] = "";
 
407
 
    if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
 
 
473
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
 
408
474
                 sizeof(addrstr)) == NULL){
 
409
475
      perror("inet_ntop");
 
411
477
      if(strcmp(addrstr, ip) != 0){
 
412
 
        fprintf(stderr, "Canonical address form: %s\n",
 
413
 
                addrstr, ntohs(to.sin6_port));
 
 
478
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
 
418
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
 
 
483
  ret = connect(tcp_sd, &to.in, sizeof(to));
 
420
485
    perror("connect");
 
424
 
  ret = initgnutls (&es);
 
 
489
  const char *out = mandos_protocol_version;
 
 
492
    size_t out_size = strlen(out);
 
 
493
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
 
494
                                   out_size - written));
 
 
500
    written += (size_t)ret;
 
 
501
    if(written < out_size){
 
 
504
      if (out == mandos_protocol_version){
 
430
 
  gnutls_transport_set_ptr (es.session,
 
431
 
                            (gnutls_transport_ptr_t) tcp_sd);
 
434
514
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
437
 
  ret = gnutls_handshake (es.session);
 
 
517
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
 
 
519
  ret = gnutls_handshake (session);
 
439
521
  if (ret != GNUTLS_E_SUCCESS){
 
441
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
 
523
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
442
524
      gnutls_perror (ret);
 
448
 
  //Retrieve OpenPGP packet that contains the wanted password
 
 
530
  /* Read OpenPGP packet that contains the wanted password */
 
451
533
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
 
473
554
      case GNUTLS_E_AGAIN:
 
475
556
      case GNUTLS_E_REHANDSHAKE:
 
476
 
        ret = gnutls_handshake (es.session);
 
 
557
        ret = gnutls_handshake (session);
 
478
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
 
 
559
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
479
560
          gnutls_perror (ret);
 
485
566
        fprintf(stderr, "Unknown error while reading data from"
 
486
 
                " encrypted session with mandos server\n");
 
 
567
                " encrypted session with Mandos server\n");
 
488
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
 
569
        gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
492
573
      buffer_length += (size_t) ret;
 
 
578
    fprintf(stderr, "Closing TLS session\n");
 
 
581
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
 
496
583
  if (buffer_length > 0){
 
497
584
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
499
586
                                               &decrypted_buffer,
 
501
588
    if (decrypted_buffer_size >= 0){
 
502
590
      while(written < (size_t) decrypted_buffer_size){
 
503
591
        ret = (int)fwrite (decrypted_buffer + written, 1,
 
504
592
                           (size_t)decrypted_buffer_size - written,
 
 
525
 
    fprintf(stderr, "Closing TLS session\n");
 
 
610
  /* Shutdown procedure */
 
529
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
 
532
 
  gnutls_deinit (es.session);
 
533
 
  gnutls_certificate_free_credentials (es.cred);
 
534
 
  gnutls_global_deinit ();
 
 
615
  gnutls_deinit (session);
 
538
 
static AvahiSimplePoll *simple_poll = NULL;
 
539
 
static AvahiServer *server = NULL;
 
541
 
static void resolve_callback(
 
542
 
    AvahiSServiceResolver *r,
 
543
 
    AvahiIfIndex interface,
 
544
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
545
 
    AvahiResolverEvent event,
 
549
 
    const char *host_name,
 
550
 
    const AvahiAddress *address,
 
552
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
 
553
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
554
 
    AVAHI_GCC_UNUSED void* userdata) {
 
 
619
static void resolve_callback(AvahiSServiceResolver *r,
 
 
620
                             AvahiIfIndex interface,
 
 
621
                             AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
 
622
                             AvahiResolverEvent event,
 
 
626
                             const char *host_name,
 
 
627
                             const AvahiAddress *address,
 
 
629
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
 
 
630
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
 
633
  mandos_context *mc = userdata;
 
556
634
  assert(r);                    /* Spurious warning */
 
558
636
  /* Called whenever a service has been resolved successfully or
 
 
583
661
  avahi_s_service_resolver_free(r);
 
586
 
static void browse_callback(
 
587
 
    AvahiSServiceBrowser *b,
 
588
 
    AvahiIfIndex interface,
 
589
 
    AvahiProtocol protocol,
 
590
 
    AvahiBrowserEvent event,
 
594
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
597
 
    AvahiServer *s = userdata;
 
598
 
    assert(b);                  /* Spurious warning */
 
600
 
    /* Called whenever a new services becomes available on the LAN or
 
601
 
       is removed from the LAN */
 
605
 
    case AVAHI_BROWSER_FAILURE:
 
607
 
      fprintf(stderr, "(Browser) %s\n",
 
608
 
              avahi_strerror(avahi_server_errno(server)));
 
609
 
      avahi_simple_poll_quit(simple_poll);
 
612
 
    case AVAHI_BROWSER_NEW:
 
613
 
      /* We ignore the returned resolver object. In the callback
 
614
 
         function we free it. If the server is terminated before
 
615
 
         the callback function is called the server will free
 
616
 
         the resolver for us. */
 
618
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
 
620
 
                                         AVAHI_PROTO_INET6, 0,
 
621
 
                                         resolve_callback, s)))
 
622
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
 
623
 
                avahi_strerror(avahi_server_errno(s)));
 
626
 
    case AVAHI_BROWSER_REMOVE:
 
629
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
 
630
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
 
664
static void browse_callback( AvahiSServiceBrowser *b,
 
 
665
                             AvahiIfIndex interface,
 
 
666
                             AvahiProtocol protocol,
 
 
667
                             AvahiBrowserEvent event,
 
 
671
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
 
674
  mandos_context *mc = userdata;
 
 
675
  assert(b);                    /* Spurious warning */
 
 
677
  /* Called whenever a new services becomes available on the LAN or
 
 
678
     is removed from the LAN */
 
 
682
  case AVAHI_BROWSER_FAILURE:
 
 
684
    fprintf(stderr, "(Avahi browser) %s\n",
 
 
685
            avahi_strerror(avahi_server_errno(mc->server)));
 
 
686
    avahi_simple_poll_quit(mc->simple_poll);
 
 
689
  case AVAHI_BROWSER_NEW:
 
 
690
    /* We ignore the returned Avahi resolver object. In the callback
 
 
691
       function we free it. If the Avahi server is terminated before
 
 
692
       the callback function is called the Avahi server will free the
 
 
695
    if (!(avahi_s_service_resolver_new(mc->server, interface,
 
 
696
                                       protocol, name, type, domain,
 
 
697
                                       AVAHI_PROTO_INET6, 0,
 
 
698
                                       resolve_callback, mc)))
 
 
699
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
 
 
700
              name, avahi_strerror(avahi_server_errno(mc->server)));
 
 
703
  case AVAHI_BROWSER_REMOVE:
 
 
706
  case AVAHI_BROWSER_ALL_FOR_NOW:
 
 
707
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
 
709
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
635
715
/* Combines file name and path and returns the malloced new
 
 
645
 
    memcpy(tmp, first, f_len);
 
 
725
    memcpy(tmp, first, f_len);  /* Spurious warning */
 
647
727
  tmp[f_len] = '/';
 
649
 
    memcpy(tmp + f_len + 1, second, s_len);
 
 
729
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
 
651
731
  tmp[f_len + 1 + s_len] = '\0';
 
656
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
 
657
 
    AvahiServerConfig config;
 
 
736
int main(int argc, char *argv[]){
 
658
737
    AvahiSServiceBrowser *sb = NULL;
 
662
 
    int returncode = EXIT_SUCCESS;
 
663
 
    const char *interface = NULL;
 
 
740
    int exitcode = EXIT_SUCCESS;
 
 
741
    const char *interface = "eth0";
 
 
742
    struct ifreq network;
 
 
746
    char *connect_to = NULL;
 
664
747
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
665
 
    char *connect_to = NULL;
 
 
748
    const char *pubkeyfile = "pubkey.txt";
 
 
749
    const char *seckeyfile = "seckey.txt";
 
 
750
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
 
 
751
                          .dh_bits = 1024, .priority = "SECURE256"};
 
 
752
    bool gnutls_initalized = false;
 
667
 
    debug_int = debug ? 1 : 0;
 
669
 
      static struct option long_options[] = {
 
670
 
        {"debug", no_argument, &debug_int, 1},
 
671
 
        {"connect", required_argument, NULL, 'C'},
 
672
 
        {"interface", required_argument, NULL, 'i'},
 
673
 
        {"keydir", required_argument, NULL, 'd'},
 
674
 
        {"seckey", required_argument, NULL, 'c'},
 
675
 
        {"pubkey", required_argument, NULL, 'k'},
 
676
 
        {"dh-bits", required_argument, NULL, 'D'},
 
679
 
      int option_index = 0;
 
680
 
      ret = getopt_long (argc, argv, "i:", long_options,
 
706
 
        dh_bits = atoi(optarg);
 
 
755
      struct argp_option options[] = {
 
 
756
        { .name = "debug", .key = 128,
 
 
757
          .doc = "Debug mode", .group = 3 },
 
 
758
        { .name = "connect", .key = 'c',
 
 
760
          .doc = "Connect directly to a sepcified mandos server",
 
 
762
        { .name = "interface", .key = 'i',
 
 
764
          .doc = "Interface that Avahi will conntect through",
 
 
766
        { .name = "keydir", .key = 'd',
 
 
768
          .doc = "Directory where the openpgp keyring is",
 
 
770
        { .name = "seckey", .key = 's',
 
 
772
          .doc = "Secret openpgp key for gnutls authentication",
 
 
774
        { .name = "pubkey", .key = 'p',
 
 
776
          .doc = "Public openpgp key for gnutls authentication",
 
 
778
        { .name = "dh-bits", .key = 129,
 
 
780
          .doc = "dh-bits to use in gnutls communication",
 
 
782
        { .name = "priority", .key = 130,
 
 
784
          .doc = "GNUTLS priority", .group = 1 },
 
 
789
      error_t parse_opt (int key, char *arg,
 
 
790
                         struct argp_state *state) {
 
 
791
        /* Get the INPUT argument from `argp_parse', which we know is
 
 
792
           a pointer to our plugin list pointer. */
 
 
814
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
 
829
          return ARGP_ERR_UNKNOWN;
 
 
834
      struct argp argp = { .options = options, .parser = parse_opt,
 
 
836
                           .doc = "Mandos client -- Get and decrypt"
 
 
837
                           " passwords from mandos server" };
 
 
838
      argp_parse (&argp, argc, argv, 0, 0, NULL);
 
714
 
    debug = debug_int ? true : false;
 
716
841
    pubkeyfile = combinepath(keydir, pubkeyfile);
 
717
842
    if (pubkeyfile == NULL){
 
718
843
      perror("combinepath");
 
722
 
    if(interface != NULL){
 
723
 
      if_index = (AvahiIfIndex) if_nametoindex(interface);
 
725
 
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
 
844
      exitcode = EXIT_FAILURE;
 
 
848
    seckeyfile = combinepath(keydir, seckeyfile);
 
 
849
    if (seckeyfile == NULL){
 
 
850
      perror("combinepath");
 
 
854
    ret = init_gnutls_global(&mc, pubkeyfile, seckeyfile);
 
 
856
      fprintf(stderr, "init_gnutls_global\n");
 
 
859
      gnutls_initalized = true;
 
 
875
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
 
877
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
730
881
    if(connect_to != NULL){
 
 
733
884
      char *address = strrchr(connect_to, ':');
 
734
885
      if(address == NULL){
 
735
886
        fprintf(stderr, "No colon in address\n");
 
 
887
        exitcode = EXIT_FAILURE;
 
739
891
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
 
741
893
        perror("Bad port number");
 
 
894
        exitcode = EXIT_FAILURE;
 
745
898
      address = connect_to;
 
746
 
      ret = start_mandos_communication(address, port, if_index);
 
 
899
      ret = start_mandos_communication(address, port, if_index, &mc);
 
 
901
        exitcode = EXIT_FAILURE;
 
 
903
        exitcode = EXIT_SUCCESS;
 
754
 
    seckeyfile = combinepath(keydir, seckeyfile);
 
755
 
    if (seckeyfile == NULL){
 
756
 
      perror("combinepath");
 
 
908
    /* If the interface is down, bring it up */
 
 
910
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
 
913
        exitcode = EXIT_FAILURE;
 
 
916
      strcpy(network.ifr_name, interface); /* Spurious warning */
 
 
917
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
 
919
        perror("ioctl SIOCGIFFLAGS");
 
 
920
        exitcode = EXIT_FAILURE;
 
 
923
      if((network.ifr_flags & IFF_UP) == 0){
 
 
924
        network.ifr_flags |= IFF_UP;
 
 
925
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
 
927
          perror("ioctl SIOCSIFFLAGS");
 
 
928
          exitcode = EXIT_FAILURE;
 
761
936
      avahi_set_log_function(empty_log);
 
764
 
    /* Initialize the psuedo-RNG */
 
 
939
    /* Initialize the pseudo-RNG for Avahi */
 
765
940
    srand((unsigned int) time(NULL));
 
767
 
    /* Allocate main loop object */
 
768
 
    if (!(simple_poll = avahi_simple_poll_new())) {
 
769
 
        fprintf(stderr, "Failed to create simple poll object.\n");
 
774
 
    /* Do not publish any local records */
 
775
 
    avahi_server_config_init(&config);
 
776
 
    config.publish_hinfo = 0;
 
777
 
    config.publish_addresses = 0;
 
778
 
    config.publish_workstation = 0;
 
779
 
    config.publish_domain = 0;
 
781
 
    /* Allocate a new server */
 
782
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
783
 
                              &config, NULL, NULL, &error);
 
785
 
    /* Free the configuration data */
 
786
 
    avahi_server_config_free(&config);
 
788
 
    /* Check if creating the server object succeeded */
 
790
 
        fprintf(stderr, "Failed to create server: %s\n",
 
 
942
    /* Allocate main Avahi loop object */
 
 
943
    mc.simple_poll = avahi_simple_poll_new();
 
 
944
    if (mc.simple_poll == NULL) {
 
 
945
        fprintf(stderr, "Avahi: Failed to create simple poll"
 
 
947
        exitcode = EXIT_FAILURE;
 
 
952
      AvahiServerConfig config;
 
 
953
      /* Do not publish any local Zeroconf records */
 
 
954
      avahi_server_config_init(&config);
 
 
955
      config.publish_hinfo = 0;
 
 
956
      config.publish_addresses = 0;
 
 
957
      config.publish_workstation = 0;
 
 
958
      config.publish_domain = 0;
 
 
960
      /* Allocate a new server */
 
 
961
      mc.server = avahi_server_new(avahi_simple_poll_get
 
 
962
                                   (mc.simple_poll), &config, NULL,
 
 
965
      /* Free the Avahi configuration data */
 
 
966
      avahi_server_config_free(&config);
 
 
969
    /* Check if creating the Avahi server object succeeded */
 
 
970
    if (mc.server == NULL) {
 
 
971
        fprintf(stderr, "Failed to create Avahi server: %s\n",
 
791
972
                avahi_strerror(error));
 
792
 
        returncode = EXIT_FAILURE;
 
 
973
        exitcode = EXIT_FAILURE;
 
796
 
    /* Create the service browser */
 
797
 
    sb = avahi_s_service_browser_new(server, if_index,
 
 
977
    /* Create the Avahi service browser */
 
 
978
    sb = avahi_s_service_browser_new(mc.server, if_index,
 
798
979
                                     AVAHI_PROTO_INET6,
 
799
980
                                     "_mandos._tcp", NULL, 0,
 
800
 
                                     browse_callback, server);
 
 
981
                                     browse_callback, &mc);
 
802
983
        fprintf(stderr, "Failed to create service browser: %s\n",
 
803
 
                avahi_strerror(avahi_server_errno(server)));
 
804
 
        returncode = EXIT_FAILURE;
 
 
984
                avahi_strerror(avahi_server_errno(mc.server)));
 
 
985
        exitcode = EXIT_FAILURE;
 
808
989
    /* Run the main loop */
 
811
 
      fprintf(stderr, "Starting avahi loop search\n");
 
 
992
      fprintf(stderr, "Starting Avahi loop search\n");
 
814
 
    avahi_simple_poll_loop(simple_poll);
 
 
995
    avahi_simple_poll_loop(mc.simple_poll);
 
819
1000
      fprintf(stderr, "%s exiting\n", argv[0]);
 
822
1003
    /* Cleanup things */
 
824
1005
        avahi_s_service_browser_free(sb);
 
827
 
        avahi_server_free(server);
 
 
1007
    if (mc.server != NULL)
 
 
1008
        avahi_server_free(mc.server);
 
830
 
        avahi_simple_poll_free(simple_poll);
 
 
1010
    if (mc.simple_poll != NULL)
 
 
1011
        avahi_simple_poll_free(mc.simple_poll);
 
831
1012
    free(pubkeyfile);
 
832
1013
    free(seckeyfile);
 
 
1015
    if (gnutls_initalized){
 
 
1016
      gnutls_certificate_free_credentials (mc.cred);
 
 
1017
      gnutls_global_deinit ();