/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

merge +
mandosclient
        Added a adjustbuffer function.

Show diffs side-by-side

added added

removed removed

Lines of Context:
65
65
#include <arpa/inet.h>          /* inet_pton() */
66
66
#include <iso646.h>             /* not */
67
67
#include <net/if.h>             /* IF_NAMESIZE */
68
 
#include <argp.h>               /* struct argp_option,
69
 
                                   struct argp_state, struct argp,
70
 
                                   argp_parse() */
 
68
 
71
69
/* GPGME */
72
70
#include <errno.h>              /* perror() */
73
71
#include <gpgme.h>
74
72
 
 
73
/* getopt_long */
 
74
#include <getopt.h>
 
75
 
75
76
#define BUFFER_SIZE 256
76
77
 
 
78
static const char *keydir = "/conf/conf.d/mandos";
 
79
static const char *pubkeyfile = "pubkey.txt";
 
80
static const char *seckeyfile = "seckey.txt";
 
81
 
77
82
bool debug = false;
78
 
static const char *keydir = "/conf/conf.d/mandos";
79
 
const char *argp_program_version = "mandosclient 0.9";
80
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
81
 
static const char mandos_protocol_version[] = "1";
82
 
 
83
 
/* Used for passing in values through the Avahi callback functions */
 
83
 
 
84
const char mandos_protocol_version[] = "1";
 
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;
87
90
  gnutls_certificate_credentials_t cred;
88
91
  unsigned int dh_bits;
89
 
  gnutls_dh_params_t dh_params;
90
92
  const char *priority;
91
93
} mandos_context;
92
94
 
93
 
/* Make room in "buffer" for at least BUFFER_SIZE additional bytes.
94
 
 * "buffer_capacity" is how much is currently allocated,
95
 
 * "buffer_length" is how much is already used. */
96
95
size_t adjustbuffer(char **buffer, size_t buffer_length,
97
96
                  size_t buffer_capacity){
98
97
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
233
232
  
234
233
  *plaintext = NULL;
235
234
  while(true){
236
 
    plaintext_capacity = adjustbuffer(plaintext,
237
 
                                      (size_t)plaintext_length,
 
235
    plaintext_capacity = adjustbuffer(plaintext, (size_t)plaintext_length,
238
236
                                      plaintext_capacity);
239
237
    if (plaintext_capacity == 0){
240
238
        perror("adjustbuffer");
288
286
  fprintf(stderr, "GnuTLS: %s", string);
289
287
}
290
288
 
291
 
static int init_gnutls_global(mandos_context *mc,
292
 
                              const char *pubkeyfile,
293
 
                              const char *seckeyfile){
 
289
static int initgnutls(mandos_context *mc, gnutls_session_t *session,
 
290
                      gnutls_dh_params_t *dh_params){
294
291
  int ret;
295
292
  
296
293
  if(debug){
338
335
  }
339
336
  
340
337
  /* GnuTLS server initialization */
341
 
  ret = gnutls_dh_params_init(&mc->dh_params);
 
338
  ret = gnutls_dh_params_init(dh_params);
342
339
  if (ret != GNUTLS_E_SUCCESS) {
343
340
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
344
341
             " %s\n", safer_gnutls_strerror(ret));
345
342
    return -1;
346
343
  }
347
 
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
344
  ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits);
348
345
  if (ret != GNUTLS_E_SUCCESS) {
349
346
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
350
347
             safer_gnutls_strerror(ret));
351
348
    return -1;
352
349
  }
353
350
  
354
 
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
355
 
 
356
 
  return 0;
357
 
}
358
 
 
359
 
static int init_gnutls_session(mandos_context *mc,
360
 
                               gnutls_session_t *session){
361
 
  int ret;
 
351
  gnutls_certificate_set_dh_params(mc->cred, *dh_params);
 
352
  
362
353
  /* GnuTLS session creation */
363
354
  ret = gnutls_init(session, GNUTLS_SERVER);
364
355
  if (ret != GNUTLS_E_SUCCESS){
403
394
                                      AvahiIfIndex if_index,
404
395
                                      mandos_context *mc){
405
396
  int ret, tcp_sd;
406
 
  union { struct sockaddr in; struct sockaddr_in6 in6; } to;
 
397
  struct sockaddr_in6 to;
407
398
  char *buffer = NULL;
408
399
  char *decrypted_buffer;
409
400
  size_t buffer_length = 0;
413
404
  int retval = 0;
414
405
  char interface[IF_NAMESIZE];
415
406
  gnutls_session_t session;
 
407
  gnutls_dh_params_t dh_params;
416
408
  
417
 
  ret = init_gnutls_session (mc, &session);
 
409
  ret = initgnutls (mc, &session, &dh_params);
418
410
  if (ret != 0){
419
411
    return -1;
420
412
  }
439
431
  }
440
432
  
441
433
  memset(&to,0,sizeof(to));     /* Spurious warning */
442
 
  to.in6.sin6_family = AF_INET6;
 
434
  to.sin6_family = AF_INET6;
443
435
  /* It would be nice to have a way to detect if we were passed an
444
436
     IPv4 address here.   Now we assume an IPv6 address. */
445
 
  ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
 
437
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
446
438
  if (ret < 0 ){
447
439
    perror("inet_pton");
448
440
    return -1;
451
443
    fprintf(stderr, "Bad address: %s\n", ip);
452
444
    return -1;
453
445
  }
454
 
  to.in6.sin6_port = htons(port);       /* Spurious warning */
 
446
  to.sin6_port = htons(port);   /* Spurious warning */
455
447
  
456
 
  to.in6.sin6_scope_id = (uint32_t)if_index;
 
448
  to.sin6_scope_id = (uint32_t)if_index;
457
449
  
458
450
  if(debug){
459
451
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
460
452
    char addrstr[INET6_ADDRSTRLEN] = "";
461
 
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
 
453
    if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
462
454
                 sizeof(addrstr)) == NULL){
463
455
      perror("inet_ntop");
464
456
    } else {
468
460
    }
469
461
  }
