8
8
* includes the following functions: "resolve_callback",
9
9
* "browse_callback", and parts of "main".
11
* Everything else is Copyright © 2007-2008 Teddy Hogeborn and Björn
12
* Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
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/>.
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>.
32
#define _FORTIFY_SOURCE 2
31
/* Needed by GPGME, specifically gpgme_data_seek() */
34
32
#define _LARGEFILE_SOURCE
35
33
#define _FILE_OFFSET_BITS 64
39
37
#include <stdlib.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
43
43
#include <avahi-core/core.h>
44
44
#include <avahi-core/lookup.h>
69
69
#include <getopt.h>
72
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
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
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";
79
78
bool debug = false;
85
84
} encrypted_session;
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,
90
90
gpgme_data_t dh_crypto, dh_plain;
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));
106
111
/* Set GPGME home directory */
107
112
rc = gpgme_get_engine_info (&engine_info);
193
198
gpgme_data_release(dh_crypto);
195
200
/* Seek back to the beginning of the GPGME plaintext data buffer */
196
gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
201
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
202
perror("pgpme_data_seek");
200
207
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
244
void debuggnutls(__attribute__((unused)) int level,
251
static void debuggnutls(__attribute__((unused)) int level,
246
253
fprintf(stderr, "%s", string);
249
int initgnutls(encrypted_session *es){
256
static int initgnutls(encrypted_session *es){
254
261
fprintf(stderr, "Initializing GnuTLS\n");
257
264
if ((ret = gnutls_global_init ())
258
265
!= GNUTLS_E_SUCCESS) {
259
266
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
277
284
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
278
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
285
" and keyfile %s as GnuTLS credentials\n", certfile,
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) {
286
293
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
288
ret, CERTFILE, KEYFILE);
295
ret, certfile, certkey);
289
296
fprintf(stdout, "The Error is: %s\n",
290
297
safer_gnutls_strerror(ret));
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){}
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){
349
356
struct sockaddr_in6 to;
350
357
encrypted_session es;
358
365
char interface[IF_NAMESIZE];
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",
364
372
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
366
374
perror("socket");
370
if(if_indextoname(if_index, interface) == NULL){
372
perror("if_indextoname");
379
if(if_indextoname((unsigned int)if_index, interface) == NULL){
381
perror("if_indextoname");
378
386
fprintf(stderr, "Binding to interface %s\n", interface);
394
402
to.sin6_scope_id = (uint32_t)if_index;
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"); */
411
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
412
/* addrstr, ntohs(to.sin6_port)); */
400
416
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
419
435
ret = gnutls_handshake (es.session);
421
437
if (ret != GNUTLS_E_SUCCESS){
422
fprintf(stderr, "\n*** Handshake failed ***\n");
439
fprintf(stderr, "\n*** Handshake failed ***\n");
477
495
decrypted_buffer_size = pgp_packet_decrypt(buffer,
479
497
&decrypted_buffer,
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,
551
569
char ip[AVAHI_ADDRESS_STR_MAX];
552
570
avahi_address_snprint(ip, sizeof(ip), address);
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);
557
int ret = start_mandos_communication(ip, port,
558
(unsigned int) interface);
575
int ret = start_mandos_communication(ip, port, interface);
560
577
exit(EXIT_SUCCESS);
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);
643
memcpy(tmp, first, f_len);
647
memcpy(tmp + f_len + 1, second, s_len);
649
tmp[f_len + 1 + s_len] = '\0';
618
654
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
619
655
AvahiServerConfig config;
620
656
AvahiSServiceBrowser *sb = NULL;
623
659
int returncode = EXIT_SUCCESS;
624
660
const char *interface = "eth0";
661
struct ifreq network;
663
char *connect_to = NULL;
664
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
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'},
632
676
int option_index = 0;
644
688
interface = optarg;
647
703
exit(EXIT_FAILURE);
707
certfile = combinepath(certdir, certfile);
708
if (certfile == NULL){
709
perror("combinepath");
710
returncode = EXIT_FAILURE;
714
certkey = combinepath(certdir, certkey);
715
if (certkey == NULL){
716
perror("combinepath");
717
returncode = EXIT_FAILURE;
721
if_index = (AvahiIfIndex) if_nametoindex(interface);
723
fprintf(stderr, "No such interface: \"%s\"\n", interface);
727
if(connect_to != NULL){
728
/* Connect directly, do not use Zeroconf */
729
/* (Mainly meant for debugging) */
730
char *address = strrchr(connect_to, ':');
732
fprintf(stderr, "No colon in address\n");
736
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
738
perror("Bad port number");
742
address = connect_to;
743
ret = start_mandos_communication(address, port, if_index);
751
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
754
returncode = EXIT_FAILURE;
757
strcpy(network.ifr_name, interface);
758
ret = ioctl(sd, SIOCGIFFLAGS, &network);
761
perror("ioctl SIOCGIFFLAGS");
762
returncode = EXIT_FAILURE;
765
if((network.ifr_flags & IFF_UP) == 0){
766
network.ifr_flags |= IFF_UP;
767
ret = ioctl(sd, SIOCSIFFLAGS, &network);
769
perror("ioctl SIOCSIFFLAGS");
770
returncode = EXIT_FAILURE;
652
777
avahi_set_log_function(empty_log);
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");
786
returncode = EXIT_FAILURE;
687
812
/* Create the service browser */
688
sb = avahi_s_service_browser_new(server,
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);