/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

plugbasedclient
        Parse a single argument as a plus-separated list of options

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 Copyright © 2007-2008 Teddy Hogeborn and Björn
12
 
 * Påhlsson.
 
11
 * Everything else is
 
12
 * Copyright © 2007-2008 Teddy Hogeborn & Björn 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 <https://www.fukt.bsnet.se/~belorn/> and
29
 
 * <https://www.fukt.bsnet.se/~teddy/>.
 
28
 * Contact the authors at <mandos@fukt.bsnet.se>.
30
29
 */
31
30
 
32
 
#define _FORTIFY_SOURCE 2
33
 
 
 
31
/* Needed by GPGME, specifically gpgme_data_seek() */
34
32
#define _LARGEFILE_SOURCE
35
33
#define _FILE_OFFSET_BITS 64
36
34
 
39
37
#include <stdlib.h>
40
38
#include <time.h>
41
39
#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"
76
71
#define BUFFER_SIZE 256
77
72
#define DH_BITS 1024
78
73
 
 
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
 
79
78
bool debug = false;
80
79
 
81
80
typedef struct {
85
84
} encrypted_session;
86
85
 
87
86
 
88
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
89
 
                            char **new_packet, const char *homedir){
 
87
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
 
88
                                   char **new_packet,
 
89
                                   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
 
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
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
  }
105
110
  
106
111
  /* Set GPGME home directory */
107
112
  rc = gpgme_get_engine_info (&engine_info);
193
198
  gpgme_data_release(dh_crypto);
194
199
  
195
200
  /* Seek back to the beginning of the GPGME plaintext data buffer */
196
 
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
197
 
 
 
201
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
 
202
    perror("pgpme_data_seek");
 
203
  }
 
204
  
198
205
  *new_packet = 0;
199
206
  while(true){
200
207
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
241
248
  return ret;
242
249
}
243
250
 
244
 
void debuggnutls(__attribute__((unused)) int level,
245
 
                 const char* string){
 
251
static void debuggnutls(__attribute__((unused)) int level,
 
252
                        const char* string){
246
253
  fprintf(stderr, "%s", string);
247
254
}
248
255
 
249
 
int initgnutls(encrypted_session *es){
 
256
static int initgnutls(encrypted_session *es){
250
257
  const char *err;
251
258
  int ret;
252
259
  
253
260
  if(debug){
254
261
    fprintf(stderr, "Initializing GnuTLS\n");
255
262
  }
256
 
  
 
263
 
257
264
  if ((ret = gnutls_global_init ())
258
265
      != GNUTLS_E_SUCCESS) {
259
266
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
275
282
  
276
283
  if(debug){
277
284
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
278
 
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
279
 
            KEYFILE);
 
285
            " and keyfile %s as GnuTLS credentials\n", certfile,
 
286
            certkey);
280
287
  }
281
288
  
282
289
  ret = gnutls_certificate_set_openpgp_key_file
283
 
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
 
290
    (es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
284
291
  if (ret != GNUTLS_E_SUCCESS) {
285
292
    fprintf
286
293
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
287
294
       " '%s')\n",
288
 
       ret, CERTFILE, KEYFILE);
 
295
       ret, certfile, certkey);
289
296
    fprintf(stdout, "The Error is: %s\n",
290
297
            safer_gnutls_strerror(ret));
291
298
    return -1;
340
347
  return 0;
341
348
}
342
349
 
343
 
void empty_log(__attribute__((unused)) AvahiLogLevel level,
344
 
               __attribute__((unused)) const char *txt){}
 
350
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
351
                      __attribute__((unused)) const char *txt){}
345
352
 
346
 
int start_mandos_communication(const char *ip, uint16_t port,
347
 
                               unsigned int if_index){
 
353
static int start_mandos_communication(const char *ip, uint16_t port,
 
354
                                      AvahiIfIndex if_index){
348
355
  int ret, tcp_sd;
349
356
  struct sockaddr_in6 to;
350
357
  encrypted_session es;
358
365
  char interface[IF_NAMESIZE];
359
366
  
360
367
  if(debug){
361
 
    fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
 
368
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
 
369
            ip, port);
362
370
  }
363
371
  
364
372
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
366
374
    perror("socket");
367
375
    return -1;
368
376
  }