470
462
  
471
 
  ret = connect(tcp_sd, &to.in, sizeof(to));
 
463
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
472
464
  if (ret < 0){
473
465
    perror("connect");
474
466
    return -1;
523
515
  }
524
516
 
525
517
  while(true){
526
 
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
527
 
                                   buffer_capacity);
 
518
    buffer_capacity = adjustbuffer(&buffer, buffer_length, buffer_capacity);
528
519
    if (buffer_capacity == 0){
529
520
      perror("adjustbuffer");
530
521
      retval = -1;
731
722
    const char *interface = "eth0";
732
723
    struct ifreq network;
733
724
    int sd;
734
 
    uid_t uid;
735
 
    gid_t gid;
736
725
    char *connect_to = NULL;
737
726
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
738
 
    const char *pubkeyfile = "pubkey.txt";
739
 
    const char *seckeyfile = "seckey.txt";
740
727
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
741
728
                          .dh_bits = 1024, .priority = "SECURE256"};
742
729
    
743
730
    {
744
 
      struct argp_option options[] = {
745
 
        { .name = "debug", .key = 128,
746
 
          .doc = "Debug mode", .group = 3 },
747
 
        { .name = "connect", .key = 'c',
748
 
          .arg = "IP",
749
 
          .doc = "Connect directly to a sepcified mandos server",
750
 
          .group = 1 },
751
 
        { .name = "interface", .key = 'i',
752
 
          .arg = "INTERFACE",
753
 
          .doc = "Interface that Avahi will conntect through",
754
 
          .group = 1 },
755
 
        { .name = "keydir", .key = 'd',
756
 
          .arg = "KEYDIR",
757
 
          .doc = "Directory where the openpgp keyring is",
758
 
          .group = 1 },
759
 
        { .name = "seckey", .key = 's',
760
 
          .arg = "SECKEY",
761
 
          .doc = "Secret openpgp key for gnutls authentication",
762
 
          .group = 1 },
763
 
        { .name = "pubkey", .key = 'p',
764
 
          .arg = "PUBKEY",
765
 
          .doc = "Public openpgp key for gnutls authentication",
766
 
          .group = 2 },
767
 
        { .name = "dh-bits", .key = 129,
768
 
          .arg = "BITS",
769
 
          .doc = "dh-bits to use in gnutls communication",
770
 
          .group = 2 },
771
 
        { .name = "priority", .key = 130,
772
 
          .arg = "PRIORITY",
773
 
          .doc = "GNUTLS priority", .group = 1 },
774
 
        { .name = NULL }
775
 
      };
776
 
 
777
 
      
778
 
      error_t parse_opt (int key, char *arg,
779
 
                         struct argp_state *state) {
780
 
        /* Get the INPUT argument from `argp_parse', which we know is
781
 
           a pointer to our plugin list pointer. */
782
 
        switch (key) {
783
 
        case 128:
784
 
          debug = true;
 
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;
785
758
          break;
786
759
        case 'c':
787
 
          connect_to = arg;
788
 
          break;
789
 
        case 'i':
790
 
          interface = arg;
 
760
          connect_to = optarg;
791
761
          break;
792
762
        case 'd':
793
 
          keydir = arg;
 
763
          keydir = optarg;
 
764
          break;
 
765
        case 'p':
 
766
          pubkeyfile = optarg;
794
767
          break;
795
768
        case 's':
796
 
          seckeyfile = arg;
797
 
          break;
798
 
        case 'p':
799
 
          pubkeyfile = arg;
800
 
          break;
801
 
        case 129:
 
769
          seckeyfile = optarg;
 
770
          break;
 
771
        case 'D':
802
772
          errno = 0;
803
 
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
 
773
          mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
804
774
          if (errno){
805
775
            perror("strtol");
806
776
            exit(EXIT_FAILURE);
807
777
          }
808
778
          break;
809
 
        case 130:
810
 
          mc.priority = arg;
811
 
          break;
812
 
        case ARGP_KEY_ARG:
813
 
          argp_usage (state);
814
 
          break;
815
 
          case ARGP_KEY_END:
816
 
            break;
 
779
        case 'P':
 
780
          mc.priority = optarg;
 
781
          break;
 
782
        case '?':
817
783
        default:
818
 
          return ARGP_ERR_UNKNOWN;
 
784
          /* getopt_long() has already printed a message about the
 
785
             unrcognized option, so just exit. */
 
786
          exit(EXIT_FAILURE);
819
787
        }
820
 
        return 0;
821
788
      }
822
 
 
823
 
      struct argp argp = { .options = options, .parser = parse_opt,
824
 
                           .args_doc = "",
825
 
                           .doc = "Mandos client -- Get and decrypt"
826
 
                           " passwords from mandos server" };
827
 
      argp_parse (&argp, argc, argv, 0, 0, NULL);
 
789
      /* Set the global debug flag from the temporary int */
 
790
      debug = debug_int ? true : false;
828
791
    }
