/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

  • Committer: Teddy Hogeborn
  • Date: 2008-07-21 23:18:02 UTC
  • mfrom: (15.1.5 mandos) (15.1.5 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20080721231802-0emzdsxkfy457p9u
merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
 * includes the following functions: "resolve_callback",
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
 
 * Everything else is
12
 
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
11
 * Everything else is Copyright © 2007-2008 Teddy Hogeborn and Björn
 
12
 * Påhlsson.
13
13
 * 
14
14
 * This program is free software: you can redistribute it and/or
15
15
 * modify it under the terms of the GNU General Public License as
25
25
 * along with this program.  If not, see
26
26
 * <http://www.gnu.org/licenses/>.
27
27
 * 
28
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
28
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
29
 * <https://www.fukt.bsnet.se/~teddy/>.
29
30
 */
30
31
 
31
 
/* Needed by GPGME, specifically gpgme_data_seek() */
 
32
#define _FORTIFY_SOURCE 2
 
33
 
32
34
#define _LARGEFILE_SOURCE
33
35
#define _FILE_OFFSET_BITS 64
34
36
 
37
39
#include <stdlib.h>
38
40
#include <time.h>
39
41
#include <net/if.h>             /* if_nametoindex */
40
 
#include <sys/ioctl.h>          // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
41
 
#include <net/if.h>             // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
42
42
 
43
43
#include <avahi-core/core.h>
44
44
#include <avahi-core/lookup.h>
68
68
// getopt long
69
69
#include <getopt.h>
70
70
 
 
71
#ifndef CERT_ROOT
 
72
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
 
73
#endif
 
74
#define CERTFILE CERT_ROOT "openpgp-client.txt"
 
75
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
71
76
#define BUFFER_SIZE 256
72
77
#define DH_BITS 1024
73
78
 
74
 
static const char *certdir = "/conf/conf.d/mandos";
75
 
static const char *certfile = "openpgp-client.txt";
76
 
static const char *certkey = "openpgp-client-key.txt";
77
 
 
78
79
bool debug = false;
79
80
 
80
81
typedef struct {
84
85
} encrypted_session;
85
86
 
86
87
 
87
 
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
 
                                   char **new_packet,
89
 
                                   const char *homedir){
 
88
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
89
                            char **new_packet, const char *homedir){
90
90
  gpgme_data_t dh_crypto, dh_plain;
91
91
  gpgme_ctx_t ctx;
92
92
  gpgme_error_t rc;
101
101
  
102
102
  /* Init GPGME */
103
103
  gpgme_check_version(NULL);
104
 
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
105
 
  if (rc != GPG_ERR_NO_ERROR){
106
 
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
107
 
            gpgme_strsource(rc), gpgme_strerror(rc));
108
 
    return -1;
109
 
  }
 
104
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
110
105
  
111
106
  /* Set GPGME home directory */
112
107
  rc = gpgme_get_engine_info (&engine_info);
198
193
  gpgme_data_release(dh_crypto);
199
194
  
200
195
  /* Seek back to the beginning of the GPGME plaintext data buffer */
201
 
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
202
 
    perror("pgpme_data_seek");
203
 
  }
204
 
  
 
196
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
 
197
 
205
198
  *new_packet = 0;
206
199
  while(true){
207
200
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
248
241
  return ret;
249
242
}
250
243
 
251
 
static void debuggnutls(__attribute__((unused)) int level,
252
 
                        const char* string){
 
244
void debuggnutls(__attribute__((unused)) int level,
 
245
                 const char* string){
253
246
  fprintf(stderr, "%s", string);
254
247
}
255
248
 
256
 
static int initgnutls(encrypted_session *es){
 
249
int initgnutls(encrypted_session *es){
257
250
  const char *err;
258
251
  int ret;
259
252
  
260
253
  if(debug){
261
254
    fprintf(stderr, "Initializing GnuTLS\n");
262
255
  }
263
 
 
 
256
  
264
257
  if ((ret = gnutls_global_init ())
265
258
      != GNUTLS_E_SUCCESS) {
266
259
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
282
275
  
283
276
  if(debug){
284
277
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
285
 
            " and keyfile %s as GnuTLS credentials\n", certfile,
286
 
            certkey);
 
278
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
 
279
            KEYFILE);
287
280
  }
288
281
  
289
282
  ret = gnutls_certificate_set_openpgp_key_file
290
 
    (es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
 
283
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
291
284
  if (ret != GNUTLS_E_SUCCESS) {
292
285
    fprintf
293
286
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
294
287
       " '%s')\n",
295
 
       ret, certfile, certkey);
 
288
       ret, CERTFILE, KEYFILE);
296
289
    fprintf(stdout, "The Error is: %s\n",
297
290
            safer_gnutls_strerror(ret));
298
291
    return -1;
347
340
  return 0;
348
341
}
349
342
 
350
 
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
351
 
                      __attribute__((unused)) const char *txt){}
 
