/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

  • Committer: Teddy Hogeborn
  • Date: 2008-07-22 06:23:29 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080722062329-jaex5y5mslf6sqjx
* mandos-clients.conf ([DEFAULT]): New section.

* plugins.d/mandosclient.c (start_mandos_communication): Only print if
                                                         debugging.
                                                         Print server
                                                         name.
                                                         Bug fix: Loop
                                                         until suc-
                                                         cess.

* server.py (serverName): Set via option, not globally.
  (Client.__init__): Removed argument "options".  Require "timeout"
                     and "interval" arguments.
  (tcp_handler.handle): Set "priority" from self.server.options.
  (main): Removed "--timeout" and "--interval" options.  New options
          "--priority" and "--servicename".  Add defaults for
          "timeout" and "interval".  Set "serviceName" from options.
          Do not pass "options" to "Client()".

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
 
63
65
#include <errno.h>              /* perror() */
64
66
#include <gpgme.h>
65
67
 
66
 
// getopt_long
 
68
// getopt long
67
69
#include <getopt.h>
68
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"
69
76
#define BUFFER_SIZE 256
70
 
 
71
 
static int dh_bits = 1024;
72
 
 
73
 
static const char *keydir = "/conf/conf.d/mandos";
74
 
static const char *pubkeyfile = "pubkey.txt";
75
 
static const char *seckeyfile = "seckey.txt";
 
77
#define DH_BITS 1024
76
78
 
77
79
bool debug = false;
78
80
 
79
 
/* Used for  */
80
81
typedef struct {
81
82
  gnutls_session_t session;
82
83
  gnutls_certificate_credentials_t cred;
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", pubkeyfile,
286
 
            seckeyfile);
 
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, pubkeyfile, seckeyfile, 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, pubkeyfile, seckeyfile);
 
288
       ret, CERTFILE, KEYFILE);
296
289
    fprintf(stdout, "The Error is: %s\n",
297
290
            safer_gnutls_strerror(ret));
298
291
    return -1;
306
299
    return -1;
307
300
  }
308
301
  
309
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, dh_bits))
 
302
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
310
303
      != GNUTLS_E_SUCCESS) {
311
304
    fprintf (stderr, "Error in prime generation: %s\n",
312
305
             safer_gnutls_strerror(ret));
342
335
  gnutls_certificate_server_set_request (es->session,
343
336
                                         GNUTLS_CERT_IGNORE);
344
337
  
345
 
  gnutls_dh_set_prime_bits (es->session, dh_bits);
 
338
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
346
339
  
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);
375
367
    return -1;
376
368
  }
377
369
  
378
 
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
370
  if(if_indextoname(if_index, interface) == NULL){
379
371
    if(debug){
380
372
      perror("if_indextoname");
381
373
    }
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
 
      if(strcmp(addrstr, ip) != 0){
412
 
        fprintf(stderr, "Canonical address form: %s\n",
413
 
                addrstr, ntohs(to.sin6_port));
414
 
      }
415
 
    }
 
397
    fprintf(stderr, "Connection to: %s\n", ip);
416
398
  }
417
399
  
418
400
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
497
479
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
498
480
                                               buffer_length,
499
481
                                               &decrypted_buffer,
500
 
                                               keydir);
 
482
                                               CERT_ROOT);
501
483
    if (decrypted_buffer_size >= 0){
502
 
      while(written < (size_t) decrypted_buffer_size){
 
484
      while(written < decrypted_buffer_size){
503
485
        ret = (int)fwrite (decrypted_buffer + written, 1,
504
486
                           (size_t)decrypted_buffer_size - written,
505
487
                           stdout);
574
556
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
575
557
                " port %d\n", name, host_name, ip, port);
576
558
      }
577
 
      int ret = start_mandos_communication(ip, port, interface);
 
559
      int ret = start_mandos_communication(ip, port,
 
560
                                           (unsigned int) interface);
578
561
      if (ret == 0){
579
562
        exit(EXIT_SUCCESS);
580
563
      }
632
615
    }
633
616
}
634
617
 
635
 
/* Combines file name and path and returns the malloced new
636
 
   string. some sane checks could/should be added */
637
 