829
 
      
 
792
    
830
793
    pubkeyfile = combinepath(keydir, pubkeyfile);
831
794
    if (pubkeyfile == NULL){
832
795
      perror("combinepath");
839
802
      perror("combinepath");
840
803
      goto end;
841
804
    }
842
 
 
843
 
    ret = init_gnutls_global(&mc, pubkeyfile, seckeyfile);
844
 
    if (ret == -1){
845
 
      fprintf(stderr, "init_gnutls_global\n");
846
 
      goto end;
847
 
    }
848
 
 
849
 
    uid = getuid();
850
 
    gid = getgid();
851
 
 
852
 
    ret = setuid(uid);
853
 
    if (ret == -1){
854
 
      perror("setuid");
855
 
    }
856
 
    
857
 
    setgid(gid);
858
 
    if (ret == -1){
859
 
      perror("setgid");
860
 
    }
861
805
    
862
806
    if_index = (AvahiIfIndex) if_nametoindex(interface);
863
807
    if(if_index == 0){
871
815
      char *address = strrchr(connect_to, ':');
872
816
      if(address == NULL){
873
817
        fprintf(stderr, "No colon in address\n");
874
 
        exitcode = EXIT_FAILURE;
875
 
        goto end;
 
818
        exit(EXIT_FAILURE);
876
819
      }
877
820
      errno = 0;
878
821
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
879
822
      if(errno){
880
823
        perror("Bad port number");
881
 
        exitcode = EXIT_FAILURE;
882
 
        goto end;
 
824
        exit(EXIT_FAILURE);
883
825
      }
884
826
      *address = '\0';
885
827
      address = connect_to;
886
828
      ret = start_mandos_communication(address, port, if_index, &mc);
887
829
      if(ret < 0){
888
 
        exitcode = EXIT_FAILURE;
 
830
        exit(EXIT_FAILURE);
889
831
      } else {
890
 
        exitcode = EXIT_SUCCESS;
 
832
        exit(EXIT_SUCCESS);
891
833
      }
892
 
      goto end;
893
834
    }
894
835
    
895
836
    /* If the interface is down, bring it up */