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
48
46
#include <avahi-common/error.h>
50
48
//mandos client part
51
#include <sys/types.h> /* socket(), setsockopt(),
53
#include <sys/socket.h> /* socket(), setsockopt(),
49
#include <sys/types.h> /* socket(), inet_pton() */
50
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
55
51
struct in6_addr, inet_pton() */
56
52
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
57
53
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
71
67
#include <getopt.h>
74
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
76
#define CERTFILE CERT_ROOT "openpgp-client.txt"
77
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
78
69
#define BUFFER_SIZE 256
79
70
#define DH_BITS 1024
72
const char *certdir = "/conf/conf.d/cryptkeyreq/";
73
const char *certfile = "openpgp-client.txt";
74
const char *certkey = "openpgp-client-key.txt";
81
76
bool debug = false;
105
100
gpgme_check_version(NULL);
106
gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
101
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
102
if (rc != GPG_ERR_NO_ERROR){
103
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
104
gpgme_strsource(rc), gpgme_strerror(rc));
108
108
/* Set GPGME home directory */
109
109
rc = gpgme_get_engine_info (&engine_info);
195
195
gpgme_data_release(dh_crypto);
197
197
/* Seek back to the beginning of the GPGME plaintext data buffer */
198
gpgme_data_seek(dh_plain, 0, SEEK_SET);
198
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
199
perror("pgpme_data_seek");
202
204
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
256
258
fprintf(stderr, "Initializing GnuTLS\n");
259
261
if ((ret = gnutls_global_init ())
260
262
!= GNUTLS_E_SUCCESS) {
261
263
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
279
281
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
280
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
282
" and keyfile %s as GnuTLS credentials\n", certfile,
284
286
ret = gnutls_certificate_set_openpgp_key_file
285
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
287
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
286
288
if (ret != GNUTLS_E_SUCCESS) {
288
290
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
290
ret, CERTFILE, KEYFILE);
292
ret, certfile, certkey);
291
293
fprintf(stdout, "The Error is: %s\n",
292
294
safer_gnutls_strerror(ret));
345
347
void empty_log(__attribute__((unused)) AvahiLogLevel level,
346
348
__attribute__((unused)) const char *txt){}
348
int start_mandos_communication(char *ip, uint16_t port,
349
unsigned int if_index){
350
int start_mandos_communication(const char *ip, uint16_t port,
351
AvahiIfIndex if_index){
351
353
struct sockaddr_in6 to;
352
354
encrypted_session es;
355
357
size_t buffer_length = 0;
356
358
size_t buffer_capacity = 0;
357
359
ssize_t decrypted_buffer_size;
359
362
char interface[IF_NAMESIZE];
362
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
365
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
365
369
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
379
383
fprintf(stderr, "Binding to interface %s\n", interface);
382
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
384
perror("setsockopt bindtodevice");
388
memset(&to,0,sizeof(to));
386
memset(&to,0,sizeof(to)); /* Spurious warning */
389
387
to.sin6_family = AF_INET6;
390
388
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
396
394
fprintf(stderr, "Bad address: %s\n", ip);
399
/* Spurious warnings for the next line, see for instance
400
<http://bugs.debian.org/488884> */
401
to.sin6_port = htons(port);
397
to.sin6_port = htons(port); /* Spurious warning */
403
399
to.sin6_scope_id = (uint32_t)if_index;
406
fprintf(stderr, "Connection to: %s\n", ip);
402
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
403
/* char addrstr[INET6_ADDRSTRLEN]; */
404
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
405
/* sizeof(addrstr)) == NULL){ */
406
/* perror("inet_ntop"); */
408
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
409
/* addrstr, ntohs(to.sin6_port)); */
409
413
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
428
432
ret = gnutls_handshake (es.session);
430
434
if (ret != GNUTLS_E_SUCCESS){
431
fprintf(stderr, "\n*** Handshake failed ***\n");
436
fprintf(stderr, "\n*** Handshake failed ***\n");
486
492
decrypted_buffer_size = pgp_packet_decrypt(buffer,
488
494
&decrypted_buffer,
490
496
if (decrypted_buffer_size >= 0){
491
while(decrypted_buffer_size > 0){
492
ret = fwrite (decrypted_buffer, 1, (size_t)decrypted_buffer_size,
497
while(written < (size_t) decrypted_buffer_size){
498
ret = (int)fwrite (decrypted_buffer + written, 1,
499
(size_t)decrypted_buffer_size - written,
494
501
if(ret == 0 and ferror(stdout)){
496
503
fprintf(stderr, "Error writing encrypted data: %s\n",
530
536
static void resolve_callback(
531
537
AvahiSServiceResolver *r,
532
AVAHI_GCC_UNUSED AvahiIfIndex interface,
538
AvahiIfIndex interface,
533
539
AVAHI_GCC_UNUSED AvahiProtocol protocol,
534
540
AvahiResolverEvent event,
535
541
const char *name,
542
548
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
543
549
AVAHI_GCC_UNUSED void* userdata) {
551
assert(r); /* Spurious warning */
547
553
/* Called whenever a service has been resolved successfully or
552
558
case AVAHI_RESOLVER_FAILURE:
554
560
" type '%s' in domain '%s': %s\n", name, type, domain,
555
561
avahi_strerror(avahi_server_errno(server)));
558
564
case AVAHI_RESOLVER_FOUND:
560
566
char ip[AVAHI_ADDRESS_STR_MAX];
561
567
avahi_address_snprint(ip, sizeof(ip), address);
563
fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
564
host_name, ip, port);
569
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
570
" port %d\n", name, host_name, ip, port);
566
int ret = start_mandos_communication(ip, port,
572
int ret = start_mandos_communication(ip, port, interface);
570
574
exit(EXIT_SUCCESS);
588
590
void* userdata) {
590
592
AvahiServer *s = userdata;
593
assert(b); /* Spurious warning */
593
595
/* Called whenever a new services becomes available on the LAN or
594
596
is removed from the LAN */
598
600
case AVAHI_BROWSER_FAILURE:
630
/* combinds file name and path and returns the malloced new string. som sane checks could/should be added */
631
const char *combinepath(const char *first, const char *second){
633
tmp = malloc(strlen(first) + strlen(second) + 2);
639
if (first[0] != '\0' and first[strlen(first) - 1] != '/'){
628
647
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
629
648
AvahiServerConfig config;
630
649
AvahiSServiceBrowser *sb = NULL;
633
652
int returncode = EXIT_SUCCESS;
634
const char *interface = "eth0";
653
const char *interface = NULL;
654
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
655
char *connect_to = NULL;
637
658
static struct option long_options[] = {
638
659
{"debug", no_argument, (int *)&debug, 1},
660
{"connect", required_argument, 0, 'C'},
639
661
{"interface", required_argument, 0, 'i'},
662
{"certdir", required_argument, 0, 'd'},
663
{"certkey", required_argument, 0, 'c'},
664
{"certfile", required_argument, 0, 'k'},
642
667
int option_index = 0;
643
668
ret = getopt_long (argc, argv, "i:", long_options,
654
679
interface = optarg;
657
694
exit(EXIT_FAILURE);
698
certfile = combinepath(certdir, certfile);
699
if (certfile == NULL){
703
if(interface != NULL){
704
if_index = (AvahiIfIndex) if_nametoindex(interface);
706
fprintf(stderr, "No such interface: \"%s\"\n", interface);
711
if(connect_to != NULL){
712
/* Connect directly, do not use Zeroconf */
713
/* (Mainly meant for debugging) */
714
char *address = strrchr(connect_to, ':');
716
fprintf(stderr, "No colon in address\n");
720
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
722
perror("Bad port number");
726
address = connect_to;
727
ret = start_mandos_communication(address, port, if_index);
735
certkey = combinepath(certdir, certkey);
736
if (certkey == NULL){
662
741
avahi_set_log_function(empty_log);
697
776
/* Create the service browser */
698
sb = avahi_s_service_browser_new(server,
700
if_nametoindex(interface),
777
sb = avahi_s_service_browser_new(server, if_index,
701
778
AVAHI_PROTO_INET6,
702
779
"_mandos._tcp", NULL, 0,
703
780
browse_callback, server);