37
37
#include <stdlib.h>
39
39
#include <net/if.h> /* if_nametoindex */
40
#include <sys/ioctl.h> /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
42
#include <net/if.h> /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
45
41
#include <avahi-core/core.h>
46
42
#include <avahi-core/lookup.h>
73
69
#define BUFFER_SIZE 256
71
static int dh_bits = 1024;
75
73
static const char *keydir = "/conf/conf.d/mandos";
76
74
static const char *pubkeyfile = "pubkey.txt";
77
75
static const char *seckeyfile = "seckey.txt";
79
77
bool debug = false;
81
/* Used for passing in values through all the callback functions */
83
AvahiSimplePoll *simple_poll;
81
gnutls_session_t session;
85
82
gnutls_certificate_credentials_t cred;
91
* Decrypt OpenPGP data using keyrings in HOMEDIR.
94
static ssize_t pgp_packet_decrypt (const char *cryptotext,
83
gnutls_dh_params_t dh_params;
87
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
97
89
const char *homedir){
98
90
gpgme_data_t dh_crypto, dh_plain;
102
ssize_t plaintext_capacity = 0;
103
ssize_t plaintext_length = 0;
94
ssize_t new_packet_capacity = 0;
95
ssize_t new_packet_length = 0;
104
96
gpgme_engine_info_t engine_info;
107
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
99
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
132
124
engine_info = engine_info->next;
134
126
if(engine_info == NULL){
135
fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
127
fprintf(stderr, "Could not set home dir to %s\n", homedir);
139
/* Create new GPGME data buffer from memory cryptotext */
140
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
131
/* Create new GPGME data buffer from packet buffer */
132
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
142
133
if (rc != GPG_ERR_NO_ERROR){
143
134
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
144
135
gpgme_strsource(rc), gpgme_strerror(rc));
159
149
if (rc != GPG_ERR_NO_ERROR){
160
150
fprintf(stderr, "bad gpgme_new: %s: %s\n",
161
151
gpgme_strsource(rc), gpgme_strerror(rc));
162
plaintext_length = -1;
166
/* Decrypt data from the cryptotext data buffer to the plaintext
155
/* Decrypt data from the FILE pointer to the plaintext data
168
157
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
169
158
if (rc != GPG_ERR_NO_ERROR){
170
159
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
171
160
gpgme_strsource(rc), gpgme_strerror(rc));
172
plaintext_length = -1;
177
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
165
fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
181
169
gpgme_decrypt_result_t result;
182
170
result = gpgme_op_decrypt_result(ctx);
197
/* Delete the GPGME FILE pointer cryptotext data buffer */
198
gpgme_data_release(dh_crypto);
209
200
/* Seek back to the beginning of the GPGME plaintext data buffer */
210
201
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
211
202
perror("pgpme_data_seek");
212
plaintext_length = -1;
218
if (plaintext_length + BUFFER_SIZE > plaintext_capacity){
219
*plaintext = realloc(*plaintext,
220
(unsigned int)plaintext_capacity
207
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
208
*new_packet = realloc(*new_packet,
209
(unsigned int)new_packet_capacity
222
if (*plaintext == NULL){
211
if (*new_packet == NULL){
223
212
perror("realloc");
224
plaintext_length = -1;
227
plaintext_capacity += BUFFER_SIZE;
215
new_packet_capacity += BUFFER_SIZE;
230
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
218
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
232
220
/* Print the data, if any */
238
225
perror("gpgme_data_read");
239
plaintext_length = -1;
242
plaintext_length += ret;
228
new_packet_length += ret;
246
fprintf(stderr, "Decrypted password is: ");
247
for(size_t i = 0; i < plaintext_length; i++){
248
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
250
fprintf(stderr, "\n");
255
/* Delete the GPGME cryptotext data buffer */
256
gpgme_data_release(dh_crypto);
231
/* FIXME: check characters before printing to screen so to not print
232
terminal control characters */
234
/* fprintf(stderr, "decrypted password is: "); */
235
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
236
/* fprintf(stderr, "\n"); */
258
239
/* Delete the GPGME plaintext data buffer */
259
240
gpgme_data_release(dh_plain);
260
return plaintext_length;
241
return new_packet_length;
263
244
static const char * safer_gnutls_strerror (int value) {
286
266
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
291
271
gnutls_global_set_log_level(11);
292
272
gnutls_global_set_log_function(debuggnutls);
295
275
/* openpgp credentials */
296
if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
276
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
297
277
!= GNUTLS_E_SUCCESS) {
298
278
fprintf (stderr, "memory error: %s\n",
299
279
safer_gnutls_strerror(ret));
309
289
ret = gnutls_certificate_set_openpgp_key_file
310
(mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
290
(es->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
311
291
if (ret != GNUTLS_E_SUCCESS) {
313
293
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
321
301
//GnuTLS server initialization
322
if ((ret = gnutls_dh_params_init(dh_params))
302
if ((ret = gnutls_dh_params_init (&es->dh_params))
323
303
!= GNUTLS_E_SUCCESS) {
324
304
fprintf (stderr, "Error in dh parameter initialization: %s\n",
325
305
safer_gnutls_strerror(ret));
329
if ((ret = gnutls_dh_params_generate2(*dh_params, mc->dh_bits))
309
if ((ret = gnutls_dh_params_generate2 (es->dh_params, dh_bits))
330
310
!= GNUTLS_E_SUCCESS) {
331
311
fprintf (stderr, "Error in prime generation: %s\n",
332
312
safer_gnutls_strerror(ret));
336
gnutls_certificate_set_dh_params(mc->cred, *dh_params);
316
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
338
318
// GnuTLS session creation
339
if ((ret = gnutls_init(session, GNUTLS_SERVER))
319
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
340
320
!= GNUTLS_E_SUCCESS){
341
321
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
342
322
safer_gnutls_strerror(ret));
345
if ((ret = gnutls_priority_set_direct(*session, mc->priority, &err))
325
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
346
326
!= GNUTLS_E_SUCCESS) {
347
327
fprintf(stderr, "Syntax error at: %s\n", err);
348
328
fprintf(stderr, "GnuTLS error: %s\n",
353
if ((ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
333
if ((ret = gnutls_credentials_set
334
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
355
335
!= GNUTLS_E_SUCCESS) {
356
336
fprintf(stderr, "Error setting a credentials set: %s\n",
357
337
safer_gnutls_strerror(ret));
361
341
/* ignore client certificate if any. */
362
gnutls_certificate_server_set_request (*session,
342
gnutls_certificate_server_set_request (es->session,
363
343
GNUTLS_CERT_IGNORE);
365
gnutls_dh_set_prime_bits (*session, mc->dh_bits);
345
gnutls_dh_set_prime_bits (es->session, dh_bits);
442
ret = initgnutls (mc, &session, &dh_params);
424
ret = initgnutls (&es);
448
gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
430
gnutls_transport_set_ptr (es.session,
431
(gnutls_transport_ptr_t) tcp_sd);
451
434
fprintf(stderr, "Establishing TLS session with %s\n", ip);
454
ret = gnutls_handshake (session);
437
ret = gnutls_handshake (es.session);
456
439
if (ret != GNUTLS_E_SUCCESS){
546
gnutls_bye (session, GNUTLS_SHUT_RDWR);
529
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
549
gnutls_deinit (session);
550
gnutls_certificate_free_credentials (mc->cred);
532
gnutls_deinit (es.session);
533
gnutls_certificate_free_credentials (es.cred);
551
534
gnutls_global_deinit ();
555
static void resolve_callback(AvahiSServiceResolver *r,
556
AvahiIfIndex interface,
557
AVAHI_GCC_UNUSED AvahiProtocol protocol,
558
AvahiResolverEvent event,
562
const char *host_name,
563
const AvahiAddress *address,
565
AVAHI_GCC_UNUSED AvahiStringList *txt,
566
AVAHI_GCC_UNUSED AvahiLookupResultFlags
569
mandos_context *mc = userdata;
538
static AvahiSimplePoll *simple_poll = NULL;
539
static AvahiServer *server = NULL;
541
static void resolve_callback(
542
AvahiSServiceResolver *r,
543
AvahiIfIndex interface,
544
AVAHI_GCC_UNUSED AvahiProtocol protocol,
545
AvahiResolverEvent event,
549
const char *host_name,
550
const AvahiAddress *address,
552
AVAHI_GCC_UNUSED AvahiStringList *txt,
553
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
554
AVAHI_GCC_UNUSED void* userdata) {
570
556
assert(r); /* Spurious warning */
572
558
/* Called whenever a service has been resolved successfully or
577
563
case AVAHI_RESOLVER_FAILURE:
578
564
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
579
565
" type '%s' in domain '%s': %s\n", name, type, domain,
580
avahi_strerror(avahi_server_errno(mc->server)));
566
avahi_strerror(avahi_server_errno(server)));
583
569
case AVAHI_RESOLVER_FOUND:
588
574
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
589
575
" port %d\n", name, host_name, ip, port);
591
int ret = start_mandos_communication(ip, port, interface, mc);
577
int ret = start_mandos_communication(ip, port, interface);
593
579
exit(EXIT_SUCCESS);
597
583
avahi_s_service_resolver_free(r);
600
static void browse_callback( AvahiSServiceBrowser *b,
601
AvahiIfIndex interface,
602
AvahiProtocol protocol,
603
AvahiBrowserEvent event,
607
AVAHI_GCC_UNUSED AvahiLookupResultFlags
610
mandos_context *mc = userdata;
611
assert(b); /* Spurious warning */
613
/* Called whenever a new services becomes available on the LAN or
614
is removed from the LAN */
618
case AVAHI_BROWSER_FAILURE:
620
fprintf(stderr, "(Browser) %s\n",
621
avahi_strerror(avahi_server_errno(mc->server)));
622
avahi_simple_poll_quit(mc->simple_poll);
625
case AVAHI_BROWSER_NEW:
626
/* We ignore the returned resolver object. In the callback
627
function we free it. If the server is terminated before
628
the callback function is called the server will free
629
the resolver for us. */
631
if (!(avahi_s_service_resolver_new(mc->server, interface,
632
protocol, name, type, domain,
633
AVAHI_PROTO_INET6, 0,
634
resolve_callback, mc)))
635
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
636
avahi_strerror(avahi_server_errno(mc->server)));
639
case AVAHI_BROWSER_REMOVE:
642
case AVAHI_BROWSER_ALL_FOR_NOW:
643
case AVAHI_BROWSER_CACHE_EXHAUSTED:
586
static void browse_callback(
587
AvahiSServiceBrowser *b,
588
AvahiIfIndex interface,
589
AvahiProtocol protocol,
590
AvahiBrowserEvent event,
594
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
597
AvahiServer *s = userdata;
598
assert(b); /* Spurious warning */
600
/* Called whenever a new services becomes available on the LAN or
601
is removed from the LAN */
605
case AVAHI_BROWSER_FAILURE:
607
fprintf(stderr, "(Browser) %s\n",
608
avahi_strerror(avahi_server_errno(server)));
609
avahi_simple_poll_quit(simple_poll);
612
case AVAHI_BROWSER_NEW:
613
/* We ignore the returned resolver object. In the callback
614
function we free it. If the server is terminated before
615
the callback function is called the server will free
616
the resolver for us. */
618
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
620
AVAHI_PROTO_INET6, 0,
621
resolve_callback, s)))
622
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
623
avahi_strerror(avahi_server_errno(s)));
626
case AVAHI_BROWSER_REMOVE:
629
case AVAHI_BROWSER_ALL_FOR_NOW:
630
case AVAHI_BROWSER_CACHE_EXHAUSTED:
648
635
/* Combines file name and path and returns the malloced new
658
memcpy(tmp, first, f_len); /* Spurious warning */
645
memcpy(tmp, first, f_len);
660
647
tmp[f_len] = '/';
662
memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
649
memcpy(tmp + f_len + 1, second, s_len);
664
651
tmp[f_len + 1 + s_len] = '\0';
671
658
AvahiSServiceBrowser *sb = NULL;
675
662
int returncode = EXIT_SUCCESS;
676
const char *interface = "eth0";
677
struct ifreq network;
663
const char *interface = NULL;
664
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
679
665
char *connect_to = NULL;
680
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
681
mandos_context mc = { .simple_poll = NULL, .server = NULL,
682
.dh_bits = 1024, .priority = "SECURE256"};
684
667
debug_int = debug ? 1 : 0;
686
struct option long_options[] = {
669
static struct option long_options[] = {
687
670
{"debug", no_argument, &debug_int, 1},
688
{"connect", required_argument, NULL, 'c'},
671
{"connect", required_argument, NULL, 'C'},
689
672
{"interface", required_argument, NULL, 'i'},
690
673
{"keydir", required_argument, NULL, 'd'},
691
{"seckey", required_argument, NULL, 's'},
692
{"pubkey", required_argument, NULL, 'p'},
674
{"seckey", required_argument, NULL, 'c'},
675
{"pubkey", required_argument, NULL, 'k'},
693
676
{"dh-bits", required_argument, NULL, 'D'},
694
{"priority", required_argument, NULL, 'P'},
697
679
int option_index = 0;
741
716
pubkeyfile = combinepath(keydir, pubkeyfile);
742
717
if (pubkeyfile == NULL){
743
718
perror("combinepath");
744
returncode = EXIT_FAILURE;
748
seckeyfile = combinepath(keydir, seckeyfile);
749
if (seckeyfile == NULL){
750
perror("combinepath");
754
if_index = (AvahiIfIndex) if_nametoindex(interface);
756
fprintf(stderr, "No such interface: \"%s\"\n", interface);
722
if(interface != NULL){
723
if_index = (AvahiIfIndex) if_nametoindex(interface);
725
fprintf(stderr, "No such interface: \"%s\"\n", interface);
760
730
if(connect_to != NULL){
784
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
787
returncode = EXIT_FAILURE;
790
strcpy(network.ifr_name, interface); /* Spurious warning */
791
ret = ioctl(sd, SIOCGIFFLAGS, &network);
794
perror("ioctl SIOCGIFFLAGS");
795
returncode = EXIT_FAILURE;
798
if((network.ifr_flags & IFF_UP) == 0){
799
network.ifr_flags |= IFF_UP;
800
ret = ioctl(sd, SIOCSIFFLAGS, &network);
802
perror("ioctl SIOCSIFFLAGS");
803
returncode = EXIT_FAILURE;
754
seckeyfile = combinepath(keydir, seckeyfile);
755
if (seckeyfile == NULL){
756
perror("combinepath");
810
761
avahi_set_log_function(empty_log);
828
779
config.publish_domain = 0;
830
781
/* Allocate a new server */
831
mc.server=avahi_server_new(avahi_simple_poll_get(mc.simple_poll),
832
&config, NULL, NULL, &error);
782
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
783
&config, NULL, NULL, &error);
834
785
/* Free the configuration data */
835
786
avahi_server_config_free(&config);
837
788
/* Check if creating the server object succeeded */
839
790
fprintf(stderr, "Failed to create server: %s\n",
840
791
avahi_strerror(error));
841
792
returncode = EXIT_FAILURE;
845
796
/* Create the service browser */
846
sb = avahi_s_service_browser_new(mc.server, if_index,
797
sb = avahi_s_service_browser_new(server, if_index,
847
798
AVAHI_PROTO_INET6,
848
799
"_mandos._tcp", NULL, 0,
849
browse_callback, &mc);
800
browse_callback, server);
851
802
fprintf(stderr, "Failed to create service browser: %s\n",
852
avahi_strerror(avahi_server_errno(mc.server)));
803
avahi_strerror(avahi_server_errno(server)));
853
804
returncode = EXIT_FAILURE;