343
void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
344
               __attribute__((unused)) const char *txt){}
352
345
 
353
 
static int start_mandos_communication(const char *ip, uint16_t port,
354
 
                                      AvahiIfIndex if_index){
 
346
int start_mandos_communication(const char *ip, uint16_t port,
 
347
                               unsigned int if_index){
355
348
  int ret, tcp_sd;
356
349
  struct sockaddr_in6 to;
357
350
  encrypted_session es;
365
358
  char interface[IF_NAMESIZE];
366
359
  
367
360
  if(debug){
368
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
369
 
            ip, port);
 
361
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
370
362
  }
371
363
  
372
364
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
374
366
    perror("socket");
375
367
    return -1;
376
368
  }
377
 
 
 
369
  
 
370
  if(if_indextoname(if_index, interface) == NULL){
 
371
    if(debug){
 
372
      perror("if_indextoname");
 
373
    }
 
374
    return -1;
 
375
  }
 
376
  
378
377
  if(debug){
379
 
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
380
 
      if(debug){
381
 
        perror("if_indextoname");
382
 
      }
383
 
      return -1;
384
 
    }
385
 
    
386
378
    fprintf(stderr, "Binding to interface %s\n", interface);
387
379
  }
388
380
  
402
394
  to.sin6_scope_id = (uint32_t)if_index;
403
395
  
404
396
  if(debug){
405
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
406
 
/*     char addrstr[INET6_ADDRSTRLEN]; */
407
 
/*     if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
408
 
/*               sizeof(addrstr)) == NULL){ */
409
 
/*       perror("inet_ntop"); */
410
 
/*     } else { */
411
 
/*       fprintf(stderr, "Really connecting to: %s, port %d\n", */
412
 
/*            addrstr, ntohs(to.sin6_port)); */
413
 
/*     } */
 
397
    fprintf(stderr, "Connection to: %s\n", ip);
414
398
  }
415
399
  
416
400
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
435
419
  ret = gnutls_handshake (es.session);
436
420
  
437
421
  if (ret != GNUTLS_E_SUCCESS){
438
 
    if(debug){
439
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
440
 
      gnutls_perror (ret);
441
 
    }
 
422
    fprintf(stderr, "\n*** Handshake failed ***\n");
 
423
    gnutls_perror (ret);
442
424
    retval = -1;
443
425
    goto exit;
444
426
  }
495
477
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
496
478
                                               buffer_length,
497
479
                                               &decrypted_buffer,
498
 
                                               certdir);
 
480
                                               CERT_ROOT);
499
481
    if (decrypted_buffer_size >= 0){
500
 
      while(written < (size_t) decrypted_buffer_size){
 
482
      while(written < decrypted_buffer_size){
501
483
        ret = (int)fwrite (decrypted_buffer + written, 1,
502
484
                           (size_t)decrypted_buffer_size - written,
503
485
                           stdout);
569
551
      char ip[AVAHI_ADDRESS_STR_MAX];
570
552
      avahi_address_snprint(ip, sizeof(ip), address);
571
553
      if(debug){
572
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
573
 
                " port %d\n", name, host_name, ip, port);
 
554
        fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
 
555
                host_name, ip, port);
574
556
      }
575
 
      int ret = start_mandos_communication(ip, port, interface);
 
557
      int ret = start_mandos_communication(ip, port,
 
558
                                           (unsigned int) interface);
576
559
      if (ret == 0){
577
560
        exit(EXIT_SUCCESS);
 
561
      } else {
 
562
        exit(EXIT_FAILURE);
578
563
      }
579
564
    }
580
565
  }
630
615
    }
631
616
}
632
617
 
633
 
/* Combines file name and path and returns the malloced new
634
 
   string. some sane checks could/should be added */
635
 
static const char *combinepath(const char *first, const char *second){
636
 
  size_t f_len = strlen(first);
637
 
  size_t s_len = strlen(second);
638
 
  char *tmp = malloc(f_len + s_len + 2);
639
 
  if (tmp == NULL){
640
 
    return NULL;
641
 
  }
642
 
  if(f_len > 0){
643
 
    memcpy(tmp, first, f_len);
644
 
  }
645
 
  tmp[f_len] = '/';
646
 
  if(s_len > 0){
647
 
    memcpy(tmp + f_len + 1, second, s_len);
648
 
  }
649
 
  tmp[f_len + 1 + s_len] = '\0';
650
 
  return tmp;
651
 
}
652
 
 
653
 
 
654
618
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
655
619
    AvahiServerConfig config;
656
620
    AvahiSServiceBrowser *sb = NULL;
658
622
    int ret;
659
623
    int returncode = EXIT_SUCCESS;
