123
281
/* Create new empty GPGME data buffer for the plaintext */
124
282
rc = gpgme_data_new(&dh_plain);
125
if (rc != GPG_ERR_NO_ERROR){
283
if(rc != GPG_ERR_NO_ERROR){
126
284
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
127
285
gpgme_strsource(rc), gpgme_strerror(rc));
131
/* Create new GPGME "context" */
132
rc = gpgme_new(&ctx);
133
if (rc != GPG_ERR_NO_ERROR){
134
fprintf(stderr, "bad gpgme_new: %s: %s\n",
135
gpgme_strsource(rc), gpgme_strerror(rc));
139
/* Decrypt data from the FILE pointer to the plaintext data buffer */
140
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
141
if (rc != GPG_ERR_NO_ERROR){
286
gpgme_data_release(dh_crypto);
290
/* Decrypt data from the cryptotext data buffer to the plaintext
292
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
293
if(rc != GPG_ERR_NO_ERROR){
142
294
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
143
295
gpgme_strsource(rc), gpgme_strerror(rc));
296
plaintext_length = -1;
298
gpgme_decrypt_result_t result;
299
result = gpgme_op_decrypt_result(mc.ctx);
301
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
303
fprintf(stderr, "Unsupported algorithm: %s\n",
304
result->unsupported_algorithm);
305
fprintf(stderr, "Wrong key usage: %u\n",
306
result->wrong_key_usage);
307
if(result->file_name != NULL){
308
fprintf(stderr, "File name: %s\n", result->file_name);
310
gpgme_recipient_t recipient;
311
recipient = result->recipients;
312
while(recipient != NULL){
313
fprintf(stderr, "Public key algorithm: %s\n",
314
gpgme_pubkey_algo_name(recipient->pubkey_algo));
315
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
316
fprintf(stderr, "Secret key available: %s\n",
317
recipient->status == GPG_ERR_NO_SECKEY
319
recipient = recipient->next;
147
/* gpgme_decrypt_result_t result; */
148
/* result = gpgme_op_decrypt_result(ctx); */
149
/* fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm); */
150
/* fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage); */
151
/* if(result->file_name != NULL){ */
152
/* fprintf(stderr, "File name: %s\n", result->file_name); */
154
/* gpgme_recipient_t recipient; */
155
/* recipient = result->recipients; */
157
/* while(recipient != NULL){ */
158
/* fprintf(stderr, "Public key algorithm: %s\n", */
159
/* gpgme_pubkey_algo_name(recipient->pubkey_algo)); */
160
/* fprintf(stderr, "Key ID: %s\n", recipient->keyid); */
161
/* fprintf(stderr, "Secret key available: %s\n", */
162
/* recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes"); */
163
/* recipient = recipient->next; */
167
/* Delete the GPGME FILE pointer cryptotext data buffer */
168
gpgme_data_release(dh_crypto);
327
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
170
330
/* Seek back to the beginning of the GPGME plaintext data buffer */
171
gpgme_data_seek(dh_plain, 0, SEEK_SET);
331
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
332
perror("gpgme_data_seek");
333
plaintext_length = -1;
175
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
176
*new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
177
if (*new_packet == NULL){
181
new_packet_capacity += BUFFER_SIZE;
339
plaintext_capacity = incbuffer(plaintext,
340
(size_t)plaintext_length,
342
if(plaintext_capacity == 0){
344
plaintext_length = -1;
184
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
348
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
185
350
/* Print the data, if any */
187
/* If password is empty, then a incorrect error will be printed */
191
356
perror("gpgme_data_read");
194
new_packet_length += ret;
197
/* Delete the GPGME plaintext data buffer */
357
plaintext_length = -1;
360
plaintext_length += ret;
364
fprintf(stderr, "Decrypted password is: ");
365
for(ssize_t i = 0; i < plaintext_length; i++){
366
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
368
fprintf(stderr, "\n");
373
/* Delete the GPGME cryptotext data buffer */
374
gpgme_data_release(dh_crypto);
376
/* Delete the GPGME plaintext data buffer */
198
377
gpgme_data_release(dh_plain);
199
return new_packet_length;
378
return plaintext_length;
202
static const char * safer_gnutls_strerror (int value) {
203
const char *ret = gnutls_strerror (value);
381
static const char * safer_gnutls_strerror(int value){
382
const char *ret = gnutls_strerror(value); /* Spurious warning from
383
-Wunreachable-code */
205
385
ret = "(unknown)";
209
void debuggnutls(int level, const char* string){
210
fprintf(stderr, "%s", string);
389
/* GnuTLS log function callback */
390
static void debuggnutls(__attribute__((unused)) int level,
392
fprintf(stderr, "GnuTLS: %s", string);
213
int initgnutls(encrypted_session *es){
395
static int init_gnutls_global(const char *pubkeyfilename,
396
const char *seckeyfilename){
217
if ((ret = gnutls_global_init ())
218
!= GNUTLS_E_SUCCESS) {
219
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
223
/* Uncomment to enable full debuggin on the gnutls library */
224
/* gnutls_global_set_log_level(11); */
225
/* gnutls_global_set_log_function(debuggnutls); */
228
/* openpgp credentials */
229
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
230
!= GNUTLS_E_SUCCESS) {
231
fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
400
fprintf(stderr, "Initializing GnuTLS\n");
403
ret = gnutls_global_init();
404
if(ret != GNUTLS_E_SUCCESS){
405
fprintf(stderr, "GnuTLS global_init: %s\n",
406
safer_gnutls_strerror(ret));
411
/* "Use a log level over 10 to enable all debugging options."
414
gnutls_global_set_log_level(11);
415
gnutls_global_set_log_function(debuggnutls);
418
/* OpenPGP credentials */
419
gnutls_certificate_allocate_credentials(&mc.cred);
420
if(ret != GNUTLS_E_SUCCESS){
421
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
425
safer_gnutls_strerror(ret));
426
gnutls_global_deinit();
431
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
432
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
235
436
ret = gnutls_certificate_set_openpgp_key_file
236
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
237
if (ret != GNUTLS_E_SUCCESS) {
239
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
240
ret, CERTFILE, KEYFILE);
241
fprintf(stdout, "The Error is: %s\n",
242
safer_gnutls_strerror(ret));
246
//Gnutls server initialization
247
if ((ret = gnutls_dh_params_init (&es->dh_params))
248
!= GNUTLS_E_SUCCESS) {
249
fprintf (stderr, "Error in dh parameter initialization: %s\n",
250
safer_gnutls_strerror(ret));
254
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
255
!= GNUTLS_E_SUCCESS) {
256
fprintf (stderr, "Error in prime generation: %s\n",
257
safer_gnutls_strerror(ret));
261
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
263
// Gnutls session creation
264
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
265
!= GNUTLS_E_SUCCESS){
266
fprintf(stderr, "Error in gnutls session initialization: %s\n",
267
safer_gnutls_strerror(ret));
270
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
271
!= GNUTLS_E_SUCCESS) {
272
fprintf(stderr, "Syntax error at: %s\n", err);
273
fprintf(stderr, "Gnutls error: %s\n",
274
safer_gnutls_strerror(ret));
278
if ((ret = gnutls_credentials_set
279
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
280
!= GNUTLS_E_SUCCESS) {
281
fprintf(stderr, "Error setting a credentials set: %s\n",
282
safer_gnutls_strerror(ret));
437
(mc.cred, pubkeyfilename, seckeyfilename,
438
GNUTLS_OPENPGP_FMT_BASE64);
439
if(ret != GNUTLS_E_SUCCESS){
441
"Error[%d] while reading the OpenPGP key pair ('%s',"
442
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
443
fprintf(stderr, "The GnuTLS error is: %s\n",
444
safer_gnutls_strerror(ret));
448
/* GnuTLS server initialization */
449
ret = gnutls_dh_params_init(&mc.dh_params);
450
if(ret != GNUTLS_E_SUCCESS){
451
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
452
" %s\n", safer_gnutls_strerror(ret));
455
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
456
if(ret != GNUTLS_E_SUCCESS){
457
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
458
safer_gnutls_strerror(ret));
462
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
468
gnutls_certificate_free_credentials(mc.cred);
469
gnutls_global_deinit();
470
gnutls_dh_params_deinit(mc.dh_params);
474
static int init_gnutls_session(gnutls_session_t *session){
476
/* GnuTLS session creation */
477
ret = gnutls_init(session, GNUTLS_SERVER);
478
if(ret != GNUTLS_E_SUCCESS){
479
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
480
safer_gnutls_strerror(ret));
485
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
486
if(ret != GNUTLS_E_SUCCESS){
487
fprintf(stderr, "Syntax error at: %s\n", err);
488
fprintf(stderr, "GnuTLS error: %s\n",
489
safer_gnutls_strerror(ret));
490
gnutls_deinit(*session);
495
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
497
if(ret != GNUTLS_E_SUCCESS){
498
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
499
safer_gnutls_strerror(ret));
500
gnutls_deinit(*session);
286
504
/* ignore client certificate if any. */
287
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
505
gnutls_certificate_server_set_request(*session,
289
gnutls_dh_set_prime_bits (es->session, DH_BITS);
508
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
294
void empty_log(AvahiLogLevel level, const char *txt){}
513
/* Avahi log function callback */
514
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
515
__attribute__((unused)) const char *txt){}
296
int start_mandos_communcation(char *ip, uint16_t port){
517
/* Called when a Mandos server is found */
518
static int start_mandos_communication(const char *ip, uint16_t port,
519
AvahiIfIndex if_index,
298
struct sockaddr_in6 to;
299
struct in6_addr ip_addr;
300
encrypted_session es;
524
struct sockaddr_in in;
525
struct sockaddr_in6 in6;
301
527
char *buffer = NULL;
302
528
char *decrypted_buffer;
303
529
size_t buffer_length = 0;
304
530
size_t buffer_capacity = 0;
305
531
ssize_t decrypted_buffer_size;
309
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
534
gnutls_session_t session;
535
int pf; /* Protocol family */
545
fprintf(stderr, "Bad address family: %d\n", af);
549
ret = init_gnutls_session(&session);
555
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
559
tcp_sd = socket(pf, SOCK_STREAM, 0);
311
561
perror("socket");
315
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
317
perror("setsockopt bindtodevice");
565
memset(&to, 0, sizeof(to));
567
to.in6.sin6_family = (sa_family_t)af;
568
ret = inet_pton(af, ip, &to.in6.sin6_addr);
570
to.in.sin_family = (sa_family_t)af;
571
ret = inet_pton(af, ip, &to.in.sin_addr);
321
memset(&to,0,sizeof(to));
322
to.sin6_family = AF_INET6;
323
ret = inet_pton(AF_INET6, ip, &ip_addr);
325
574
perror("inet_pton");
329
578
fprintf(stderr, "Bad address: %s\n", ip);
332
to.sin6_port = htons(port);
333
to.sin6_scope_id = if_nametoindex("eth0");
335
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
582
to.in6.sin6_port = htons(port); /* Spurious warnings from
584
-Wunreachable-code */
586
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
587
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
589
if(if_index == AVAHI_IF_UNSPEC){
590
fprintf(stderr, "An IPv6 link-local address is incomplete"
591
" without a network interface\n");
594
/* Set the network interface number as scope */
595
to.in6.sin6_scope_id = (uint32_t)if_index;
598
to.in.sin_port = htons(port); /* Spurious warnings from
600
-Wunreachable-code */
604
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
605
char interface[IF_NAMESIZE];
606
if(if_indextoname((unsigned int)if_index, interface) == NULL){
607
perror("if_indextoname");
609
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
610
ip, interface, port);
613
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
616
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
617
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
620
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
623
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
629
if(strcmp(addrstr, ip) != 0){
630
fprintf(stderr, "Canonical address form: %s\n", addrstr);
636
ret = connect(tcp_sd, &to.in6, sizeof(to));
638
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
337
641
perror("connect");
341
ret = initgnutls (&es);
348
gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
350
ret = gnutls_handshake (es.session);
352
if (ret != GNUTLS_E_SUCCESS){
353
fprintf(stderr, "\n*** Handshake failed ***\n");
645
const char *out = mandos_protocol_version;
361
if (buffer_length + BUFFER_SIZE > buffer_capacity){
362
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
648
size_t out_size = strlen(out);
649
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
650
out_size - written));
656
written += (size_t)ret;
657
if(written < out_size){
660
if(out == mandos_protocol_version){
367
buffer_capacity += BUFFER_SIZE;
670
fprintf(stderr, "Establishing TLS session with %s\n", ip);
673
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
676
ret = gnutls_handshake(session);
677
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
679
if(ret != GNUTLS_E_SUCCESS){
681
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
688
/* Read OpenPGP packet that contains the wanted password */
691
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
696
buffer_capacity = incbuffer(&buffer, buffer_length,
698
if(buffer_capacity == 0){
370
ret = gnutls_record_recv
371
(es.session, buffer+buffer_length, BUFFER_SIZE);
704
sret = gnutls_record_recv(session, buffer+buffer_length,
377
711
case GNUTLS_E_INTERRUPTED:
378
712
case GNUTLS_E_AGAIN:
380
714
case GNUTLS_E_REHANDSHAKE:
381
ret = gnutls_handshake (es.session);
383
fprintf(stderr, "\n*** Handshake failed ***\n");
716
ret = gnutls_handshake(session);
717
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
719
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
390
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
726
fprintf(stderr, "Unknown error while reading data from"
727
" encrypted session with Mandos server\n");
392
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
729
gnutls_bye(session, GNUTLS_SHUT_RDWR);
396
buffer_length += ret;
733
buffer_length += (size_t) sret;
400
if (buffer_length > 0){
401
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
404
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
738
fprintf(stderr, "Closing TLS session\n");
741
gnutls_bye(session, GNUTLS_SHUT_RDWR);
743
if(buffer_length > 0){
744
decrypted_buffer_size = pgp_packet_decrypt(buffer,
747
if(decrypted_buffer_size >= 0){
749
while(written < (size_t) decrypted_buffer_size){
750
ret = (int)fwrite(decrypted_buffer + written, 1,
751
(size_t)decrypted_buffer_size - written,
753
if(ret == 0 and ferror(stdout)){
755
fprintf(stderr, "Error writing encrypted data: %s\n",
761
written += (size_t)ret;
405
763
free(decrypted_buffer);
771
/* Shutdown procedure */
412
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
415
gnutls_deinit (es.session);
416
gnutls_certificate_free_credentials (es.cred);
417
gnutls_global_deinit ();
775
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
779
gnutls_deinit(session);
421
static AvahiSimplePoll *simple_poll = NULL;
422
static AvahiServer *server = NULL;
424
static void resolve_callback(
425
AvahiSServiceResolver *r,
426
AVAHI_GCC_UNUSED AvahiIfIndex interface,
427
AVAHI_GCC_UNUSED AvahiProtocol protocol,
428
AvahiResolverEvent event,
432
const char *host_name,
433
const AvahiAddress *address,
435
AvahiStringList *txt,
436
AvahiLookupResultFlags flags,
437
AVAHI_GCC_UNUSED void* userdata) {
441
/* Called whenever a service has been resolved successfully or timed out */
444
case AVAHI_RESOLVER_FAILURE:
445
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)));
448
case AVAHI_RESOLVER_FOUND: {
449
char ip[AVAHI_ADDRESS_STR_MAX];
450
avahi_address_snprint(ip, sizeof(ip), address);
451
int ret = start_mandos_communcation(ip, port);
459
avahi_s_service_resolver_free(r);
462
static void browse_callback(
463
AvahiSServiceBrowser *b,
464
AvahiIfIndex interface,
465
AvahiProtocol protocol,
466
AvahiBrowserEvent event,
470
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
473
AvahiServer *s = userdata;
476
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
480
case AVAHI_BROWSER_FAILURE:
482
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
483
avahi_simple_poll_quit(simple_poll);
486
case AVAHI_BROWSER_NEW:
487
/* We ignore the returned resolver object. In the callback
488
function we free it. If the server is terminated before
489
the callback function is called the server will free
490
the resolver for us. */
492
if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
493
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
497
case AVAHI_BROWSER_REMOVE:
500
case AVAHI_BROWSER_ALL_FOR_NOW:
501
case AVAHI_BROWSER_CACHE_EXHAUSTED:
506
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
783
static void resolve_callback(AvahiSServiceResolver *r,
784
AvahiIfIndex interface,
786
AvahiResolverEvent event,
790
const char *host_name,
791
const AvahiAddress *address,
793
AVAHI_GCC_UNUSED AvahiStringList *txt,
794
AVAHI_GCC_UNUSED AvahiLookupResultFlags
796
AVAHI_GCC_UNUSED void* userdata){
799
/* Called whenever a service has been resolved successfully or
804
case AVAHI_RESOLVER_FAILURE:
805
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
806
" of type '%s' in domain '%s': %s\n", name, type, domain,
807
avahi_strerror(avahi_server_errno(mc.server)));
810
case AVAHI_RESOLVER_FOUND:
812
char ip[AVAHI_ADDRESS_STR_MAX];
813
avahi_address_snprint(ip, sizeof(ip), address);
815
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
816
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
817
ip, (intmax_t)interface, port);
819
int ret = start_mandos_communication(ip, port, interface,
820
avahi_proto_to_af(proto));
822
avahi_simple_poll_quit(mc.simple_poll);
826
avahi_s_service_resolver_free(r);
829
static void browse_callback(AvahiSServiceBrowser *b,
830
AvahiIfIndex interface,
831
AvahiProtocol protocol,
832
AvahiBrowserEvent event,
836
AVAHI_GCC_UNUSED AvahiLookupResultFlags
838
AVAHI_GCC_UNUSED void* userdata){
841
/* Called whenever a new services becomes available on the LAN or
842
is removed from the LAN */
846
case AVAHI_BROWSER_FAILURE:
848
fprintf(stderr, "(Avahi browser) %s\n",
849
avahi_strerror(avahi_server_errno(mc.server)));
850
avahi_simple_poll_quit(mc.simple_poll);
853
case AVAHI_BROWSER_NEW:
854
/* We ignore the returned Avahi resolver object. In the callback
855
function we free it. If the Avahi server is terminated before
856
the callback function is called the Avahi server will free the
859
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
860
name, type, domain, protocol, 0,
861
resolve_callback, NULL) == NULL)
862
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
863
name, avahi_strerror(avahi_server_errno(mc.server)));
866
case AVAHI_BROWSER_REMOVE:
869
case AVAHI_BROWSER_ALL_FOR_NOW:
870
case AVAHI_BROWSER_CACHE_EXHAUSTED:
872
fprintf(stderr, "No Mandos server found, still searching...\n");
878
sig_atomic_t quit_now = 0;
880
/* stop main loop after sigterm has been called */
881
static void handle_sigterm(__attribute__((unused)) int sig){
886
int old_errno = errno;
887
if(mc.simple_poll != NULL){
888
avahi_simple_poll_quit(mc.simple_poll);
893
int main(int argc, char *argv[]){
894
AvahiSServiceBrowser *sb = NULL;
899
int exitcode = EXIT_SUCCESS;
900
const char *interface = "eth0";
901
struct ifreq network;
905
char *connect_to = NULL;
906
char tempdir[] = "/tmp/mandosXXXXXX";
907
bool tempdir_created = false;
908
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
909
const char *seckey = PATHDIR "/" SECKEY;
910
const char *pubkey = PATHDIR "/" PUBKEY;
912
bool gnutls_initialized = false;
913
bool gpgme_initialized = false;
916
struct sigaction old_sigterm_action;
917
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
920
struct argp_option options[] = {
921
{ .name = "debug", .key = 128,
922
.doc = "Debug mode", .group = 3 },
923
{ .name = "connect", .key = 'c',
924
.arg = "ADDRESS:PORT",
925
.doc = "Connect directly to a specific Mandos server",
927
{ .name = "interface", .key = 'i',
929
.doc = "Network interface that will be used to search for"
932
{ .name = "seckey", .key = 's',
934
.doc = "OpenPGP secret key file base name",
936
{ .name = "pubkey", .key = 'p',
938
.doc = "OpenPGP public key file base name",
940
{ .name = "dh-bits", .key = 129,
942
.doc = "Bit length of the prime number used in the"
943
" Diffie-Hellman key exchange",
945
{ .name = "priority", .key = 130,
947
.doc = "GnuTLS priority string for the TLS handshake",
949
{ .name = "delay", .key = 131,
951
.doc = "Maximum delay to wait for interface startup",
956
error_t parse_opt(int key, char *arg,
957
struct argp_state *state){
959
case 128: /* --debug */
962
case 'c': /* --connect */
965
case 'i': /* --interface */
968
case 's': /* --seckey */
971
case 'p': /* --pubkey */
974
case 129: /* --dh-bits */
976
tmpmax = strtoimax(arg, &tmp, 10);
977
if(errno != 0 or tmp == arg or *tmp != '\0'
978
or tmpmax != (typeof(mc.dh_bits))tmpmax){
979
fprintf(stderr, "Bad number of DH bits\n");
982
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
984
case 130: /* --priority */
987
case 131: /* --delay */
989
delay = strtof(arg, &tmp);
990
if(errno != 0 or tmp == arg or *tmp != '\0'){
991
fprintf(stderr, "Bad delay\n");
1000
return ARGP_ERR_UNKNOWN;
1005
struct argp argp = { .options = options, .parser = parse_opt,
1007
.doc = "Mandos client -- Get and decrypt"
1008
" passwords from a Mandos server" };
1009
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
1010
if(ret == ARGP_ERR_UNKNOWN){
1011
fprintf(stderr, "Unknown error while parsing arguments\n");
1012
exitcode = EXIT_FAILURE;
1018
avahi_set_log_function(empty_log);
1021
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1022
from the signal handler */
1023
/* Initialize the pseudo-RNG for Avahi */
1024
srand((unsigned int) time(NULL));
1025
mc.simple_poll = avahi_simple_poll_new();
1026
if(mc.simple_poll == NULL){
1027
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1028
exitcode = EXIT_FAILURE;
1032
sigemptyset(&sigterm_action.sa_mask);
1033
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1035
perror("sigaddset");
1036
exitcode = EXIT_FAILURE;
1039
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1041
perror("sigaddset");
1042
exitcode = EXIT_FAILURE;
1045
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1047
perror("sigaddset");
1048
exitcode = EXIT_FAILURE;
1051
ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
1053
perror("sigaction");
1054
exitcode = EXIT_FAILURE;
1058
/* If the interface is down, bring it up */
1059
if(interface[0] != '\0'){
1061
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1062
messages to mess up the prompt */
1063
ret = klogctl(8, NULL, 5);
1064
bool restore_loglevel = true;
1066
restore_loglevel = false;
1069
#endif /* __linux__ */
1071
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1074
exitcode = EXIT_FAILURE;
1076
if(restore_loglevel){
1077
ret = klogctl(7, NULL, 0);
1082
#endif /* __linux__ */
1085
strcpy(network.ifr_name, interface);
1086
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1088
perror("ioctl SIOCGIFFLAGS");
1090
if(restore_loglevel){
1091
ret = klogctl(7, NULL, 0);
1096
#endif /* __linux__ */
1097
exitcode = EXIT_FAILURE;
1100
if((network.ifr_flags & IFF_UP) == 0){
1101
network.ifr_flags |= IFF_UP;
1102
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1104
perror("ioctl SIOCSIFFLAGS");
1105
exitcode = EXIT_FAILURE;
1107
if(restore_loglevel){
1108
ret = klogctl(7, NULL, 0);
1113
#endif /* __linux__ */
1117
/* sleep checking until interface is running */
1118
for(int i=0; i < delay * 4; i++){
1119
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1121
perror("ioctl SIOCGIFFLAGS");
1122
} else if(network.ifr_flags & IFF_RUNNING){
1125
struct timespec sleeptime = { .tv_nsec = 250000000 };
1126
ret = nanosleep(&sleeptime, NULL);
1127
if(ret == -1 and errno != EINTR){
1128
perror("nanosleep");
1131
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1136
if(restore_loglevel){
1137
/* Restores kernel loglevel to default */
1138
ret = klogctl(7, NULL, 0);
1143
#endif /* __linux__ */
1160
ret = init_gnutls_global(pubkey, seckey);
1162
fprintf(stderr, "init_gnutls_global failed\n");
1163
exitcode = EXIT_FAILURE;
1166
gnutls_initialized = true;
1169
if(mkdtemp(tempdir) == NULL){
1173
tempdir_created = true;
1175
if(not init_gpgme(pubkey, seckey, tempdir)){
1176
fprintf(stderr, "init_gpgme failed\n");
1177
exitcode = EXIT_FAILURE;
1180
gpgme_initialized = true;
1183
if(interface[0] != '\0'){
1184
if_index = (AvahiIfIndex) if_nametoindex(interface);
1186
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1187
exitcode = EXIT_FAILURE;
1192
if(connect_to != NULL){
1193
/* Connect directly, do not use Zeroconf */
1194
/* (Mainly meant for debugging) */
1195
char *address = strrchr(connect_to, ':');
1196
if(address == NULL){
1197
fprintf(stderr, "No colon in address\n");
1198
exitcode = EXIT_FAILURE;
1203
tmpmax = strtoimax(address+1, &tmp, 10);
1204
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1205
or tmpmax != (uint16_t)tmpmax){
1206
fprintf(stderr, "Bad port number\n");
1207
exitcode = EXIT_FAILURE;
1210
port = (uint16_t)tmpmax;
1212
address = connect_to;
1213
/* Colon in address indicates IPv6 */
1215
if(strchr(address, ':') != NULL){
1220
ret = start_mandos_communication(address, port, if_index, af);
1222
exitcode = EXIT_FAILURE;
1224
exitcode = EXIT_SUCCESS;
507
1230
AvahiServerConfig config;
508
AvahiSServiceBrowser *sb = NULL;
512
avahi_set_log_function(empty_log);
514
/* Initialize the psuedo-RNG */
517
/* Allocate main loop object */
518
if (!(simple_poll = avahi_simple_poll_new())) {
519
fprintf(stderr, "Failed to create simple poll object.\n");
523
/* Do not publish any local records */
1231
/* Do not publish any local Zeroconf records */
524
1232
avahi_server_config_init(&config);
525
1233
config.publish_hinfo = 0;
526
1234
config.publish_addresses = 0;
527
1235
config.publish_workstation = 0;
528
1236
config.publish_domain = 0;
530
/* /\* Set a unicast DNS server for wide area DNS-SD *\/ */
531
/* avahi_address_parse("193.11.177.11", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]); */
532
/* config.n_wide_area_servers = 1; */
533
/* config.enable_wide_area = 1; */
535
1238
/* Allocate a new server */
536
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
538
/* Free the configuration data */
1239
mc.server = avahi_server_new(avahi_simple_poll_get
1240
(mc.simple_poll), &config, NULL,
1243
/* Free the Avahi configuration data */
539
1244
avahi_server_config_free(&config);
541
/* Check wether creating the server object succeeded */
543
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
547
/* Create the service browser */
548
if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
549
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
553
/* Run the main loop */
554
avahi_simple_poll_loop(simple_poll);
562
avahi_s_service_browser_free(sb);
565
avahi_server_free(server);
568
avahi_simple_poll_free(simple_poll);
1247
/* Check if creating the Avahi server object succeeded */
1248
if(mc.server == NULL){
1249
fprintf(stderr, "Failed to create Avahi server: %s\n",
1250
avahi_strerror(error));
1251
exitcode = EXIT_FAILURE;
1255
/* Create the Avahi service browser */
1256
sb = avahi_s_service_browser_new(mc.server, if_index,
1257
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1258
NULL, 0, browse_callback, NULL);
1260
fprintf(stderr, "Failed to create service browser: %s\n",
1261
avahi_strerror(avahi_server_errno(mc.server)));
1262
exitcode = EXIT_FAILURE;
1266
/* Run the main loop */
1269
fprintf(stderr, "Starting Avahi loop search\n");
1272
avahi_simple_poll_loop(mc.simple_poll);
1277
fprintf(stderr, "%s exiting\n", argv[0]);
1280
/* Cleanup things */
1282
avahi_s_service_browser_free(sb);
1284
if(mc.server != NULL)
1285
avahi_server_free(mc.server);
1287
if(mc.simple_poll != NULL)
1288
avahi_simple_poll_free(mc.simple_poll);
1290
if(gnutls_initialized){
1291
gnutls_certificate_free_credentials(mc.cred);
1292
gnutls_global_deinit();
1293
gnutls_dh_params_deinit(mc.dh_params);
1296
if(gpgme_initialized){
1297
gpgme_release(mc.ctx);
1300
/* Removes the temp directory used by GPGME */
1301
if(tempdir_created){
1303
struct dirent *direntry;
1304
d = opendir(tempdir);
1306
if(errno != ENOENT){
1311
direntry = readdir(d);
1312
if(direntry == NULL){
1315
/* Skip "." and ".." */
1316
if(direntry->d_name[0] == '.'
1317
and (direntry->d_name[1] == '\0'
1318
or (direntry->d_name[1] == '.'
1319
and direntry->d_name[2] == '\0'))){
1322
char *fullname = NULL;
1323
ret = asprintf(&fullname, "%s/%s", tempdir,
1329
ret = remove(fullname);
1331
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1338
ret = rmdir(tempdir);
1339
if(ret == -1 and errno != ENOENT){