272
116
/* Create new empty GPGME data buffer for the plaintext */
273
117
rc = gpgme_data_new(&dh_plain);
274
if(rc != GPG_ERR_NO_ERROR){
118
if (rc != GPG_ERR_NO_ERROR){
275
119
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
276
120
gpgme_strsource(rc), gpgme_strerror(rc));
277
gpgme_data_release(dh_crypto);
281
/* Decrypt data from the cryptotext data buffer to the plaintext
283
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
284
if(rc != GPG_ERR_NO_ERROR){
124
/* Create new GPGME "context" */
125
rc = gpgme_new(&ctx);
126
if (rc != GPG_ERR_NO_ERROR){
127
fprintf(stderr, "bad gpgme_new: %s: %s\n",
128
gpgme_strsource(rc), gpgme_strerror(rc));
132
/* Decrypt data from the FILE pointer to the plaintext data buffer */
133
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
134
if (rc != GPG_ERR_NO_ERROR){
285
135
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
286
136
gpgme_strsource(rc), gpgme_strerror(rc));
287
plaintext_length = -1;
289
gpgme_decrypt_result_t result;
290
result = gpgme_op_decrypt_result(mc.ctx);
292
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
294
fprintf(stderr, "Unsupported algorithm: %s\n",
295
result->unsupported_algorithm);
296
fprintf(stderr, "Wrong key usage: %u\n",
297
result->wrong_key_usage);
298
if(result->file_name != NULL){
299
fprintf(stderr, "File name: %s\n", result->file_name);
301
gpgme_recipient_t recipient;
302
recipient = result->recipients;
304
while(recipient != NULL){
305
fprintf(stderr, "Public key algorithm: %s\n",
306
gpgme_pubkey_algo_name(recipient->pubkey_algo));
307
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
308
fprintf(stderr, "Secret key available: %s\n",
309
recipient->status == GPG_ERR_NO_SECKEY
311
recipient = recipient->next;
141
fprintf(stderr, "decryption of gpg packet succeeded\n");
145
gpgme_decrypt_result_t result;
146
result = gpgme_op_decrypt_result(ctx);
148
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
150
fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
151
fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
152
if(result->file_name != NULL){
153
fprintf(stderr, "File name: %s\n", result->file_name);
155
gpgme_recipient_t recipient;
156
recipient = result->recipients;
158
while(recipient != NULL){
159
fprintf(stderr, "Public key algorithm: %s\n",
160
gpgme_pubkey_algo_name(recipient->pubkey_algo));
161
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
162
fprintf(stderr, "Secret key available: %s\n",
163
recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
164
recipient = recipient->next;
320
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
170
/* Delete the GPGME FILE pointer cryptotext data buffer */
171
gpgme_data_release(dh_crypto);
323
173
/* Seek back to the beginning of the GPGME plaintext data buffer */
324
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
325
perror("gpgme_data_seek");
326
plaintext_length = -1;
174
gpgme_data_seek(dh_plain, 0, SEEK_SET);
332
plaintext_capacity = incbuffer(plaintext,
333
(size_t)plaintext_length,
335
if(plaintext_capacity == 0){
337
plaintext_length = -1;
178
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
179
*new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
180
if (*new_packet == NULL){
184
new_packet_capacity += BUFFER_SIZE;
341
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
187
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
343
188
/* Print the data, if any */
190
/* If password is empty, then a incorrect error will be printed */
349
194
perror("gpgme_data_read");
350
plaintext_length = -1;
353
plaintext_length += ret;
197
new_packet_length += ret;
357
fprintf(stderr, "Decrypted password is: ");
358
for(ssize_t i = 0; i < plaintext_length; i++){
359
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
361
fprintf(stderr, "\n");
201
fprintf(stderr, "decrypted password is: %s\n", *new_packet);
366
/* Delete the GPGME cryptotext data buffer */
367
gpgme_data_release(dh_crypto);
369
/* Delete the GPGME plaintext data buffer */
204
/* Delete the GPGME plaintext data buffer */
370
205
gpgme_data_release(dh_plain);
371
return plaintext_length;
206
return new_packet_length;
374
static const char * safer_gnutls_strerror(int value){
375
const char *ret = gnutls_strerror(value); /* Spurious warning from
376
-Wunreachable-code */
209
static const char * safer_gnutls_strerror (int value) {
210
const char *ret = gnutls_strerror (value);
378
212
ret = "(unknown)";
382
/* GnuTLS log function callback */
383
static void debuggnutls(__attribute__((unused)) int level,
385
fprintf(stderr, "GnuTLS: %s", string);
216
void debuggnutls(int level, const char* string){
217
fprintf(stderr, "%s", string);
388
static int init_gnutls_global(const char *pubkeyfilename,
389
const char *seckeyfilename){
220
int initgnutls(encrypted_session *es){
393
fprintf(stderr, "Initializing GnuTLS\n");
225
fprintf(stderr, "Initializing gnutls\n");
396
ret = gnutls_global_init();
397
if(ret != GNUTLS_E_SUCCESS){
398
fprintf(stderr, "GnuTLS global_init: %s\n",
399
safer_gnutls_strerror(ret));
229
if ((ret = gnutls_global_init ())
230
!= GNUTLS_E_SUCCESS) {
231
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
404
/* "Use a log level over 10 to enable all debugging options."
407
236
gnutls_global_set_log_level(11);
408
237
gnutls_global_set_log_function(debuggnutls);
411
/* OpenPGP credentials */
412
gnutls_certificate_allocate_credentials(&mc.cred);
413
if(ret != GNUTLS_E_SUCCESS){
414
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
418
safer_gnutls_strerror(ret));
419
gnutls_global_deinit();
241
/* openpgp credentials */
242
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
243
!= GNUTLS_E_SUCCESS) {
244
fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
424
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
425
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
249
fprintf(stderr, "Attempting to use openpgp certificate %s"
250
" and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
429
253
ret = gnutls_certificate_set_openpgp_key_file
430
(mc.cred, pubkeyfilename, seckeyfilename,
431
GNUTLS_OPENPGP_FMT_BASE64);
432
if(ret != GNUTLS_E_SUCCESS){
434
"Error[%d] while reading the OpenPGP key pair ('%s',"
435
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
436
fprintf(stderr, "The GnuTLS error is: %s\n",
437
safer_gnutls_strerror(ret));
441
/* GnuTLS server initialization */
442
ret = gnutls_dh_params_init(&mc.dh_params);
443
if(ret != GNUTLS_E_SUCCESS){
444
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
445
" %s\n", safer_gnutls_strerror(ret));
448
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
449
if(ret != GNUTLS_E_SUCCESS){
450
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
451
safer_gnutls_strerror(ret));
455
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
461
gnutls_certificate_free_credentials(mc.cred);
462
gnutls_global_deinit();
463
gnutls_dh_params_deinit(mc.dh_params);
467
static int init_gnutls_session(gnutls_session_t *session){
469
/* GnuTLS session creation */
470
ret = gnutls_init(session, GNUTLS_SERVER);
471
if(ret != GNUTLS_E_SUCCESS){
472
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
473
safer_gnutls_strerror(ret));
478
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
479
if(ret != GNUTLS_E_SUCCESS){
480
fprintf(stderr, "Syntax error at: %s\n", err);
481
fprintf(stderr, "GnuTLS error: %s\n",
482
safer_gnutls_strerror(ret));
483
gnutls_deinit(*session);
488
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
490
if(ret != GNUTLS_E_SUCCESS){
491
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
492
safer_gnutls_strerror(ret));
493
gnutls_deinit(*session);
254
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
255
if (ret != GNUTLS_E_SUCCESS) {
257
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
258
ret, CERTFILE, KEYFILE);
259
fprintf(stdout, "The Error is: %s\n",
260
safer_gnutls_strerror(ret));
264
//Gnutls server initialization
265
if ((ret = gnutls_dh_params_init (&es->dh_params))
266
!= GNUTLS_E_SUCCESS) {
267
fprintf (stderr, "Error in dh parameter initialization: %s\n",
268
safer_gnutls_strerror(ret));
272
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
273
!= GNUTLS_E_SUCCESS) {
274
fprintf (stderr, "Error in prime generation: %s\n",
275
safer_gnutls_strerror(ret));
279
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
281
// Gnutls session creation
282
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
283
!= GNUTLS_E_SUCCESS){
284
fprintf(stderr, "Error in gnutls session initialization: %s\n",
285
safer_gnutls_strerror(ret));
288
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
289
!= GNUTLS_E_SUCCESS) {
290
fprintf(stderr, "Syntax error at: %s\n", err);
291
fprintf(stderr, "Gnutls error: %s\n",
292
safer_gnutls_strerror(ret));
296
if ((ret = gnutls_credentials_set
297
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
298
!= GNUTLS_E_SUCCESS) {
299
fprintf(stderr, "Error setting a credentials set: %s\n",
300
safer_gnutls_strerror(ret));
497
304
/* ignore client certificate if any. */
498
gnutls_certificate_server_set_request(*session,
305
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
501
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
307
gnutls_dh_set_prime_bits (es->session, DH_BITS);
506
/* Avahi log function callback */
507
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
508
__attribute__((unused)) const char *txt){}
312
void empty_log(AvahiLogLevel level, const char *txt){}
510
/* Called when a Mandos server is found */
511
static int start_mandos_communication(const char *ip, uint16_t port,
512
AvahiIfIndex if_index,
314
int start_mandos_communcation(char *ip, uint16_t port){
517
struct sockaddr_in in;
518
struct sockaddr_in6 in6;
316
struct sockaddr_in6 to;
317
struct in6_addr ip_addr;
318
encrypted_session es;
520
319
char *buffer = NULL;
521
320
char *decrypted_buffer;
522
321
size_t buffer_length = 0;
523
322
size_t buffer_capacity = 0;
524
323
ssize_t decrypted_buffer_size;
527
gnutls_session_t session;
528
int pf; /* Protocol family */
538
fprintf(stderr, "Bad address family: %d\n", af);
542
ret = init_gnutls_session(&session);
325
const char interface[] = "eth0";
548
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
328
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
552
tcp_sd = socket(pf, SOCK_STREAM, 0);
331
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
554
333
perror("socket");
338
fprintf(stderr, "Binding to interface %s\n", interface);
341
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
343
perror("setsockopt bindtodevice");
558
memset(&to, 0, sizeof(to));
560
to.in6.sin6_family = (uint16_t)af;
561
ret = inet_pton(af, ip, &to.in6.sin6_addr);
563
to.in.sin_family = (sa_family_t)af;
564
ret = inet_pton(af, ip, &to.in.sin_addr);
347
memset(&to,0,sizeof(to));
348
to.sin6_family = AF_INET6;
349
ret = inet_pton(AF_INET6, ip, &ip_addr);
567
351
perror("inet_pton");
571
355
fprintf(stderr, "Bad address: %s\n", ip);
575
to.in6.sin6_port = htons(port); /* Spurious warnings from
577
-Wunreachable-code */
579
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
580
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
582
if(if_index == AVAHI_IF_UNSPEC){
583
fprintf(stderr, "An IPv6 link-local address is incomplete"
584
" without a network interface\n");
587
/* Set the network interface number as scope */
588
to.in6.sin6_scope_id = (uint32_t)if_index;
591
to.in.sin_port = htons(port); /* Spurious warnings from
593
-Wunreachable-code */
358
to.sin6_port = htons(port);
359
to.sin6_scope_id = if_nametoindex(interface);
597
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
598
char interface[IF_NAMESIZE];
599
if(if_indextoname((unsigned int)if_index, interface) == NULL){
600
perror("if_indextoname");
602
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
603
ip, interface, port);
606
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
609
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
610
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
613
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
616
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
622
if(strcmp(addrstr, ip) != 0){
623
fprintf(stderr, "Canonical address form: %s\n", addrstr);
362
fprintf(stderr, "Connection to: %s\n", ip);
629
ret = connect(tcp_sd, &to.in6, sizeof(to));
631
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
365
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
634
367
perror("connect");
638
const char *out = mandos_protocol_version;
371
ret = initgnutls (&es);
378
gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
381
fprintf(stderr, "Establishing tls session with %s\n", ip);
385
ret = gnutls_handshake (es.session);
387
if (ret != GNUTLS_E_SUCCESS){
388
fprintf(stderr, "\n*** Handshake failed ***\n");
394
//Retrieve gpg packet that contains the wanted password
397
fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
641
size_t out_size = strlen(out);
642
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
643
out_size - written));
649
written += (size_t)ret;
650
if(written < out_size){
653
if(out == mandos_protocol_version){
401
if (buffer_length + BUFFER_SIZE > buffer_capacity){
402
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
663
fprintf(stderr, "Establishing TLS session with %s\n", ip);
666
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
669
ret = gnutls_handshake(session);
670
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
672
if(ret != GNUTLS_E_SUCCESS){
674
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
681
/* Read OpenPGP packet that contains the wanted password */
684
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
689
buffer_capacity = incbuffer(&buffer, buffer_length,
691
if(buffer_capacity == 0){
407
buffer_capacity += BUFFER_SIZE;
697
sret = gnutls_record_recv(session, buffer+buffer_length,
410
ret = gnutls_record_recv
411
(es.session, buffer+buffer_length, BUFFER_SIZE);
704
417
case GNUTLS_E_INTERRUPTED:
705
418
case GNUTLS_E_AGAIN:
707
420
case GNUTLS_E_REHANDSHAKE:
709
ret = gnutls_handshake(session);
710
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
712
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
421
ret = gnutls_handshake (es.session);
423
fprintf(stderr, "\n*** Handshake failed ***\n");
719
fprintf(stderr, "Unknown error while reading data from"
720
" encrypted session with Mandos server\n");
430
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
722
gnutls_bye(session, GNUTLS_SHUT_RDWR);
432
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
726
buffer_length += (size_t) sret;
436
buffer_length += ret;
731
fprintf(stderr, "Closing TLS session\n");
734
gnutls_bye(session, GNUTLS_SHUT_RDWR);
736
if(buffer_length > 0){
737
decrypted_buffer_size = pgp_packet_decrypt(buffer,
740
if(decrypted_buffer_size >= 0){
742
while(written < (size_t) decrypted_buffer_size){
743
ret = (int)fwrite(decrypted_buffer + written, 1,
744
(size_t)decrypted_buffer_size - written,
746
if(ret == 0 and ferror(stdout)){
748
fprintf(stderr, "Error writing encrypted data: %s\n",
754
written += (size_t)ret;
440
if (buffer_length > 0){
441
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
442
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
756
443
free(decrypted_buffer);
764
/* Shutdown procedure */
452
fprintf(stderr, "Closing tls session\n");
768
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
772
gnutls_deinit(session);
456
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
459
gnutls_deinit (es.session);
460
gnutls_certificate_free_credentials (es.cred);
461
gnutls_global_deinit ();
776
static void resolve_callback(AvahiSServiceResolver *r,
777
AvahiIfIndex interface,
779
AvahiResolverEvent event,
783
const char *host_name,
784
const AvahiAddress *address,
786
AVAHI_GCC_UNUSED AvahiStringList *txt,
787
AVAHI_GCC_UNUSED AvahiLookupResultFlags
789
__attribute__((unused)) void* userdata){
792
/* Called whenever a service has been resolved successfully or
797
case AVAHI_RESOLVER_FAILURE:
798
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
799
" of type '%s' in domain '%s': %s\n", name, type, domain,
800
avahi_strerror(avahi_server_errno(mc.server)));
803
case AVAHI_RESOLVER_FOUND:
805
char ip[AVAHI_ADDRESS_STR_MAX];
806
avahi_address_snprint(ip, sizeof(ip), address);
808
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
809
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
810
ip, (intmax_t)interface, port);
812
int ret = start_mandos_communication(ip, port, interface,
813
avahi_proto_to_af(proto));
815
avahi_simple_poll_quit(mc.simple_poll);
819
avahi_s_service_resolver_free(r);
822
static void browse_callback(AvahiSServiceBrowser *b,
823
AvahiIfIndex interface,
824
AvahiProtocol protocol,
825
AvahiBrowserEvent event,
829
AVAHI_GCC_UNUSED AvahiLookupResultFlags
831
__attribute__((unused)) void* userdata){
834
/* Called whenever a new services becomes available on the LAN or
835
is removed from the LAN */
839
case AVAHI_BROWSER_FAILURE:
841
fprintf(stderr, "(Avahi browser) %s\n",
842
avahi_strerror(avahi_server_errno(mc.server)));
843
avahi_simple_poll_quit(mc.simple_poll);
846
case AVAHI_BROWSER_NEW:
847
/* We ignore the returned Avahi resolver object. In the callback
848
function we free it. If the Avahi server is terminated before
849
the callback function is called the Avahi server will free the
852
if(!(avahi_s_service_resolver_new(mc.server, interface,
853
protocol, name, type, domain,
854
AVAHI_PROTO_INET6, 0,
855
resolve_callback, NULL)))
856
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
857
name, avahi_strerror(avahi_server_errno(mc.server)));
860
case AVAHI_BROWSER_REMOVE:
863
case AVAHI_BROWSER_ALL_FOR_NOW:
864
case AVAHI_BROWSER_CACHE_EXHAUSTED:
866
fprintf(stderr, "No Mandos server found, still searching...\n");
872
static void handle_sigterm(__attribute__((unused)) int sig){
873
int old_errno = errno;
874
avahi_simple_poll_quit(mc.simple_poll);
878
int main(int argc, char *argv[]){
879
AvahiSServiceBrowser *sb = NULL;
884
int exitcode = EXIT_SUCCESS;
885
const char *interface = "eth0";
886
struct ifreq network;
890
char *connect_to = NULL;
891
char tempdir[] = "/tmp/mandosXXXXXX";
892
bool tempdir_created = false;
893
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
894
const char *seckey = PATHDIR "/" SECKEY;
895
const char *pubkey = PATHDIR "/" PUBKEY;
897
bool gnutls_initialized = false;
898
bool gpgme_initialized = false;
901
struct sigaction old_sigterm_action;
902
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
904
/* Initialize mandos context */
905
mc = (mandos_context){ .simple_poll = NULL, .server = NULL,
906
.dh_bits = 1024, .priority = "SECURE256"
907
":!CTYPE-X.509:+CTYPE-OPENPGP" };
910
struct argp_option options[] = {
911
{ .name = "debug", .key = 128,
912
.doc = "Debug mode", .group = 3 },
913
{ .name = "connect", .key = 'c',
914
.arg = "ADDRESS:PORT",
915
.doc = "Connect directly to a specific Mandos server",
917
{ .name = "interface", .key = 'i',
919
.doc = "Network interface that will be used to search for"
922
{ .name = "seckey", .key = 's',
924
.doc = "OpenPGP secret key file base name",
926
{ .name = "pubkey", .key = 'p',
928
.doc = "OpenPGP public key file base name",
930
{ .name = "dh-bits", .key = 129,
932
.doc = "Bit length of the prime number used in the"
933
" Diffie-Hellman key exchange",
935
{ .name = "priority", .key = 130,
937
.doc = "GnuTLS priority string for the TLS handshake",
939
{ .name = "delay", .key = 131,
941
.doc = "Maximum delay to wait for interface startup",
946
error_t parse_opt(int key, char *arg,
947
struct argp_state *state){
949
case 128: /* --debug */
952
case 'c': /* --connect */
955
case 'i': /* --interface */
958
case 's': /* --seckey */
961
case 'p': /* --pubkey */
964
case 129: /* --dh-bits */
965
ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
966
if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
967
or arg[numchars] != '\0'){
968
fprintf(stderr, "Bad number of DH bits\n");
971
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
973
case 130: /* --priority */
976
case 131: /* --delay */
977
ret = sscanf(arg, "%lf%n", &delay, &numchars);
978
if(ret < 1 or arg[numchars] != '\0'){
979
fprintf(stderr, "Bad delay\n");
988
return ARGP_ERR_UNKNOWN;
993
struct argp argp = { .options = options, .parser = parse_opt,
995
.doc = "Mandos client -- Get and decrypt"
996
" passwords from a Mandos server" };
997
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
998
if(ret == ARGP_ERR_UNKNOWN){
999
fprintf(stderr, "Unknown error while parsing arguments\n");
1000
exitcode = EXIT_FAILURE;
1005
/* If the interface is down, bring it up */
1006
if(interface[0] != '\0'){
1008
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1009
messages to mess up the prompt */
1010
ret = klogctl(8, NULL, 5);
1011
bool restore_loglevel = true;
1013
restore_loglevel = false;
1018
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1021
exitcode = EXIT_FAILURE;
1023
if(restore_loglevel){
1024
ret = klogctl(7, NULL, 0);
1032
strcpy(network.ifr_name, interface);
1033
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1035
perror("ioctl SIOCGIFFLAGS");
1037
if(restore_loglevel){
1038
ret = klogctl(7, NULL, 0);
1044
exitcode = EXIT_FAILURE;
1047
if((network.ifr_flags & IFF_UP) == 0){
1048
network.ifr_flags |= IFF_UP;
1049
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1051
perror("ioctl SIOCSIFFLAGS");
1052
exitcode = EXIT_FAILURE;
1054
if(restore_loglevel){
1055
ret = klogctl(7, NULL, 0);
1064
/* sleep checking until interface is running */
1065
for(int i=0; i < delay * 4; i++){
1066
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1068
perror("ioctl SIOCGIFFLAGS");
1069
} else if(network.ifr_flags & IFF_RUNNING){
1072
struct timespec sleeptime = { .tv_nsec = 250000000 };
1073
ret = nanosleep(&sleeptime, NULL);
1074
if(ret == -1 and errno != EINTR){
1075
perror("nanosleep");
1078
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1083
if(restore_loglevel){
1084
/* Restores kernel loglevel to default */
1085
ret = klogctl(7, NULL, 0);
1107
ret = init_gnutls_global(pubkey, seckey);
1109
fprintf(stderr, "init_gnutls_global failed\n");
1110
exitcode = EXIT_FAILURE;
1113
gnutls_initialized = true;
1116
if(mkdtemp(tempdir) == NULL){
1120
tempdir_created = true;
1122
if(not init_gpgme(pubkey, seckey, tempdir)){
1123
fprintf(stderr, "init_gpgme failed\n");
1124
exitcode = EXIT_FAILURE;
1127
gpgme_initialized = true;
1130
if(interface[0] != '\0'){
1131
if_index = (AvahiIfIndex) if_nametoindex(interface);
1133
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1134
exitcode = EXIT_FAILURE;
1139
if(connect_to != NULL){
1140
/* Connect directly, do not use Zeroconf */
1141
/* (Mainly meant for debugging) */
1142
char *address = strrchr(connect_to, ':');
1143
if(address == NULL){
1144
fprintf(stderr, "No colon in address\n");
1145
exitcode = EXIT_FAILURE;
1149
ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
1150
if(ret < 1 or tmpmax != (uint16_t)tmpmax
1151
or address[numchars+1] != '\0'){
1152
fprintf(stderr, "Bad port number\n");
1153
exitcode = EXIT_FAILURE;
1156
port = (uint16_t)tmpmax;
1158
address = connect_to;
1159
/* Colon in address indicates IPv6 */
1161
if(strchr(address, ':') != NULL){
1166
ret = start_mandos_communication(address, port, if_index,
1169
exitcode = EXIT_FAILURE;
1171
exitcode = EXIT_SUCCESS;
1177
avahi_set_log_function(empty_log);
1180
/* Initialize the pseudo-RNG for Avahi */
1181
srand((unsigned int) time(NULL));
1183
/* Allocate main Avahi loop object */
1184
mc.simple_poll = avahi_simple_poll_new();
1185
if(mc.simple_poll == NULL){
1186
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1187
exitcode = EXIT_FAILURE;
465
static AvahiSimplePoll *simple_poll = NULL;
466
static AvahiServer *server = NULL;
468
static void resolve_callback(
469
AvahiSServiceResolver *r,
470
AVAHI_GCC_UNUSED AvahiIfIndex interface,
471
AVAHI_GCC_UNUSED AvahiProtocol protocol,
472
AvahiResolverEvent event,
476
const char *host_name,
477
const AvahiAddress *address,
479
AvahiStringList *txt,
480
AvahiLookupResultFlags flags,
481
AVAHI_GCC_UNUSED void* userdata) {
485
/* Called whenever a service has been resolved successfully or timed out */
488
case AVAHI_RESOLVER_FAILURE:
489
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_server_errno(server)));
492
case AVAHI_RESOLVER_FOUND: {
493
char ip[AVAHI_ADDRESS_STR_MAX];
494
avahi_address_snprint(ip, sizeof(ip), address);
496
fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
498
int ret = start_mandos_communcation(ip, port);
506
avahi_s_service_resolver_free(r);
509
static void browse_callback(
510
AvahiSServiceBrowser *b,
511
AvahiIfIndex interface,
512
AvahiProtocol protocol,
513
AvahiBrowserEvent event,
517
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
520
AvahiServer *s = userdata;
523
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
527
case AVAHI_BROWSER_FAILURE:
529
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
530
avahi_simple_poll_quit(simple_poll);
533
case AVAHI_BROWSER_NEW:
534
/* We ignore the returned resolver object. In the callback
535
function we free it. If the server is terminated before
536
the callback function is called the server will free
537
the resolver for us. */
539
if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
540
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
544
case AVAHI_BROWSER_REMOVE:
547
case AVAHI_BROWSER_ALL_FOR_NOW:
548
case AVAHI_BROWSER_CACHE_EXHAUSTED:
553
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1192
554
AvahiServerConfig config;
1193
/* Do not publish any local Zeroconf records */
555
AvahiSServiceBrowser *sb = NULL;
556
const char db[] = "--debug";
559
int returncode = EXIT_SUCCESS;
560
char *basename = rindex(argv[0], '/');
561
if(basename == NULL){
567
char *program_name = malloc(strlen(basename) + sizeof(db));
569
if (program_name == NULL){
574
program_name[0] = '\0';
576
for (int i = 1; i < argc; i++){
577
if (not strncmp(argv[i], db, 5)){
578
strcat(strcat(strcat(program_name, db ), "="), basename);
579
if(not strcmp(argv[i], db) or not strcmp(argv[i], program_name)){
587
avahi_set_log_function(empty_log);
590
/* Initialize the psuedo-RNG */
593
/* Allocate main loop object */
594
if (!(simple_poll = avahi_simple_poll_new())) {
595
fprintf(stderr, "Failed to create simple poll object.\n");
600
/* Do not publish any local records */
1194
601
avahi_server_config_init(&config);
1195
602
config.publish_hinfo = 0;
1196
603
config.publish_addresses = 0;
1197
604
config.publish_workstation = 0;
1198
605
config.publish_domain = 0;
1200
607
/* Allocate a new server */
1201
mc.server = avahi_server_new(avahi_simple_poll_get
1202
(mc.simple_poll), &config, NULL,
1205
/* Free the Avahi configuration data */
608
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
610
/* Free the configuration data */
1206
611
avahi_server_config_free(&config);
1209
/* Check if creating the Avahi server object succeeded */
1210
if(mc.server == NULL){
1211
fprintf(stderr, "Failed to create Avahi server: %s\n",
1212
avahi_strerror(error));
1213
exitcode = EXIT_FAILURE;
1217
/* Create the Avahi service browser */
1218
sb = avahi_s_service_browser_new(mc.server, if_index,
1219
AVAHI_PROTO_INET6, "_mandos._tcp",
1220
NULL, 0, browse_callback, NULL);
1222
fprintf(stderr, "Failed to create service browser: %s\n",
1223
avahi_strerror(avahi_server_errno(mc.server)));
1224
exitcode = EXIT_FAILURE;
1228
sigemptyset(&sigterm_action.sa_mask);
1229
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1231
perror("sigaddset");
1232
exitcode = EXIT_FAILURE;
1235
ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
1237
perror("sigaction");
1238
exitcode = EXIT_FAILURE;
1242
/* Run the main loop */
1245
fprintf(stderr, "Starting Avahi loop search\n");
1248
avahi_simple_poll_loop(mc.simple_poll);
1253
fprintf(stderr, "%s exiting\n", argv[0]);
1256
/* Cleanup things */
1258
avahi_s_service_browser_free(sb);
1260
if(mc.server != NULL)
1261
avahi_server_free(mc.server);
1263
if(mc.simple_poll != NULL)
1264
avahi_simple_poll_free(mc.simple_poll);
1266
if(gnutls_initialized){
1267
gnutls_certificate_free_credentials(mc.cred);
1268
gnutls_global_deinit();
1269
gnutls_dh_params_deinit(mc.dh_params);
1272
if(gpgme_initialized){
1273
gpgme_release(mc.ctx);
1276
/* Removes the temp directory used by GPGME */
1277
if(tempdir_created){
1279
struct dirent *direntry;
1280
d = opendir(tempdir);
1282
if(errno != ENOENT){
1287
direntry = readdir(d);
1288
if(direntry == NULL){
1291
/* Skip "." and ".." */
1292
if(direntry->d_name[0] == '.'
1293
and (direntry->d_name[1] == '\0'
1294
or (direntry->d_name[1] == '.'
1295
and direntry->d_name[2] == '\0'))){
1298
char *fullname = NULL;
1299
ret = asprintf(&fullname, "%s/%s", tempdir,
1305
ret = remove(fullname);
1307
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1314
ret = rmdir(tempdir);
1315
if(ret == -1 and errno != ENOENT){
613
/* Check if creating the server object succeeded */
615
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
616
returncode = EXIT_FAILURE;
620
/* Create the service browser */
621
if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
622
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
623
returncode = EXIT_FAILURE;
627
/* Run the main loop */
630
fprintf(stderr, "Starting avahi loop search\n");
633
avahi_simple_poll_loop(simple_poll);
638
fprintf(stderr, "%s exiting\n", argv[0]);
643
avahi_s_service_browser_free(sb);
646
avahi_server_free(server);
649
avahi_simple_poll_free(simple_poll);