/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

Added support for protocol version handling

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
#define _LARGEFILE_SOURCE
33
33
#define _FILE_OFFSET_BITS 64
34
34
 
 
35
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY() */
 
36
 
35
37
#include <stdio.h>
36
38
#include <assert.h>
37
39
#include <stdlib.h>
77
79
 
78
80
bool debug = false;
79
81
 
 
82
const char mandos_protocol_version[] = "1";
 
83
 
80
84
typedef struct {
81
 
  gnutls_session_t session;
 
85
  AvahiSimplePoll *simple_poll;
 
86
  AvahiServer *server;
82
87
  gnutls_certificate_credentials_t cred;
83
 
  gnutls_dh_params_t dh_params;
84
 
} encrypted_session;
 
88
  unsigned int dh_bits;
 
89
  const char *priority;
 
90
} mandos_context;
85
91
 
 
92
size_t adjustbuffer(char *buffer, size_t buffer_length,
 
93
                  size_t buffer_capacity){
 
94
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
 
95
    buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
 
96
    if (buffer == NULL){
 
97
      return 0;
 
98
    }
 
99
    buffer_capacity += BUFFER_SIZE;
 
100
  }
 
101
  return buffer_capacity;
 
102
}
86
103
 
87
104
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
105
                                   char **new_packet,
91
108
  gpgme_ctx_t ctx;
92
109
  gpgme_error_t rc;
93
110
  ssize_t ret;
94
 
  ssize_t new_packet_capacity = 0;
 
111
  size_t new_packet_capacity = 0;
95
112
  ssize_t new_packet_length = 0;
96
113
  gpgme_engine_info_t engine_info;
97
114
 
204
221
  
205
222
  *new_packet = 0;
206
223
  while(true){
207
 
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
208
 
      *new_packet = realloc(*new_packet,
209
 
                            (unsigned int)new_packet_capacity
210
 
                            + BUFFER_SIZE);
211
 
      if (*new_packet == NULL){
212
 
        perror("realloc");
 
224
    new_packet_capacity = adjustbuffer(*new_packet, new_packet_length,
 
225
                                       new_packet_capacity);
 
226
    if (new_packet_capacity == 0){
 
227
        perror("adjustbuffer");
213
228
        return -1;
214
229
      }
215
230
      new_packet_capacity += BUFFER_SIZE;
253
268
  fprintf(stderr, "%s", string);
254
269
}
255
270
 
256
 
static int initgnutls(encrypted_session *es){
 
271
static int initgnutls(mandos_context *mc){
257
272
  const char *err;
258
273
  int ret;
259
274
  
322
337
            safer_gnutls_strerror(ret));
323
338
  }
324
339
  
325
 
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
 
340
  if ((ret = gnutls_priority_set_direct (es->session, mc->priority, &err))
326
341
      != GNUTLS_E_SUCCESS) {
327
342
    fprintf(stderr, "Syntax error at: %s\n", err);
328
343
    fprintf(stderr, "GnuTLS error: %s\n",
351
366
                      __attribute__((unused)) const char *txt){}
352
367
 
353
368
static int start_mandos_communication(const char *ip, uint16_t port,
354
 
                                      AvahiIfIndex if_index){
 
369
                                      AvahiIfIndex if_index,
 
370
                                      mandos_context *mc){
355
371
  int ret, tcp_sd;
356
372
  struct sockaddr_in6 to;
357
373
  encrypted_session es;
360
376
  size_t buffer_length = 0;
361
377
  size_t buffer_capacity = 0;
362
378
  ssize_t decrypted_buffer_size;
363
 
  size_t written = 0;
 
379
  size_t written;
364
380
  int retval = 0;
365
381
  char interface[IF_NAMESIZE];
366
382
  
418
434
    perror("connect");
419
435
    return -1;
420
436
  }
421
 
  
 
437
 
 
438
  char *out = mandos_protocol_version;
 
439
  written = 0;
 
440
  while (true){
 
441
    size_t out_size = strlen(out);
 
442
    ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
443
                                   out_size - written));
 
444
    if (ret == -1){
 
445
      perror("write");
 
446
      retval = -1;
 
447
      goto end;
 
448
    }
 
449
    written += ret;
 
450
    if(written < out_size){
 
451
      continue;
 
452
    } else {
 
453
      if (out == mandos_protocol_version){
 
454
        written = 0;
 
455
        out = "\r\n";
 
456
      } else {
 
457
        break;
 
458
      }
 
459
    }
 
460
  }
 
461
 
422
462
  ret = initgnutls (&es);
423
463
  if (ret != 0){
424
464
    retval = -1;
451
491
  }
