8
8
* includes the following functions: "resolve_callback",
9
9
* "browse_callback", and parts of "main".
12
* Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
11
* Everything else is Copyright © 2007-2008 Teddy Hogeborn and Björn
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 <mandos@fukt.bsnet.se>.
28
* Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
29
* <https://www.fukt.bsnet.se/~teddy/>.
31
/* Needed by GPGME, specifically gpgme_data_seek() */
32
#define _FORTIFY_SOURCE 2
32
34
#define _LARGEFILE_SOURCE
33
35
#define _FILE_OFFSET_BITS 64
46
48
#include <avahi-common/error.h>
48
50
//mandos client part
49
#include <sys/types.h> /* socket(), inet_pton() */
50
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
51
#include <sys/types.h> /* socket(), setsockopt(),
53
#include <sys/socket.h> /* socket(), setsockopt(),
51
55
struct in6_addr, inet_pton() */
52
56
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
53
57
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
67
71
#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"
69
78
#define BUFFER_SIZE 256
70
79
#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";
76
81
bool debug = false;
100
105
gpgme_check_version(NULL);
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));
106
gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
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
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
199
perror("pgpme_data_seek");
198
gpgme_data_seek(dh_plain, 0, SEEK_SET);
204
202
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
258
256
fprintf(stderr, "Initializing GnuTLS\n");
261
259
if ((ret = gnutls_global_init ())
262
260
!= GNUTLS_E_SUCCESS) {
263
261
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
281
279
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
282
" and keyfile %s as GnuTLS credentials\n", certfile,
280
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
286
284
ret = gnutls_certificate_set_openpgp_key_file
287
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
285
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
288
286
if (ret != GNUTLS_E_SUCCESS) {
290
288
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
292
ret, certfile, certkey);
290
ret, CERTFILE, KEYFILE);
293
291
fprintf(stdout, "The Error is: %s\n",
294
292
safer_gnutls_strerror(ret));
347
345
void empty_log(__attribute__((unused)) AvahiLogLevel level,
348
346
__attribute__((unused)) const char *txt){}
350
int start_mandos_communication(const char *ip, uint16_t port,
351
AvahiIfIndex if_index){
348
int start_mandos_communication(char *ip, uint16_t port,
349
unsigned int if_index){
353
351
struct sockaddr_in6 to;
354
352
encrypted_session es;
357
355
size_t buffer_length = 0;
358
356
size_t buffer_capacity = 0;
359
357
ssize_t decrypted_buffer_size;
362
359
char interface[IF_NAMESIZE];
365
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
362
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
369
365
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
383
379
fprintf(stderr, "Binding to interface %s\n", interface);
386
memset(&to,0,sizeof(to)); /* Spurious warning */
382
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
384
perror("setsockopt bindtodevice");
388
memset(&to,0,sizeof(to));
387
389
to.sin6_family = AF_INET6;
388
390
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
394
396
fprintf(stderr, "Bad address: %s\n", ip);
397
to.sin6_port = htons(port); /* Spurious warning */
399
/* Spurious warnings for the next line, see for instance
400
<http://bugs.debian.org/488884> */
401
to.sin6_port = htons(port);
399
403
to.sin6_scope_id = (uint32_t)if_index;
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)); */
406
fprintf(stderr, "Connection to: %s\n", ip);
413
409
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
432
428
ret = gnutls_handshake (es.session);
434
430
if (ret != GNUTLS_E_SUCCESS){
436
fprintf(stderr, "\n*** Handshake failed ***\n");
431
fprintf(stderr, "\n*** Handshake failed ***\n");
492
486
decrypted_buffer_size = pgp_packet_decrypt(buffer,
494
488
&decrypted_buffer,
496
490
if (decrypted_buffer_size >= 0){
497
while(written < (size_t) decrypted_buffer_size){
498
ret = (int)fwrite (decrypted_buffer + written, 1,
499
(size_t)decrypted_buffer_size - written,
491
while(decrypted_buffer_size > 0){
492
ret = fwrite (decrypted_buffer, 1, (size_t)decrypted_buffer_size,
501
494
if(ret == 0 and ferror(stdout)){
503
496
fprintf(stderr, "Error writing encrypted data: %s\n",
536
530
static void resolve_callback(
537
531
AvahiSServiceResolver *r,
538
AvahiIfIndex interface,
532
AVAHI_GCC_UNUSED AvahiIfIndex interface,
539
533
AVAHI_GCC_UNUSED AvahiProtocol protocol,
540
534
AvahiResolverEvent event,
541
535
const char *name,
548
542
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
549
543
AVAHI_GCC_UNUSED void* userdata) {
551
assert(r); /* Spurious warning */
553
547
/* Called whenever a service has been resolved successfully or
558
552
case AVAHI_RESOLVER_FAILURE:
560
554
" type '%s' in domain '%s': %s\n", name, type, domain,
561
555
avahi_strerror(avahi_server_errno(server)));
564
558
case AVAHI_RESOLVER_FOUND:
566
560
char ip[AVAHI_ADDRESS_STR_MAX];
567
561
avahi_address_snprint(ip, sizeof(ip), address);
569
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
570
" port %d\n", name, host_name, ip, port);
563
fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
564
host_name, ip, port);
572
int ret = start_mandos_communication(ip, port, interface);
566
int ret = start_mandos_communication(ip, port,
574
570
exit(EXIT_SUCCESS);
590
588
void* userdata) {
592
590
AvahiServer *s = userdata;
593
assert(b); /* Spurious warning */
595
593
/* Called whenever a new services becomes available on the LAN or
596
594
is removed from the LAN */
600
598
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] != '/'){
647
628
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
648
629
AvahiServerConfig config;
649
630
AvahiSServiceBrowser *sb = NULL;
652
633
int returncode = EXIT_SUCCESS;
653
const char *interface = NULL;
654
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
655
char *connect_to = NULL;
634
const char *interface = "eth0";
658
637
static struct option long_options[] = {
659
638
{"debug", no_argument, (int *)&debug, 1},
660
{"connect", required_argument, 0, 'C'},
661
639
{"interface", required_argument, 0, 'i'},
662
{"certdir", required_argument, 0, 'd'},
663
{"certkey", required_argument, 0, 'c'},
664
{"certfile", required_argument, 0, 'k'},
667
642
int option_index = 0;
668
643
ret = getopt_long (argc, argv, "i:", long_options,
679
654
interface = optarg;
694
657
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){
741
662
avahi_set_log_function(empty_log);
776
697
/* Create the service browser */
777
sb = avahi_s_service_browser_new(server, if_index,
698
sb = avahi_s_service_browser_new(server,
700
if_nametoindex(interface),
778
701
AVAHI_PROTO_INET6,
779
702
"_mandos._tcp", NULL, 0,
780
703
browse_callback, server);