64
59
#include <string.h> /* memset */
65
60
#include <arpa/inet.h> /* inet_pton() */
66
61
#include <iso646.h> /* not */
67
#include <net/if.h> /* IF_NAMESIZE */
70
64
#include <errno.h> /* perror() */
74
68
#include <getopt.h>
76
70
#define BUFFER_SIZE 256
78
static const char *keydir = "/conf/conf.d/mandos";
79
static const char *pubkeyfile = "pubkey.txt";
80
static const char *seckeyfile = "seckey.txt";
73
const char *certdir = "/conf/conf.d/cryptkeyreq/";
74
const char *certfile = "openpgp-client.txt";
75
const char *certkey = "openpgp-client-key.txt";
82
77
bool debug = false;
84
const char mandos_protocol_version[] = "1";
86
/* Used for passing in values through all the callback functions */
88
AvahiSimplePoll *simple_poll;
80
gnutls_session_t session;
90
81
gnutls_certificate_credentials_t cred;
95
size_t adjustbuffer(char **buffer, size_t buffer_length,
96
size_t buffer_capacity){
97
if (buffer_length + BUFFER_SIZE > buffer_capacity){
98
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
102
buffer_capacity += BUFFER_SIZE;
104
return buffer_capacity;
108
* Decrypt OpenPGP data using keyrings in HOMEDIR.
109
* Returns -1 on error
111
static ssize_t pgp_packet_decrypt (const char *cryptotext,
114
const char *homedir){
82
gnutls_dh_params_t dh_params;
86
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
87
char **new_packet, const char *homedir){
115
88
gpgme_data_t dh_crypto, dh_plain;
119
size_t plaintext_capacity = 0;
120
ssize_t plaintext_length = 0;
92
ssize_t new_packet_capacity = 0;
93
ssize_t new_packet_length = 0;
121
94
gpgme_engine_info_t engine_info;
124
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
97
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
195
/* Delete the GPGME FILE pointer cryptotext data buffer */
196
gpgme_data_release(dh_crypto);
226
198
/* Seek back to the beginning of the GPGME plaintext data buffer */
227
199
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
228
200
perror("pgpme_data_seek");
229
plaintext_length = -1;
235
plaintext_capacity = adjustbuffer(plaintext, (size_t)plaintext_length,
237
if (plaintext_capacity == 0){
238
perror("adjustbuffer");
239
plaintext_length = -1;
205
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
206
*new_packet = realloc(*new_packet,
207
(unsigned int)new_packet_capacity
209
if (*new_packet == NULL){
213
new_packet_capacity += BUFFER_SIZE;
243
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
216
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
245
218
/* Print the data, if any */
251
223
perror("gpgme_data_read");
252
plaintext_length = -1;
255
plaintext_length += ret;
226
new_packet_length += ret;
259
fprintf(stderr, "Decrypted password is: ");
260
for(ssize_t i = 0; i < plaintext_length; i++){
261
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
263
fprintf(stderr, "\n");
268
/* Delete the GPGME cryptotext data buffer */
269
gpgme_data_release(dh_crypto);
229
/* FIXME: check characters before printing to screen so to not print
230
terminal control characters */
232
/* fprintf(stderr, "decrypted password is: "); */
233
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
234
/* fprintf(stderr, "\n"); */
271
237
/* Delete the GPGME plaintext data buffer */
272
238
gpgme_data_release(dh_plain);
273
return plaintext_length;
239
return new_packet_length;
276
242
static const char * safer_gnutls_strerror (int value) {
297
262
if ((ret = gnutls_global_init ())
298
263
!= GNUTLS_E_SUCCESS) {
299
fprintf (stderr, "GnuTLS global_init: %s\n",
300
safer_gnutls_strerror(ret));
264
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
305
/* "Use a log level over 10 to enable all debugging options."
308
269
gnutls_global_set_log_level(11);
309
270
gnutls_global_set_log_function(debuggnutls);
312
/* OpenPGP credentials */
313
if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
273
/* openpgp credentials */
274
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
314
275
!= GNUTLS_E_SUCCESS) {
315
fprintf (stderr, "GnuTLS memory error: %s\n",
276
fprintf (stderr, "memory error: %s\n",
316
277
safer_gnutls_strerror(ret));
321
282
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
322
" and keyfile %s as GnuTLS credentials\n", pubkeyfile,
283
" and keyfile %s as GnuTLS credentials\n", certfile,
326
287
ret = gnutls_certificate_set_openpgp_key_file
327
(mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
288
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
328
289
if (ret != GNUTLS_E_SUCCESS) {
330
"Error[%d] while reading the OpenPGP key pair ('%s',"
331
" '%s')\n", ret, pubkeyfile, seckeyfile);
332
fprintf(stdout, "The GnuTLS error is: %s\n",
291
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
293
ret, certfile, certkey);
294
fprintf(stdout, "The Error is: %s\n",
333
295
safer_gnutls_strerror(ret));
337
/* GnuTLS server initialization */
338
ret = gnutls_dh_params_init(dh_params);
339
if (ret != GNUTLS_E_SUCCESS) {
340
fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
341
" %s\n", safer_gnutls_strerror(ret));
344
ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits);
345
if (ret != GNUTLS_E_SUCCESS) {
346
fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
347
safer_gnutls_strerror(ret));
351
gnutls_certificate_set_dh_params(mc->cred, *dh_params);
353
/* GnuTLS session creation */
354
ret = gnutls_init(session, GNUTLS_SERVER);
355
if (ret != GNUTLS_E_SUCCESS){
299
//GnuTLS server initialization
300
if ((ret = gnutls_dh_params_init (&es->dh_params))
301
!= GNUTLS_E_SUCCESS) {
302
fprintf (stderr, "Error in dh parameter initialization: %s\n",
303
safer_gnutls_strerror(ret));
307
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
308
!= GNUTLS_E_SUCCESS) {
309
fprintf (stderr, "Error in prime generation: %s\n",
310
safer_gnutls_strerror(ret));
314
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
316
// GnuTLS session creation
317
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
318
!= GNUTLS_E_SUCCESS){
356
319
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
357
320
safer_gnutls_strerror(ret));
362
ret = gnutls_priority_set_direct(*session, mc->priority, &err);
363
if (ret != GNUTLS_E_SUCCESS) {
364
fprintf(stderr, "Syntax error at: %s\n", err);
365
fprintf(stderr, "GnuTLS error: %s\n",
366
safer_gnutls_strerror(ret));
323
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
324
!= GNUTLS_E_SUCCESS) {
325
fprintf(stderr, "Syntax error at: %s\n", err);
326
fprintf(stderr, "GnuTLS error: %s\n",
327
safer_gnutls_strerror(ret));
371
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
373
if (ret != GNUTLS_E_SUCCESS) {
374
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
331
if ((ret = gnutls_credentials_set
332
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
333
!= GNUTLS_E_SUCCESS) {
334
fprintf(stderr, "Error setting a credentials set: %s\n",
375
335
safer_gnutls_strerror(ret));
379
339
/* ignore client certificate if any. */
380
gnutls_certificate_server_set_request (*session,
340
gnutls_certificate_server_set_request (es->session,
381
341
GNUTLS_CERT_IGNORE);
383
gnutls_dh_set_prime_bits (*session, mc->dh_bits);
343
gnutls_dh_set_prime_bits (es->session, DH_BITS);
388
/* Avahi log function callback */
389
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
390
__attribute__((unused)) const char *txt){}
348
void empty_log(__attribute__((unused)) AvahiLogLevel level,
349
__attribute__((unused)) const char *txt){}
392
/* Called when a Mandos server is found */
393
static int start_mandos_communication(const char *ip, uint16_t port,
394
AvahiIfIndex if_index,
351
int start_mandos_communication(const char *ip, uint16_t port,
352
AvahiIfIndex if_index){
397
354
struct sockaddr_in6 to;
355
encrypted_session es;
398
356
char *buffer = NULL;
399
357
char *decrypted_buffer;
400
358
size_t buffer_length = 0;
401
359
size_t buffer_capacity = 0;
402
360
ssize_t decrypted_buffer_size;
405
363
char interface[IF_NAMESIZE];
406
gnutls_session_t session;
407
gnutls_dh_params_t dh_params;
409
ret = initgnutls (mc, &session, &dh_params);
415
366
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
589
/* Shutdown procedure */
521
fprintf(stderr, "Closing TLS session\n");
525
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
594
gnutls_deinit (session);
595
gnutls_certificate_free_credentials (mc->cred);
528
gnutls_deinit (es.session);
529
gnutls_certificate_free_credentials (es.cred);
596
530
gnutls_global_deinit ();
600
static void resolve_callback(AvahiSServiceResolver *r,
601
AvahiIfIndex interface,
602
AVAHI_GCC_UNUSED AvahiProtocol protocol,
603
AvahiResolverEvent event,
607
const char *host_name,
608
const AvahiAddress *address,
610
AVAHI_GCC_UNUSED AvahiStringList *txt,
611
AVAHI_GCC_UNUSED AvahiLookupResultFlags
614
mandos_context *mc = userdata;
534
static AvahiSimplePoll *simple_poll = NULL;
535
static AvahiServer *server = NULL;
537
static void resolve_callback(
538
AvahiSServiceResolver *r,
539
AvahiIfIndex interface,
540
AVAHI_GCC_UNUSED AvahiProtocol protocol,
541
AvahiResolverEvent event,
545
const char *host_name,
546
const AvahiAddress *address,
548
AVAHI_GCC_UNUSED AvahiStringList *txt,
549
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
550
AVAHI_GCC_UNUSED void* userdata) {
615
552
assert(r); /* Spurious warning */
617
554
/* Called whenever a service has been resolved successfully or
642
579
avahi_s_service_resolver_free(r);
645
static void browse_callback( AvahiSServiceBrowser *b,
646
AvahiIfIndex interface,
647
AvahiProtocol protocol,
648
AvahiBrowserEvent event,
652
AVAHI_GCC_UNUSED AvahiLookupResultFlags
655
mandos_context *mc = userdata;
656
assert(b); /* Spurious warning */
658
/* Called whenever a new services becomes available on the LAN or
659
is removed from the LAN */
663
case AVAHI_BROWSER_FAILURE:
665
fprintf(stderr, "(Avahi browser) %s\n",
666
avahi_strerror(avahi_server_errno(mc->server)));
667
avahi_simple_poll_quit(mc->simple_poll);
670
case AVAHI_BROWSER_NEW:
671
/* We ignore the returned Avahi resolver object. In the callback
672
function we free it. If the Avahi server is terminated before
673
the callback function is called the Avahi server will free the
676
if (!(avahi_s_service_resolver_new(mc->server, interface,
677
protocol, name, type, domain,
678
AVAHI_PROTO_INET6, 0,
679
resolve_callback, mc)))
680
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
681
name, avahi_strerror(avahi_server_errno(mc->server)));
684
case AVAHI_BROWSER_REMOVE:
687
case AVAHI_BROWSER_ALL_FOR_NOW:
688
case AVAHI_BROWSER_CACHE_EXHAUSTED:
690
fprintf(stderr, "No Mandos server found, still searching...\n");
582
static void browse_callback(
583
AvahiSServiceBrowser *b,
584
AvahiIfIndex interface,
585
AvahiProtocol protocol,
586
AvahiBrowserEvent event,
590
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
593
AvahiServer *s = userdata;
594
assert(b); /* Spurious warning */
596
/* Called whenever a new services becomes available on the LAN or
597
is removed from the LAN */
601
case AVAHI_BROWSER_FAILURE:
603
fprintf(stderr, "(Browser) %s\n",
604
avahi_strerror(avahi_server_errno(server)));
605
avahi_simple_poll_quit(simple_poll);
608
case AVAHI_BROWSER_NEW:
609
/* We ignore the returned resolver object. In the callback
610
function we free it. If the server is terminated before
611
the callback function is called the server will free
612
the resolver for us. */
614
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
616
AVAHI_PROTO_INET6, 0,
617
resolve_callback, s)))
618
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
619
avahi_strerror(avahi_server_errno(s)));
622
case AVAHI_BROWSER_REMOVE:
625
case AVAHI_BROWSER_ALL_FOR_NOW:
626
case AVAHI_BROWSER_CACHE_EXHAUSTED:
696
/* Combines file name and path and returns the malloced new
697
string. some sane checks could/should be added */
698
static const char *combinepath(const char *first, const char *second){
699
size_t f_len = strlen(first);
700
size_t s_len = strlen(second);
701
char *tmp = malloc(f_len + s_len + 2);
631
/* combinds file name and path and returns the malloced new string. som sane checks could/should be added */
632
const char *combinepath(const char *first, const char *second){
634
tmp = malloc(strlen(first) + strlen(second) + 2);
702
635
if (tmp == NULL){
706
memcpy(tmp, first, f_len); /* Spurious warning */
710
memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
712
tmp[f_len + 1 + s_len] = '\0';
640
if (first[0] != '\0' and first[strlen(first) - 1] != '/'){
717
int main(int argc, char *argv[]){
648
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
649
AvahiServerConfig config;
718
650
AvahiSServiceBrowser *sb = NULL;
721
int exitcode = EXIT_SUCCESS;
722
const char *interface = "eth0";
723
struct ifreq network;
653
int returncode = EXIT_SUCCESS;
654
const char *interface = NULL;
655
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
725
656
char *connect_to = NULL;
726
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
727
mandos_context mc = { .simple_poll = NULL, .server = NULL,
728
.dh_bits = 1024, .priority = "SECURE256"};
731
/* Temporary int to get the address of for getopt_long */
732
int debug_int = debug ? 1 : 0;
734
struct option long_options[] = {
735
{"debug", no_argument, &debug_int, 1},
736
{"connect", required_argument, NULL, 'c'},
737
{"interface", required_argument, NULL, 'i'},
738
{"keydir", required_argument, NULL, 'd'},
739
{"seckey", required_argument, NULL, 's'},
740
{"pubkey", required_argument, NULL, 'p'},
741
{"dh-bits", required_argument, NULL, 'D'},
742
{"priority", required_argument, NULL, 'P'},
745
int option_index = 0;
746
ret = getopt_long (argc, argv, "i:", long_options,
773
mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
780
mc.priority = optarg;
784
/* getopt_long() has already printed a message about the
785
unrcognized option, so just exit. */
789
/* Set the global debug flag from the temporary int */
790
debug = debug_int ? true : false;
793
pubkeyfile = combinepath(keydir, pubkeyfile);
794
if (pubkeyfile == NULL){
795
perror("combinepath");
796
exitcode = EXIT_FAILURE;
800
seckeyfile = combinepath(keydir, seckeyfile);
801
if (seckeyfile == NULL){
802
perror("combinepath");
806
if_index = (AvahiIfIndex) if_nametoindex(interface);
808
fprintf(stderr, "No such interface: \"%s\"\n", interface);
659
static struct option long_options[] = {
660
{"debug", no_argument, (int *)&debug, 1},
661
{"connect", required_argument, 0, 'C'},
662
{"interface", required_argument, 0, 'i'},
663
{"certdir", required_argument, 0, 'd'},
664
{"certkey", required_argument, 0, 'c'},
665
{"certfile", required_argument, 0, 'k'},
668
int option_index = 0;
669
ret = getopt_long (argc, argv, "i:", long_options,
699
certfile = combinepath(certdir, certfile);
700
if (certfile == NULL){
704
if(interface != NULL){
705
if_index = (AvahiIfIndex) if_nametoindex(interface);
707
fprintf(stderr, "No such interface: \"%s\"\n", interface);
812
712
if(connect_to != NULL){
836
/* If the interface is down, bring it up */
838
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
841
exitcode = EXIT_FAILURE;
844
strcpy(network.ifr_name, interface); /* Spurious warning */
845
ret = ioctl(sd, SIOCGIFFLAGS, &network);
847
perror("ioctl SIOCGIFFLAGS");
848
exitcode = EXIT_FAILURE;
851
if((network.ifr_flags & IFF_UP) == 0){
852
network.ifr_flags |= IFF_UP;
853
ret = ioctl(sd, SIOCSIFFLAGS, &network);
855
perror("ioctl SIOCSIFFLAGS");
856
exitcode = EXIT_FAILURE;
736
certkey = combinepath(certdir, certkey);
737
if (certkey == NULL){
864
742
avahi_set_log_function(empty_log);
867
/* Initialize the pseudo-RNG for Avahi */
745
/* Initialize the psuedo-RNG */
868
746
srand((unsigned int) time(NULL));
870
/* Allocate main Avahi loop object */
871
mc.simple_poll = avahi_simple_poll_new();
872
if (mc.simple_poll == NULL) {
873
fprintf(stderr, "Avahi: Failed to create simple poll"
875
exitcode = EXIT_FAILURE;
880
AvahiServerConfig config;
881
/* Do not publish any local Zeroconf records */
882
avahi_server_config_init(&config);
883
config.publish_hinfo = 0;
884
config.publish_addresses = 0;
885
config.publish_workstation = 0;
886
config.publish_domain = 0;
888
/* Allocate a new server */
889
mc.server = avahi_server_new(avahi_simple_poll_get
890
(mc.simple_poll), &config, NULL,
893
/* Free the Avahi configuration data */
894
avahi_server_config_free(&config);
897
/* Check if creating the Avahi server object succeeded */
898
if (mc.server == NULL) {
899
fprintf(stderr, "Failed to create Avahi server: %s\n",
748
/* Allocate main loop object */
749
if (!(simple_poll = avahi_simple_poll_new())) {
750
fprintf(stderr, "Failed to create simple poll object.\n");
755
/* Do not publish any local records */
756
avahi_server_config_init(&config);
757
config.publish_hinfo = 0;
758
config.publish_addresses = 0;
759
config.publish_workstation = 0;
760
config.publish_domain = 0;
762
/* Allocate a new server */
763
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
764
&config, NULL, NULL, &error);
766
/* Free the configuration data */
767
avahi_server_config_free(&config);
769
/* Check if creating the server object succeeded */
771
fprintf(stderr, "Failed to create server: %s\n",
900
772
avahi_strerror(error));
901
exitcode = EXIT_FAILURE;
773
returncode = EXIT_FAILURE;
905
/* Create the Avahi service browser */
906
sb = avahi_s_service_browser_new(mc.server, if_index,
777
/* Create the service browser */
778
sb = avahi_s_service_browser_new(server, if_index,
907
779
AVAHI_PROTO_INET6,
908
780
"_mandos._tcp", NULL, 0,
909
browse_callback, &mc);
781
browse_callback, server);
911
783
fprintf(stderr, "Failed to create service browser: %s\n",
912
avahi_strerror(avahi_server_errno(mc.server)));
913
exitcode = EXIT_FAILURE;
784
avahi_strerror(avahi_server_errno(server)));
785
returncode = EXIT_FAILURE;
917
789
/* Run the main loop */
920
fprintf(stderr, "Starting Avahi loop search\n");
792
fprintf(stderr, "Starting avahi loop search\n");
923
avahi_simple_poll_loop(mc.simple_poll);
795
avahi_simple_poll_loop(simple_poll);
928
800
fprintf(stderr, "%s exiting\n", argv[0]);
931
803
/* Cleanup things */
933
805
avahi_s_service_browser_free(sb);
935
if (mc.server != NULL)
936
avahi_server_free(mc.server);
808
avahi_server_free(server);
938
if (mc.simple_poll != NULL)
939
avahi_simple_poll_free(mc.simple_poll);
811
avahi_simple_poll_free(simple_poll);