static const char *combinepath(const char *first, const char *second){
638
 
  size_t f_len = strlen(first);
639
 
  size_t s_len = strlen(second);
640
 
  char *tmp = malloc(f_len + s_len + 2);
641
 
  if (tmp == NULL){
642
 
    return NULL;
643
 
  }
644
 
  if(f_len > 0){
645
 
    memcpy(tmp, first, f_len);
646
 
  }
647
 
  tmp[f_len] = '/';
648
 
  if(s_len > 0){
649
 
    memcpy(tmp + f_len + 1, second, s_len);
650
 
  }
651
 
  tmp[f_len + 1 + s_len] = '\0';
652
 
  return tmp;
653
 
}
654
 
 
655
 
 
656
618
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
657
619
    AvahiServerConfig config;
658
620
    AvahiSServiceBrowser *sb = NULL;
659
621
    int error;
660
622
    int ret;
661
 
    int debug_int = 0;
662
623
    int returncode = EXIT_SUCCESS;
663
 
    const char *interface = NULL;
664
 
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
665
 
    char *connect_to = NULL;
 
624
    const char *interface = "eth0";
666
625
    
667
 
    debug_int = debug ? 1 : 0;
668
626
    while (true){
669
627
      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'},
 
628
        {"debug", no_argument, (int *)&debug, 1},
 
629
        {"interface", required_argument, 0, 'i'},
677
630
        {0, 0, 0, 0} };
678
631
      
679
632
      int option_index = 0;
690
643
      case 'i':
691
644
        interface = optarg;
692
645
        break;
693
 
      case 'C':
694
 
        connect_to = optarg;
695
 
        break;
696
 
      case 'd':
697
 
        keydir = optarg;
698
 
        break;
699
 
      case 'c':
700
 
        pubkeyfile = optarg;
701
 
        break;
702
 
      case 'k':
703
 
        seckeyfile = optarg;
704
 
        break;
705
 
      case 'D':
706
 
        dh_bits = atoi(optarg);
707
 
        break;
708
 
      case '?':
709
 
        break
710
646
      default:
711
647
        exit(EXIT_FAILURE);
712
648
      }
713
649
    }
714
 
    debug = debug_int ? true : false;
715
 
    
716
 
    pubkeyfile = combinepath(keydir, pubkeyfile);
717
 
    if (pubkeyfile == NULL){
718
 
      perror("combinepath");
719
 
      goto exit;
720
 
    }
721
 
    
722
 
    if(interface != NULL){
723
 
      if_index = (AvahiIfIndex) if_nametoindex(interface);
724
 
      if(if_index == 0){
725
 
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
726
 
        exit(EXIT_FAILURE);
727
 
      }
728
 
    }
729
 
    
730
 
    if(connect_to != NULL){
731
 
      /* Connect directly, do not use Zeroconf */
732
 
      /* (Mainly meant for debugging) */
733
 
      char *address = strrchr(connect_to, ':');
734
 
      if(address == NULL){
735
 
        fprintf(stderr, "No colon in address\n");
736
 
        exit(EXIT_FAILURE);
737
 
      }
738
 
      errno = 0;
739
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
740
 
      if(errno){
741
 
        perror("Bad port number");
742
 
        exit(EXIT_FAILURE);
743
 
      }
744
 
      *address = '\0';
745
 
      address = connect_to;
746
 
      ret = start_mandos_communication(address, port, if_index);
747
 
      if(ret < 0){
748
 
        exit(EXIT_FAILURE);
749
 
      } else {
750
 
        exit(EXIT_SUCCESS);
751
 
      }
752
 
    }
753
 
    
754
 
    seckeyfile = combinepath(keydir, seckeyfile);
755
 
    if (seckeyfile == NULL){
756
 
      perror("combinepath");
757
 
      goto exit;
758
 
    }
759
650
    
760
651
    if (not debug){
761
652
      avahi_set_log_function(empty_log);
794
685
    }
795
686
    
796
687
    /* Create the service browser */
797
 
    sb = avahi_s_service_browser_new(server, if_index,
 
688
    sb = avahi_s_service_browser_new(server,
 
689
                                     (AvahiIfIndex)
 
690
                                     if_nametoindex(interface),
798
691
                                     AVAHI_PROTO_INET6,
799
692
                                     "_mandos._tcp", NULL, 0,
800
693
                                     browse_callback, server);
828
721
 
829
722
    if (simple_poll)
830
723
        avahi_simple_poll_free(simple_poll);
831
 
    free(pubkeyfile);
832
 
    free(seckeyfile);
833
 
    
 
724
 
834
725
    return returncode;
835
726
}