452
492
 
453
493
  while(true){
454
 
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
455
 
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
456
 
      if (buffer == NULL){
457
 
        perror("realloc");
458
 
        goto exit;
459
 
      }
460
 
      buffer_capacity += BUFFER_SIZE;
 
494
    buffer_capacity = adjustbuffer(buffer, buffer_length, buffer_capacity);
 
495
    if (buffer_capacity == 0){
 
496
      perror("adjustbuffer");
 
497
      retval = -1;
 
498
      goto exit;
461
499
    }
462
500
    
463
501
    ret = gnutls_record_recv
497
535
                                               &decrypted_buffer,
498
536
                                               certdir);
499
537
    if (decrypted_buffer_size >= 0){
 
538
      written = 0;
500
539
      while(written < (size_t) decrypted_buffer_size){
501
540
        ret = (int)fwrite (decrypted_buffer + written, 1,
502
541
                           (size_t)decrypted_buffer_size - written,
533
572
  return retval;
534
573
}
535
574
 
536
 
static AvahiSimplePoll *simple_poll = NULL;
537
 
static AvahiServer *server = NULL;
538
 
 
539
 
static void resolve_callback(
540
 
    AvahiSServiceResolver *r,
541
 
    AvahiIfIndex interface,
542
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
543
 
    AvahiResolverEvent event,
544
 
    const char *name,
545
 
    const char *type,
546
 
    const char *domain,
547
 
    const char *host_name,
548
 
    const AvahiAddress *address,
549
 
    uint16_t port,
550
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
551
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
552
 
    AVAHI_GCC_UNUSED void* userdata) {
553
 
    
 
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) {
 
588
  mandos_context *mc = userdata;
554
589
  assert(r);                    /* Spurious warning */
555
590
  
556
591
  /* Called whenever a service has been resolved successfully or
561
596
  case AVAHI_RESOLVER_FAILURE:
562
597
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
563
598
            " type '%s' in domain '%s': %s\n", name, type, domain,
564
 
            avahi_strerror(avahi_server_errno(server)));
 
599
            avahi_strerror(avahi_server_errno(mc->server)));
565
600
    break;
566
601
    
567
602
  case AVAHI_RESOLVER_FOUND:
572
607
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
573
608
                " port %d\n", name, host_name, ip, port);
574
609
      }
575
 
      int ret = start_mandos_communication(ip, port, interface);
 
610
      int ret = start_mandos_communication(ip, port, interface, mc);
576
611
      if (ret == 0){
577
612
        exit(EXIT_SUCCESS);
578
613
      }
581
616
  avahi_s_service_resolver_free(r);
582
617
}
583
618
 
584
 
static void browse_callback(
585
 
    AvahiSServiceBrowser *b,
586
 
    AvahiIfIndex interface,
587
 
    AvahiProtocol protocol,
588
 
    AvahiBrowserEvent event,
589
 
    const char *name,
590
 
    const char *type,
591
 
    const char *domain,
592
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
593
 
    void* userdata) {
594
 
    
595
 
    AvahiServer *s = userdata;
596
 
    assert(b);                  /* Spurious warning */
597
 
    
598
 
    /* Called whenever a new services becomes available on the LAN or
599
 
       is removed from the LAN */
600
 
    
601
 
    switch (event) {
602
 
    default:
603
 
    case AVAHI_BROWSER_FAILURE:
604
 
      
605
 
      fprintf(stderr, "(Browser) %s\n",
606
 
              avahi_strerror(avahi_server_errno(server)));
607
 
      avahi_simple_poll_quit(simple_poll);
608
 
      return;
609
 
      
610
 
    case AVAHI_BROWSER_NEW:
611
 
      /* We ignore the returned resolver object. In the callback
612
 
         function we free it. If the server is terminated before
613
 
         the callback function is called the server will free
614
 
         the resolver for us. */
615
 
      
616
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
617
 
                                         type, domain,
618
 
                                         AVAHI_PROTO_INET6, 0,
619
 
                                         resolve_callback, s)))
620
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
621
 
                avahi_strerror(avahi_server_errno(s)));
622
 
      break;
623
 
      
624
 
    case AVAHI_BROWSER_REMOVE:
625
 
      break;
626
 
      
627
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
628
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
629
 
      break;
630
 
    }
 