369
 
  
370
 
  if(if_indextoname(if_index, interface) == NULL){
371
 
    if(debug){
372
 
      perror("if_indextoname");
 
377
 
 
378
  if(debug){
 
379
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
380
      if(debug){
 
381
        perror("if_indextoname");
 
382
      }
 
383
      return -1;
373
384
    }
374
 
    return -1;
375
 
  }
376
 
  
377
 
  if(debug){
 
385
    
378
386
    fprintf(stderr, "Binding to interface %s\n", interface);
379
387
  }
380
388
  
394
402
  to.sin6_scope_id = (uint32_t)if_index;
395
403
  
396
404
  if(debug){
397
 
    fprintf(stderr, "Connection to: %s\n", ip);
 
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
/*     } */
398
414
  }
399
415
  
400
416
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
419
435
  ret = gnutls_handshake (es.session);
420
436
  
421
437
  if (ret != GNUTLS_E_SUCCESS){
422
 
    fprintf(stderr, "\n*** Handshake failed ***\n");
423
 
    gnutls_perror (ret);
 
438
    if(debug){
 
439
      fprintf(stderr, "\n*** Handshake failed ***\n");
 
440
      gnutls_perror (ret);
 
441
    }
424
442
    retval = -1;
425
443
    goto exit;
426
444
  }
477
495
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
478
496
                                               buffer_length,
479
497
                                               &decrypted_buffer,
480
 
                                               CERT_ROOT);
 
498
                                               certdir);
481
499
    if (decrypted_buffer_size >= 0){
482
 
      while(written < decrypted_buffer_size){
 
500
      while(written < (size_t) decrypted_buffer_size){
483
501
        ret = (int)fwrite (decrypted_buffer + written, 1,
484
502
                           (size_t)decrypted_buffer_size - written,
485
503
                           stdout);
551
569
      char ip[AVAHI_ADDRESS_STR_MAX];
552
570
      avahi_address_snprint(ip, sizeof(ip), address);
553
571
      if(debug){
554
 
        fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
555
 
                host_name, ip, port);
 
572
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
 
573
                " port %d\n", name, host_name, ip, port);
556
574
      }
557
 
      int ret = start_mandos_communication(ip, port,
558
 
                                           (unsigned int) interface);
 
575
      int ret = start_mandos_communication(ip, port, interface);
559
576
      if (ret == 0){
560
577
        exit(EXIT_SUCCESS);
561
 
      } else {
562
 
        exit(EXIT_FAILURE);
563
578
      }
564
579
    }
565
580
  }
615
630
    }
616
631
}
617
632
 
 
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
 
618
654
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
619
655
    AvahiServerConfig config;
620
656
    AvahiSServiceBrowser *sb = NULL;
622
658
    int ret;
623
659
    int returncode = EXIT_SUCCESS;
624
660
    const char *interface = "eth0";
 
661
    struct ifreq network;
 
662
    int sd;
 
663
    char *connect_to = NULL;
 
664
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
625
665
    
626
666
    while (true){
627
667
      static struct option long_options[] = {
628
668
        {"debug", no_argument, (int *)&debug, 1},
 
669
        {"connect", required_argument, 0, 'C'},
629
670
        {"interface", required_argument, 0, 'i'},
 
671
        {"certdir", required_argument, 0, 'd'},
 
672
        {"certkey", required_argument, 0, 'c'},
 
673
        {"certfile", required_argument, 0, 'k'},
630
674
        {0, 0, 0, 0} };
631
675
      
632
676
      int option_index = 0;
643
687
      case 'i':
644
688
        interface = optarg;
645
689
        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;
646
702
      default:
647
703
        exit(EXIT_FAILURE);
648
704
      }
649
705
    }
650
706
    
 
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
    
651
776
    if (not debug){
652
777
      avahi_set_log_function(empty_log);
653
778
    }
658
783
    /* Allocate main loop object */
659
784
    if (!(simple_poll = avahi_simple_poll_new())) {
660
785
        fprintf(stderr, "Failed to create simple poll object.\n");
661
 
        
 
786
        returncode = EXIT_FAILURE;      
662
787
        goto exit;
663
788
    }
664
789
 
685
810
    }
686
811
    
687
812
    /* Create the service browser */
688
 
    sb = avahi_s_service_browser_new(server,
689
 
                                     (AvahiIfIndex)
690
 
                                     if_nametoindex(interface),
 
813
    sb = avahi_s_service_browser_new(server, if_index,
691
814
                                     AVAHI_PROTO_INET6,
692
815
                                     "_mandos._tcp", NULL, 0,
693
816
                                     browse_callback, server);
721
844
 
722
845
    if (simple_poll)
723
846
        avahi_simple_poll_free(simple_poll);
724
 
 
 
847
    free(certfile);
 
848
    free(certkey);
 
849
    
725
850
    return returncode;
726
851
}