660
624
    const char *interface = "eth0";
661
 
    struct ifreq network;
662
 
    int sd;
663
 
    char *connect_to = NULL;
664
 
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
665
625
    
666
626
    while (true){
667
627
      static struct option long_options[] = {
668
628
        {"debug", no_argument, (int *)&debug, 1},
669
 
        {"connect", required_argument, 0, 'C'},
670
629
        {"interface", required_argument, 0, 'i'},
671
 
        {"certdir", required_argument, 0, 'd'},
672
 
        {"certkey", required_argument, 0, 'c'},
673
 
        {"certfile", required_argument, 0, 'k'},
674
630
        {0, 0, 0, 0} };
675
631
      
676
632
      int option_index = 0;
687
643
      case 'i':
688
644
        interface = optarg;
689
645
        break;
690
 
      case 'C':
691
 
        connect_to = optarg;
692
 
        break;
693
 
      case 'd':
694
 
        certdir = optarg;
695
 
        break;
696
 
      case 'c':
697
 
        certfile = optarg;
698
 
        break;
699
 
      case 'k':
700
 
        certkey = optarg;
701
 
        break;
702
646
      default:
703
647
        exit(EXIT_FAILURE);
704
648
      }
705
649
    }
706
650
    
707
 
    certfile = combinepath(certdir, certfile);
708
 
    if (certfile == NULL){
709
 
      perror("combinepath");
710
 
      returncode = EXIT_FAILURE;
711
 
      goto exit;
712
 
    }
713
 
 
714
 
    certkey = combinepath(certdir, certkey);
715
 
    if (certkey == NULL){
716
 
      perror("combinepath");
717
 
      returncode = EXIT_FAILURE;
718
 
      goto exit;
719
 
    }
720
 
    
721
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
722
 
    if(if_index == 0){
723
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
724
 
      exit(EXIT_FAILURE);
725
 
    }
726
 
    
727
 
    if(connect_to != NULL){
728
 
      /* Connect directly, do not use Zeroconf */
729
 
      /* (Mainly meant for debugging) */
730
 
      char *address = strrchr(connect_to, ':');
731
 
      if(address == NULL){
732
 
        fprintf(stderr, "No colon in address\n");
733
 
        exit(EXIT_FAILURE);
734
 
      }
735
 
      errno = 0;
736
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
737
 
      if(errno){
738
 
        perror("Bad port number");
739
 
        exit(EXIT_FAILURE);
740
 
      }
741
 
      *address = '\0';
742
 
      address = connect_to;
743
 
      ret = start_mandos_communication(address, port, if_index);
744
 
      if(ret < 0){
745
 
        exit(EXIT_FAILURE);
746
 
      } else {
747
 
        exit(EXIT_SUCCESS);
748
 
      }
749
 
    }
750
 
    
751
 
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
752
 
    if(sd < 0) {
753
 
      perror("socket");
754
 
      returncode = EXIT_FAILURE;
755
 
      goto exit;
756
 
    }
757
 
    strcpy(network.ifr_name, interface);    
758
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
759
 
    if(ret == -1){
760
 
      
761
 
      perror("ioctl SIOCGIFFLAGS");
762
 
      returncode = EXIT_FAILURE;
763
 
      goto exit;
764
 
    }
765
 
    if((network.ifr_flags & IFF_UP) == 0){
766
 
      network.ifr_flags |= IFF_UP;
767
 
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
768
 
      if(ret == -1){
769
 
        perror("ioctl SIOCSIFFLAGS");
770
 
        returncode = EXIT_FAILURE;
771
 
        goto exit;
772
 
      }
773
 
    }
774
 
    close(sd);
775
 
    
776
651
    if (not debug){
777
652
      avahi_set_log_function(empty_log);
778
653
    }
783
658
    /* Allocate main loop object */
784
659
    if (!(simple_poll = avahi_simple_poll_new())) {
785
660
        fprintf(stderr, "Failed to create simple poll object.\n");
786
 
        returncode = EXIT_FAILURE;      
 
661
        
787
662
        goto exit;
788
663
    }
789
664
 
810
685
    }
811
686
    
812
687
    /* Create the service browser */
813
 
    sb = avahi_s_service_browser_new(server, if_index,
 
688
    sb = avahi_s_service_browser_new(server,
 
689
                                     (AvahiIfIndex)
 
690
                                     if_nametoindex(interface),
814
691
                                     AVAHI_PROTO_INET6,
815
692
                                     "_mandos._tcp", NULL, 0,
816
693
                                     browse_callback, server);
844
721
 
845
722
    if (simple_poll)
846
723
        avahi_simple_poll_free(simple_poll);
847
 
    free(certfile);
848
 
    free(certkey);
849
 
    
 
724
 
850
725
    return returncode;
851
726
}