619
static void browse_callback( AvahiSServiceBrowser *b,
 
620
                             AvahiIfIndex interface,
 
621
                             AvahiProtocol protocol,
 
622
                             AvahiBrowserEvent event,
 
623
                             const char *name,
 
624
                             const char *type,
 
625
                             const char *domain,
 
626
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
627
                             void* userdata) {
 
628
  mandos_context *mc = userdata;
 
629
  assert(b);                    /* Spurious warning */
 
630
  
 
631
  /* Called whenever a new services becomes available on the LAN or
 
632
     is removed from the LAN */
 
633
  
 
634
  switch (event) {
 
635
  default:
 
636
  case AVAHI_BROWSER_FAILURE:
 
637
      
 
638
    fprintf(stderr, "(Browser) %s\n",
 
639
            avahi_strerror(avahi_server_errno(mc->server)));
 
640
    avahi_simple_poll_quit(mc->simple_poll);
 
641
    return;
 
642
      
 
643
  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,
 
651
                                       AVAHI_PROTO_INET6, 0,
 
652
                                       resolve_callback, mc)))
 
653
      fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
 
654
              avahi_strerror(avahi_server_errno(s)));
 
655
    break;
 
656
      
 
657
  case AVAHI_BROWSER_REMOVE:
 
658
    break;
 
659
      
 
660
  case AVAHI_BROWSER_ALL_FOR_NOW:
 
661
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
662
    break;
 
663
  }
631
664
}
632
665
 
633
666
/* Combines file name and path and returns the malloced new
662
695
    int sd;
663
696
    char *connect_to = NULL;
664
697
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
698
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
 
699
                          .dh_bits = 2048, .priority = "SECURE256"};
665
700
    
666
701
    while (true){
667
702
      static struct option long_options[] = {
671
706
        {"certdir", required_argument, 0, 'd'},
672
707
        {"certkey", required_argument, 0, 'c'},
673
708
        {"certfile", required_argument, 0, 'k'},
 
709
        {"dh_bits", required_argument, 0, 'D'},
 
710
        {"priority", required_argument, 0, 'p'},
674
711
        {0, 0, 0, 0} };
675
712
      
676
713
      int option_index = 0;
699
736
      case 'k':
700
737
        certkey = optarg;
701
738
        break;
 
739
      case 'D':
 
740
        {
 
741
          long int tmp;
 
742
          errno = 0;
 
743
          tmp = strtol(optarg, NULL, 10);
 
744
          if (errno == ERANGE){
 
745
            perror("strtol");
 
746
            exit(EXIT_FAILURE);
 
747
          }
 
748
          mc.dh_bits = tmp;
 
749
        }
 
750
        break;
 
751
      case 'p':
 
752
        mc.priority = optarg;
 
753
        break;
702
754
      default:
703
755
        exit(EXIT_FAILURE);
704
756
      }
781
833
    srand((unsigned int) time(NULL));
782
834
 
783
835
    /* Allocate main loop object */
784
 
    if (!(simple_poll = avahi_simple_poll_new())) {
 
836
    if (!(mc.simple_poll = avahi_simple_poll_new())) {
785
837
        fprintf(stderr, "Failed to create simple poll object.\n");
786
838
        returncode = EXIT_FAILURE;      
787
839
        goto exit;
795
847
    config.publish_domain = 0;
796
848
 
797
849
    /* Allocate a new server */
798
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
 
850
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
799
851
                              &config, NULL, NULL, &error);
800
852
 
801
853
    /* Free the configuration data */
802
854
    avahi_server_config_free(&config);
803
855
 
804
856
    /* Check if creating the server object succeeded */
805
 
    if (!server) {
 
857
    if (!mc.server) {
806
858
        fprintf(stderr, "Failed to create server: %s\n",
807
859
                avahi_strerror(error));
808
860
        returncode = EXIT_FAILURE;
810
862
    }
811
863
    
812
864
    /* Create the service browser */
813
 
    sb = avahi_s_service_browser_new(server, if_index,
 
865
    sb = avahi_s_service_browser_new(mc.server, if_index,
814
866
                                     AVAHI_PROTO_INET6,
815
867
                                     "_mandos._tcp", NULL, 0,
816
 
                                     browse_callback, server);
 
868
                                     browse_callback, &mc);
817
869
    if (!sb) {
818
870
        fprintf(stderr, "Failed to create service browser: %s\n",
819
 
                avahi_strerror(avahi_server_errno(server)));
 
871
                avahi_strerror(avahi_server_errno(mc.server)));
820
872
        returncode = EXIT_FAILURE;
821
873
        goto exit;
822
874
    }
839
891
    if (sb)
840
892
        avahi_s_service_browser_free(sb);
841
893
    
842
 
    if (server)
843
 
        avahi_server_free(server);
 
894
    if (mc.server)
 
895
        avahi_server_free(mc.server);
844
896
 
845
897
    if (simple_poll)
846
898
        avahi_simple_poll_free(simple_poll);