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