60
64
#include <string.h> /* memset */
61
65
#include <arpa/inet.h> /* inet_pton() */
62
66
#include <iso646.h> /* not */
67
#include <net/if.h> /* IF_NAMESIZE */
65
70
#include <errno.h> /* perror() */
69
74
#include <getopt.h>
71
76
#define BUFFER_SIZE 256
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";
78
static const char *keydir = "/conf/conf.d/mandos";
79
static const char *pubkeyfile = "pubkey.txt";
80
static const char *seckeyfile = "seckey.txt";
78
82
bool debug = false;
84
const char mandos_protocol_version[] = "1";
86
/* Used for passing in values through all the callback functions */
81
88
AvahiSimplePoll *simple_poll;
82
89
AvahiServer *server;
83
90
gnutls_certificate_credentials_t cred;
84
91
unsigned int dh_bits;
92
gnutls_dh_params_t dh_params;
85
93
const char *priority;
88
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
96
size_t adjustbuffer(char **buffer, size_t buffer_length,
97
size_t buffer_capacity){
98
if (buffer_length + BUFFER_SIZE > buffer_capacity){
99
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
103
buffer_capacity += BUFFER_SIZE;
105
return buffer_capacity;
109
* Decrypt OpenPGP data using keyrings in HOMEDIR.
110
* Returns -1 on error
112
static ssize_t pgp_packet_decrypt (const char *cryptotext,
90
115
const char *homedir){
91
116
gpgme_data_t dh_crypto, dh_plain;
95
ssize_t new_packet_capacity = 0;
96
ssize_t new_packet_length = 0;
120
size_t plaintext_capacity = 0;
121
ssize_t plaintext_length = 0;
97
122
gpgme_engine_info_t engine_info;
100
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
125
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
198
/* Delete the GPGME FILE pointer cryptotext data buffer */
199
gpgme_data_release(dh_crypto);
201
227
/* Seek back to the beginning of the GPGME plaintext data buffer */
202
228
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
203
229
perror("pgpme_data_seek");
230
plaintext_length = -1;
208
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
209
*new_packet = realloc(*new_packet,
210
(unsigned int)new_packet_capacity
212
if (*new_packet == NULL){
216
new_packet_capacity += BUFFER_SIZE;
236
plaintext_capacity = adjustbuffer(plaintext, (size_t)plaintext_length,
238
if (plaintext_capacity == 0){
239
perror("adjustbuffer");
240
plaintext_length = -1;
219
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
244
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
221
246
/* Print the data, if any */
226
252
perror("gpgme_data_read");
253
plaintext_length = -1;
229
new_packet_length += ret;
256
plaintext_length += ret;
232
/* FIXME: check characters before printing to screen so to not print
233
terminal control characters */
235
/* fprintf(stderr, "decrypted password is: "); */
236
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
237
/* fprintf(stderr, "\n"); */
260
fprintf(stderr, "Decrypted password is: ");
261
for(ssize_t i = 0; i < plaintext_length; i++){
262
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
264
fprintf(stderr, "\n");
269
/* Delete the GPGME cryptotext data buffer */
270
gpgme_data_release(dh_crypto);
240
272
/* Delete the GPGME plaintext data buffer */
241
273
gpgme_data_release(dh_plain);
242
return new_packet_length;
274
return plaintext_length;
245
277
static const char * safer_gnutls_strerror (int value) {
265
297
if ((ret = gnutls_global_init ())
266
298
!= GNUTLS_E_SUCCESS) {
267
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
299
fprintf (stderr, "GnuTLS global_init: %s\n",
300
safer_gnutls_strerror(ret));
305
/* "Use a log level over 10 to enable all debugging options."
272
308
gnutls_global_set_log_level(11);
273
309
gnutls_global_set_log_function(debuggnutls);
276
/* openpgp credentials */
277
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
312
/* OpenPGP credentials */
313
if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
278
314
!= GNUTLS_E_SUCCESS) {
279
fprintf (stderr, "memory error: %s\n",
315
fprintf (stderr, "GnuTLS memory error: %s\n",
280
316
safer_gnutls_strerror(ret));
285
321
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
286
" and keyfile %s as GnuTLS credentials\n", certfile,
322
" and keyfile %s as GnuTLS credentials\n", pubkeyfile,
290
326
ret = gnutls_certificate_set_openpgp_key_file
291
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
327
(mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
292
328
if (ret != GNUTLS_E_SUCCESS) {
294
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
296
ret, certfile, certkey);
297
fprintf(stdout, "The Error is: %s\n",
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",
298
333
safer_gnutls_strerror(ret));
302
//GnuTLS server initialization
303
if ((ret = gnutls_dh_params_init (&es->dh_params))
304
!= GNUTLS_E_SUCCESS) {
305
fprintf (stderr, "Error in dh parameter initialization: %s\n",
306
safer_gnutls_strerror(ret));
310
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
311
!= GNUTLS_E_SUCCESS) {
312
fprintf (stderr, "Error in prime generation: %s\n",
313
safer_gnutls_strerror(ret));
317
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
319
// GnuTLS session creation
320
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
321
!= GNUTLS_E_SUCCESS){
337
/* GnuTLS server initialization */
338
ret = gnutls_dh_params_init(&mc->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(mc->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, mc->dh_params);
356
static int init_gnutls_session(mandos_context *mc, gnutls_session_t *session){
358
/* GnuTLS session creation */
359
ret = gnutls_init(session, GNUTLS_SERVER);
360
if (ret != GNUTLS_E_SUCCESS){
322
361
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
323
362
safer_gnutls_strerror(ret));
326
if ((ret = gnutls_priority_set_direct (es->session, mc->priority, &err))
327
!= GNUTLS_E_SUCCESS) {
328
fprintf(stderr, "Syntax error at: %s\n", err);
329
fprintf(stderr, "GnuTLS error: %s\n",
330
safer_gnutls_strerror(ret));
367
ret = gnutls_priority_set_direct(*session, mc->priority, &err);
368
if (ret != GNUTLS_E_SUCCESS) {
369
fprintf(stderr, "Syntax error at: %s\n", err);
370
fprintf(stderr, "GnuTLS error: %s\n",
371
safer_gnutls_strerror(ret));
334
if ((ret = gnutls_credentials_set
335
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
336
!= GNUTLS_E_SUCCESS) {
337
fprintf(stderr, "Error setting a credentials set: %s\n",
376
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
378
if (ret != GNUTLS_E_SUCCESS) {
379
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
338
380
safer_gnutls_strerror(ret));
342
384
/* ignore client certificate if any. */
343
gnutls_certificate_server_set_request (es->session,
385
gnutls_certificate_server_set_request (*session,
344
386
GNUTLS_CERT_IGNORE);
346
gnutls_dh_set_prime_bits (es->session, DH_BITS);
388
gnutls_dh_set_prime_bits (*session, mc->dh_bits);
393
/* Avahi log function callback */
351
394
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
352
395
__attribute__((unused)) const char *txt){}
397
/* Called when a Mandos server is found */
354
398
static int start_mandos_communication(const char *ip, uint16_t port,
355
399
AvahiIfIndex if_index,
356
400
mandos_context *mc){
358
402
struct sockaddr_in6 to;
359
encrypted_session es;
360
403
char *buffer = NULL;
361
404
char *decrypted_buffer;
362
405
size_t buffer_length = 0;
363
406
size_t buffer_capacity = 0;
364
407
ssize_t decrypted_buffer_size;
367
410
char interface[IF_NAMESIZE];
411
gnutls_session_t session;
412
gnutls_dh_params_t dh_params;
414
ret = init_gnutls_session (mc, &session);
370
420
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
407
456
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
408
/* char addrstr[INET6_ADDRSTRLEN]; */
409
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
410
/* sizeof(addrstr)) == NULL){ */
411
/* perror("inet_ntop"); */
413
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
414
/* addrstr, ntohs(to.sin6_port)); */
457
char addrstr[INET6_ADDRSTRLEN] = "";
458
if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
459
sizeof(addrstr)) == NULL){
462
if(strcmp(addrstr, ip) != 0){
463
fprintf(stderr, "Canonical address form: %s\n", addrstr);
418
468
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
473
538
case GNUTLS_E_AGAIN:
475
540
case GNUTLS_E_REHANDSHAKE:
476
ret = gnutls_handshake (es.session);
541
ret = gnutls_handshake (session);
478
fprintf(stderr, "\n*** Handshake failed ***\n");
543
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
479
544
gnutls_perror (ret);
485
550
fprintf(stderr, "Unknown error while reading data from"
486
" encrypted session with mandos server\n");
551
" encrypted session with Mandos server\n");
488
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
553
gnutls_bye (session, GNUTLS_SHUT_RDWR);
492
557
buffer_length += (size_t) ret;
562
fprintf(stderr, "Closing TLS session\n");
565
gnutls_bye (session, GNUTLS_SHUT_RDWR);
496
567
if (buffer_length > 0){
497
568
decrypted_buffer_size = pgp_packet_decrypt(buffer,
499
570
&decrypted_buffer,
501
572
if (decrypted_buffer_size >= 0){
502
574
while(written < (size_t) decrypted_buffer_size){
503
575
ret = (int)fwrite (decrypted_buffer + written, 1,
504
576
(size_t)decrypted_buffer_size - written,
525
fprintf(stderr, "Closing TLS session\n");
594
/* Shutdown procedure */
529
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
532
gnutls_deinit (es.session);
533
gnutls_certificate_free_credentials (es.cred);
599
gnutls_deinit (session);
600
gnutls_certificate_free_credentials (mc->cred);
534
601
gnutls_global_deinit ();
538
static void resolve_callback( 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) {
605
static void resolve_callback(AvahiSServiceResolver *r,
606
AvahiIfIndex interface,
607
AVAHI_GCC_UNUSED AvahiProtocol protocol,
608
AvahiResolverEvent event,
612
const char *host_name,
613
const AvahiAddress *address,
615
AVAHI_GCC_UNUSED AvahiStringList *txt,
616
AVAHI_GCC_UNUSED AvahiLookupResultFlags
551
619
mandos_context *mc = userdata;
552
620
assert(r); /* Spurious warning */
599
668
case AVAHI_BROWSER_FAILURE:
601
fprintf(stderr, "(Browser) %s\n",
670
fprintf(stderr, "(Avahi browser) %s\n",
602
671
avahi_strerror(avahi_server_errno(mc->server)));
603
672
avahi_simple_poll_quit(mc->simple_poll);
606
675
case AVAHI_BROWSER_NEW:
607
/* We ignore the returned resolver object. In the callback
608
function we free it. If the server is terminated before
609
the callback function is called the server will free
610
the resolver for us. */
612
if (!(avahi_s_service_resolver_new(mc->server, interface, protocol, name,
676
/* We ignore the returned Avahi resolver object. In the callback
677
function we free it. If the Avahi server is terminated before
678
the callback function is called the Avahi server will free the
681
if (!(avahi_s_service_resolver_new(mc->server, interface,
682
protocol, name, type, domain,
614
683
AVAHI_PROTO_INET6, 0,
615
684
resolve_callback, mc)))
616
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
617
avahi_strerror(avahi_server_errno(s)));
685
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
686
name, avahi_strerror(avahi_server_errno(mc->server)));
620
689
case AVAHI_BROWSER_REMOVE:
623
692
case AVAHI_BROWSER_ALL_FOR_NOW:
624
693
case AVAHI_BROWSER_CACHE_EXHAUSTED:
695
fprintf(stderr, "No Mandos server found, still searching...\n");
639
memcpy(tmp, first, f_len);
711
memcpy(tmp, first, f_len); /* Spurious warning */
641
713
tmp[f_len] = '/';
643
memcpy(tmp + f_len + 1, second, s_len);
715
memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
645
717
tmp[f_len + 1 + s_len] = '\0';
650
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
651
AvahiServerConfig config;
722
int main(int argc, char *argv[]){
652
723
AvahiSServiceBrowser *sb = NULL;
655
int returncode = EXIT_SUCCESS;
726
int exitcode = EXIT_SUCCESS;
656
727
const char *interface = "eth0";
657
728
struct ifreq network;
659
732
char *connect_to = NULL;
660
733
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
661
734
mandos_context mc = { .simple_poll = NULL, .server = NULL,
662
.dh_bits = 2048, .priority = "SECURE256"};
735
.dh_bits = 1024, .priority = "SECURE256"};
665
static struct option long_options[] = {
666
{"debug", no_argument, (int *)&debug, 1},
667
{"connect", required_argument, 0, 'C'},
668
{"interface", required_argument, 0, 'i'},
669
{"certdir", required_argument, 0, 'd'},
670
{"certkey", required_argument, 0, 'c'},
671
{"certfile", required_argument, 0, 'k'},
672
{"dh_bits", required_argument, 0, 'D'},
673
{"priority", required_argument, 0, 'p'},
676
int option_index = 0;
677
ret = getopt_long (argc, argv, "i:", long_options,
738
/* Temporary int to get the address of for getopt_long */
739
int debug_int = debug ? 1 : 0;
741
struct option long_options[] = {
742
{"debug", no_argument, &debug_int, 1},
743
{"connect", required_argument, NULL, 'c'},
744
{"interface", required_argument, NULL, 'i'},
745
{"keydir", required_argument, NULL, 'd'},
746
{"seckey", required_argument, NULL, 's'},
747
{"pubkey", required_argument, NULL, 'p'},
748
{"dh-bits", required_argument, NULL, 'D'},
749
{"priority", required_argument, NULL, 'P'},
752
int option_index = 0;
753
ret = getopt_long (argc, argv, "i:", long_options,
706
tmp = strtol(optarg, NULL, 10);
707
if (errno == ERANGE){
780
mc.dh_bits = (unsigned int) strtol(optarg, NULL, 10);
708
782
perror("strtol");
709
783
exit(EXIT_FAILURE);
787
mc.priority = optarg;
791
/* getopt_long() has already printed a message about the
792
unrcognized option, so just exit. */
715
mc.priority = optarg;
722
certfile = combinepath(certdir, certfile);
723
if (certfile == NULL){
724
perror("combinepath");
725
returncode = EXIT_FAILURE;
729
certkey = combinepath(certdir, certkey);
730
if (certkey == NULL){
731
perror("combinepath");
732
returncode = EXIT_FAILURE;
796
/* Set the global debug flag from the temporary int */
797
debug = debug_int ? true : false;
800
pubkeyfile = combinepath(keydir, pubkeyfile);
801
if (pubkeyfile == NULL){
802
perror("combinepath");
803
exitcode = EXIT_FAILURE;
807
seckeyfile = combinepath(keydir, seckeyfile);
808
if (seckeyfile == NULL){
809
perror("combinepath");
813
ret = init_gnutls_global(&mc);
815
fprintf(stderr, "init_gnutls_global\n");
736
832
if_index = (AvahiIfIndex) if_nametoindex(interface);
745
841
char *address = strrchr(connect_to, ':');
746
842
if(address == NULL){
747
843
fprintf(stderr, "No colon in address\n");
844
exitcode = EXIT_FAILURE;
751
848
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
753
850
perror("Bad port number");
851
exitcode = EXIT_FAILURE;
757
855
address = connect_to;
758
ret = start_mandos_communication(address, port, if_index);
856
ret = start_mandos_communication(address, port, if_index, &mc);
858
exitcode = EXIT_FAILURE;
860
exitcode = EXIT_SUCCESS;
766
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
769
returncode = EXIT_FAILURE;
772
strcpy(network.ifr_name, interface);
773
ret = ioctl(sd, SIOCGIFFLAGS, &network);
776
perror("ioctl SIOCGIFFLAGS");
777
returncode = EXIT_FAILURE;
780
if((network.ifr_flags & IFF_UP) == 0){
781
network.ifr_flags |= IFF_UP;
782
ret = ioctl(sd, SIOCSIFFLAGS, &network);
865
/* If the interface is down, bring it up */
867
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
870
exitcode = EXIT_FAILURE;
873
strcpy(network.ifr_name, interface); /* Spurious warning */
874
ret = ioctl(sd, SIOCGIFFLAGS, &network);
784
perror("ioctl SIOCSIFFLAGS");
785
returncode = EXIT_FAILURE;
876
perror("ioctl SIOCGIFFLAGS");
877
exitcode = EXIT_FAILURE;
880
if((network.ifr_flags & IFF_UP) == 0){
881
network.ifr_flags |= IFF_UP;
882
ret = ioctl(sd, SIOCSIFFLAGS, &network);
884
perror("ioctl SIOCSIFFLAGS");
885
exitcode = EXIT_FAILURE;
792
893
avahi_set_log_function(empty_log);
795
/* Initialize the psuedo-RNG */
896
/* Initialize the pseudo-RNG for Avahi */
796
897
srand((unsigned int) time(NULL));
798
/* Allocate main loop object */
799
if (!(mc.simple_poll = avahi_simple_poll_new())) {
800
fprintf(stderr, "Failed to create simple poll object.\n");
801
returncode = EXIT_FAILURE;
805
/* Do not publish any local records */
806
avahi_server_config_init(&config);
807
config.publish_hinfo = 0;
808
config.publish_addresses = 0;
809
config.publish_workstation = 0;
810
config.publish_domain = 0;
812
/* Allocate a new server */
813
mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
814
&config, NULL, NULL, &error);
816
/* Free the configuration data */
817
avahi_server_config_free(&config);
819
/* Check if creating the server object succeeded */
821
fprintf(stderr, "Failed to create server: %s\n",
899
/* Allocate main Avahi loop object */
900
mc.simple_poll = avahi_simple_poll_new();
901
if (mc.simple_poll == NULL) {
902
fprintf(stderr, "Avahi: Failed to create simple poll"
904
exitcode = EXIT_FAILURE;
909
AvahiServerConfig config;
910
/* Do not publish any local Zeroconf records */
911
avahi_server_config_init(&config);
912
config.publish_hinfo = 0;
913
config.publish_addresses = 0;
914
config.publish_workstation = 0;
915
config.publish_domain = 0;
917
/* Allocate a new server */
918
mc.server = avahi_server_new(avahi_simple_poll_get
919
(mc.simple_poll), &config, NULL,
922
/* Free the Avahi configuration data */
923
avahi_server_config_free(&config);
926
/* Check if creating the Avahi server object succeeded */
927
if (mc.server == NULL) {
928
fprintf(stderr, "Failed to create Avahi server: %s\n",
822
929
avahi_strerror(error));
823
returncode = EXIT_FAILURE;
930
exitcode = EXIT_FAILURE;
827
/* Create the service browser */
934
/* Create the Avahi service browser */
828
935
sb = avahi_s_service_browser_new(mc.server, if_index,
829
936
AVAHI_PROTO_INET6,
830
937
"_mandos._tcp", NULL, 0,
831
938
browse_callback, &mc);
833
940
fprintf(stderr, "Failed to create service browser: %s\n",
834
941
avahi_strerror(avahi_server_errno(mc.server)));
835
returncode = EXIT_FAILURE;
942
exitcode = EXIT_FAILURE;
839
946
/* Run the main loop */
842
fprintf(stderr, "Starting avahi loop search\n");
949
fprintf(stderr, "Starting Avahi loop search\n");
845
avahi_simple_poll_loop(simple_poll);
952
avahi_simple_poll_loop(mc.simple_poll);
850
957
fprintf(stderr, "%s exiting\n", argv[0]);
853
960
/* Cleanup things */
855
962
avahi_s_service_browser_free(sb);
964
if (mc.server != NULL)
858
965
avahi_server_free(mc.server);
861
avahi_simple_poll_free(simple_poll);
967
if (mc.simple_poll != NULL)
968
avahi_simple_poll_free(mc.simple_poll);