330
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
194
/* Delete the GPGME FILE pointer cryptotext data buffer */
195
gpgme_data_release(dh_crypto);
333
197
/* Seek back to the beginning of the GPGME plaintext data buffer */
334
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
335
perror("gpgme_data_seek");
336
plaintext_length = -1;
198
gpgme_data_seek(dh_plain, 0, SEEK_SET);
342
plaintext_capacity = incbuffer(plaintext,
343
(size_t)plaintext_length,
345
if(plaintext_capacity == 0){
347
plaintext_length = -1;
202
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
203
*new_packet = realloc(*new_packet,
204
(unsigned int)new_packet_capacity
206
if (*new_packet == NULL){
210
new_packet_capacity += BUFFER_SIZE;
351
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
213
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
353
215
/* Print the data, if any */
359
220
perror("gpgme_data_read");
360
plaintext_length = -1;
363
plaintext_length += ret;
367
fprintf(stderr, "Decrypted password is: ");
368
for(ssize_t i = 0; i < plaintext_length; i++){
369
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
371
fprintf(stderr, "\n");
376
/* Delete the GPGME cryptotext data buffer */
377
gpgme_data_release(dh_crypto);
223
new_packet_length += ret;
226
/* FIXME: check characters before printing to screen so to not print
227
terminal control characters */
229
/* fprintf(stderr, "decrypted password is: "); */
230
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
231
/* fprintf(stderr, "\n"); */
379
234
/* Delete the GPGME plaintext data buffer */
380
235
gpgme_data_release(dh_plain);
381
return plaintext_length;
236
return new_packet_length;
384
static const char * safer_gnutls_strerror(int value){
385
const char *ret = gnutls_strerror(value); /* Spurious warning from
386
-Wunreachable-code */
239
static const char * safer_gnutls_strerror (int value) {
240
const char *ret = gnutls_strerror (value);
388
242
ret = "(unknown)";
392
/* GnuTLS log function callback */
393
static void debuggnutls(__attribute__((unused)) int level,
395
fprintf(stderr, "GnuTLS: %s", string);
246
void debuggnutls(__attribute__((unused)) int level,
248
fprintf(stderr, "%s", string);
398
static int init_gnutls_global(const char *pubkeyfilename,
399
const char *seckeyfilename){
251
int initgnutls(encrypted_session *es){
403
256
fprintf(stderr, "Initializing GnuTLS\n");
406
ret = gnutls_global_init();
407
if(ret != GNUTLS_E_SUCCESS){
408
fprintf(stderr, "GnuTLS global_init: %s\n",
409
safer_gnutls_strerror(ret));
259
if ((ret = gnutls_global_init ())
260
!= GNUTLS_E_SUCCESS) {
261
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
414
/* "Use a log level over 10 to enable all debugging options."
417
266
gnutls_global_set_log_level(11);
418
267
gnutls_global_set_log_function(debuggnutls);
421
/* OpenPGP credentials */
422
gnutls_certificate_allocate_credentials(&mc.cred);
423
if(ret != GNUTLS_E_SUCCESS){
424
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
428
safer_gnutls_strerror(ret));
429
gnutls_global_deinit();
270
/* openpgp credentials */
271
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
272
!= GNUTLS_E_SUCCESS) {
273
fprintf (stderr, "memory error: %s\n",
274
safer_gnutls_strerror(ret));
434
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
435
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
279
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
280
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
439
284
ret = gnutls_certificate_set_openpgp_key_file
440
(mc.cred, pubkeyfilename, seckeyfilename,
441
GNUTLS_OPENPGP_FMT_BASE64);
442
if(ret != GNUTLS_E_SUCCESS){
444
"Error[%d] while reading the OpenPGP key pair ('%s',"
445
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
446
fprintf(stderr, "The GnuTLS error is: %s\n",
447
safer_gnutls_strerror(ret));
451
/* GnuTLS server initialization */
452
ret = gnutls_dh_params_init(&mc.dh_params);
453
if(ret != GNUTLS_E_SUCCESS){
454
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
455
" %s\n", safer_gnutls_strerror(ret));
458
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
459
if(ret != GNUTLS_E_SUCCESS){
460
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
461
safer_gnutls_strerror(ret));
465
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
471
gnutls_certificate_free_credentials(mc.cred);
472
gnutls_global_deinit();
473
gnutls_dh_params_deinit(mc.dh_params);
477
static int init_gnutls_session(gnutls_session_t *session){
479
/* GnuTLS session creation */
481
ret = gnutls_init(session, GNUTLS_SERVER);
485
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
486
if(ret != GNUTLS_E_SUCCESS){
285
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
286
if (ret != GNUTLS_E_SUCCESS) {
288
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
290
ret, CERTFILE, KEYFILE);
291
fprintf(stdout, "The Error is: %s\n",
292
safer_gnutls_strerror(ret));
296
//GnuTLS server initialization
297
if ((ret = gnutls_dh_params_init (&es->dh_params))
298
!= GNUTLS_E_SUCCESS) {
299
fprintf (stderr, "Error in dh parameter initialization: %s\n",
300
safer_gnutls_strerror(ret));
304
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
305
!= GNUTLS_E_SUCCESS) {
306
fprintf (stderr, "Error in prime generation: %s\n",
307
safer_gnutls_strerror(ret));
311
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
313
// GnuTLS session creation
314
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
315
!= GNUTLS_E_SUCCESS){
487
316
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
488
317
safer_gnutls_strerror(ret));
494
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
496
gnutls_deinit(*session);
499
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
500
if(ret != GNUTLS_E_SUCCESS){
501
fprintf(stderr, "Syntax error at: %s\n", err);
502
fprintf(stderr, "GnuTLS error: %s\n",
503
safer_gnutls_strerror(ret));
504
gnutls_deinit(*session);
320
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
321
!= GNUTLS_E_SUCCESS) {
322
fprintf(stderr, "Syntax error at: %s\n", err);
323
fprintf(stderr, "GnuTLS error: %s\n",
324
safer_gnutls_strerror(ret));
510
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
513
gnutls_deinit(*session);
516
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
517
if(ret != GNUTLS_E_SUCCESS){
518
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
328
if ((ret = gnutls_credentials_set
329
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
330
!= GNUTLS_E_SUCCESS) {
331
fprintf(stderr, "Error setting a credentials set: %s\n",
519
332
safer_gnutls_strerror(ret));
520
gnutls_deinit(*session);
524
336
/* ignore client certificate if any. */
525
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
337
gnutls_certificate_server_set_request (es->session,
527
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
340
gnutls_dh_set_prime_bits (es->session, DH_BITS);
532
/* Avahi log function callback */
533
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
534
__attribute__((unused)) const char *txt){}
345
void empty_log(__attribute__((unused)) AvahiLogLevel level,
346
__attribute__((unused)) const char *txt){}
536
/* Called when a Mandos server is found */
537
static int start_mandos_communication(const char *ip, uint16_t port,
538
AvahiIfIndex if_index,
540
int ret, tcp_sd = -1;
543
struct sockaddr_in in;
544
struct sockaddr_in6 in6;
348
int start_mandos_communication(char *ip, uint16_t port,
349
unsigned int if_index){
351
struct sockaddr_in6 to;
352
encrypted_session es;
546
353
char *buffer = NULL;
547
char *decrypted_buffer = NULL;
354
char *decrypted_buffer;
548
355
size_t buffer_length = 0;
549
356
size_t buffer_capacity = 0;
552
gnutls_session_t session;
553
int pf; /* Protocol family */
567
fprintf(stderr, "Bad address family: %d\n", af);
571
ret = init_gnutls_session(&session);
357
ssize_t decrypted_buffer_size;
359
char interface[IF_NAMESIZE];
577
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
362
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
581
tcp_sd = socket(pf, SOCK_STREAM, 0);
365
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
583
367
perror("socket");
591
memset(&to, 0, sizeof(to));
593
to.in6.sin6_family = (sa_family_t)af;
594
ret = inet_pton(af, ip, &to.in6.sin6_addr);
596
to.in.sin_family = (sa_family_t)af;
597
ret = inet_pton(af, ip, &to.in.sin_addr);
371
if(if_indextoname(if_index, interface) == NULL){
373
perror("if_indextoname");
379
fprintf(stderr, "Binding to interface %s\n", interface);
382
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
384
perror("setsockopt bindtodevice");
388
memset(&to,0,sizeof(to));
389
to.sin6_family = AF_INET6;
390
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
600
392
perror("inet_pton");
604
396
fprintf(stderr, "Bad address: %s\n", ip);
608
to.in6.sin6_port = htons(port); /* Spurious warnings from
610
-Wunreachable-code */
612
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
613
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
615
if(if_index == AVAHI_IF_UNSPEC){
616
fprintf(stderr, "An IPv6 link-local address is incomplete"
617
" without a network interface\n");
620
/* Set the network interface number as scope */
621
to.in6.sin6_scope_id = (uint32_t)if_index;
624
to.in.sin_port = htons(port); /* Spurious warnings from
626
-Wunreachable-code */
399
/* Spurious warnings for the next line, see for instance
400
<http://bugs.debian.org/488884> */
401
to.sin6_port = htons(port);
403
to.sin6_scope_id = (uint32_t)if_index;
634
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
635
char interface[IF_NAMESIZE];
636
if(if_indextoname((unsigned int)if_index, interface) == NULL){
637
perror("if_indextoname");
639
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
640
ip, interface, port);
643
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
646
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
647
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
650
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
653
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
659
if(strcmp(addrstr, ip) != 0){
660
fprintf(stderr, "Canonical address form: %s\n", addrstr);
670
ret = connect(tcp_sd, &to.in6, sizeof(to));
672
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
406
fprintf(stderr, "Connection to: %s\n", ip);
409
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
675
411
perror("connect");
683
const char *out = mandos_protocol_version;
686
size_t out_size = strlen(out);
687
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
688
out_size - written));
693
written += (size_t)ret;
694
if(written < out_size){
697
if(out == mandos_protocol_version){
415
ret = initgnutls (&es);
421
gnutls_transport_set_ptr (es.session,
422
(gnutls_transport_ptr_t) tcp_sd);
711
425
fprintf(stderr, "Establishing TLS session with %s\n", ip);
718
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
725
ret = gnutls_handshake(session);
729
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
731
if(ret != GNUTLS_E_SUCCESS){
733
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
739
/* Read OpenPGP packet that contains the wanted password */
428
ret = gnutls_handshake (es.session);
430
if (ret != GNUTLS_E_SUCCESS){
431
fprintf(stderr, "\n*** Handshake failed ***\n");
437
//Retrieve OpenPGP packet that contains the wanted password
742
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
440
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
752
buffer_capacity = incbuffer(&buffer, buffer_length,
754
if(buffer_capacity == 0){
763
sret = gnutls_record_recv(session, buffer+buffer_length,
445
if (buffer_length + BUFFER_SIZE > buffer_capacity){
446
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
451
buffer_capacity += BUFFER_SIZE;
454
ret = gnutls_record_recv
455
(es.session, buffer+buffer_length, BUFFER_SIZE);
770
461
case GNUTLS_E_INTERRUPTED:
771
462
case GNUTLS_E_AGAIN:
773
464
case GNUTLS_E_REHANDSHAKE:
775
ret = gnutls_handshake(session);
780
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
782
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
465
ret = gnutls_handshake (es.session);
467
fprintf(stderr, "\n*** Handshake failed ***\n");
788
474
fprintf(stderr, "Unknown error while reading data from"
789
" encrypted session with Mandos server\n");
790
gnutls_bye(session, GNUTLS_SHUT_RDWR);
475
" encrypted session with mandos server\n");
477
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
794
buffer_length += (size_t) sret;
799
fprintf(stderr, "Closing TLS session\n");
807
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
811
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
813
if(buffer_length > 0){
814
ssize_t decrypted_buffer_size;
481
buffer_length += (size_t) ret;
485
if (buffer_length > 0){
815
486
decrypted_buffer_size = pgp_packet_decrypt(buffer,
818
if(decrypted_buffer_size >= 0){
821
while(written < (size_t) decrypted_buffer_size){
826
ret = (int)fwrite(decrypted_buffer + written, 1,
827
(size_t)decrypted_buffer_size - written,
490
if (decrypted_buffer_size >= 0){
491
while(decrypted_buffer_size > 0){
492
ret = fwrite (decrypted_buffer, 1, (size_t)decrypted_buffer_size,
829
494
if(ret == 0 and ferror(stdout)){
831
496
fprintf(stderr, "Error writing encrypted data: %s\n",
832
497
strerror(errno));
836
written += (size_t)ret;
502
decrypted_buffer += ret;
503
decrypted_buffer_size -= ret;
505
free(decrypted_buffer);
842
/* Shutdown procedure */
845
free(decrypted_buffer);
514
fprintf(stderr, "Closing TLS session\n");
848
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
853
gnutls_deinit(session);
518
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
521
gnutls_deinit (es.session);
522
gnutls_certificate_free_credentials (es.cred);
523
gnutls_global_deinit ();
860
static void resolve_callback(AvahiSServiceResolver *r,
861
AvahiIfIndex interface,
863
AvahiResolverEvent event,
867
const char *host_name,
868
const AvahiAddress *address,
870
AVAHI_GCC_UNUSED AvahiStringList *txt,
871
AVAHI_GCC_UNUSED AvahiLookupResultFlags
873
AVAHI_GCC_UNUSED void* userdata){
527
static AvahiSimplePoll *simple_poll = NULL;
528
static AvahiServer *server = NULL;
530
static void resolve_callback(
531
AvahiSServiceResolver *r,
532
AVAHI_GCC_UNUSED AvahiIfIndex interface,
533
AVAHI_GCC_UNUSED AvahiProtocol protocol,
534
AvahiResolverEvent event,
538
const char *host_name,
539
const AvahiAddress *address,
541
AVAHI_GCC_UNUSED AvahiStringList *txt,
542
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
543
AVAHI_GCC_UNUSED void* userdata) {
876
547
/* Called whenever a service has been resolved successfully or
885
552
case AVAHI_RESOLVER_FAILURE:
886
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
887
" of type '%s' in domain '%s': %s\n", name, type, domain,
888
avahi_strerror(avahi_server_errno(mc.server)));
553
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
554
" type '%s' in domain '%s': %s\n", name, type, domain,
555
avahi_strerror(avahi_server_errno(server)));
891
558
case AVAHI_RESOLVER_FOUND:
893
560
char ip[AVAHI_ADDRESS_STR_MAX];
894
561
avahi_address_snprint(ip, sizeof(ip), address);
896
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
897
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
898
ip, (intmax_t)interface, port);
563
fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
564
host_name, ip, port);
900
int ret = start_mandos_communication(ip, port, interface,
901
avahi_proto_to_af(proto));
903
avahi_simple_poll_quit(mc.simple_poll);
566
int ret = start_mandos_communication(ip, port,
907
576
avahi_s_service_resolver_free(r);
910
static void browse_callback(AvahiSServiceBrowser *b,
911
AvahiIfIndex interface,
912
AvahiProtocol protocol,
913
AvahiBrowserEvent event,
917
AVAHI_GCC_UNUSED AvahiLookupResultFlags
919
AVAHI_GCC_UNUSED void* userdata){
922
/* Called whenever a new services becomes available on the LAN or
923
is removed from the LAN */
931
case AVAHI_BROWSER_FAILURE:
933
fprintf(stderr, "(Avahi browser) %s\n",
934
avahi_strerror(avahi_server_errno(mc.server)));
935
avahi_simple_poll_quit(mc.simple_poll);
938
case AVAHI_BROWSER_NEW:
939
/* We ignore the returned Avahi resolver object. In the callback
940
function we free it. If the Avahi server is terminated before
941
the callback function is called the Avahi server will free the
944
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
945
name, type, domain, protocol, 0,
946
resolve_callback, NULL) == NULL)
947
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
948
name, avahi_strerror(avahi_server_errno(mc.server)));
951
case AVAHI_BROWSER_REMOVE:
954
case AVAHI_BROWSER_ALL_FOR_NOW:
955
case AVAHI_BROWSER_CACHE_EXHAUSTED:
957
fprintf(stderr, "No Mandos server found, still searching...\n");
963
/* stop main loop after sigterm has been called */
964
static void handle_sigterm(int sig){
969
signal_received = sig;
970
int old_errno = errno;
971
if(mc.simple_poll != NULL){
972
avahi_simple_poll_quit(mc.simple_poll);
977
int main(int argc, char *argv[]){
978
AvahiSServiceBrowser *sb = NULL;
983
int exitcode = EXIT_SUCCESS;
984
const char *interface = "eth0";
985
struct ifreq network;
987
bool take_down_interface = false;
990
char *connect_to = NULL;
991
char tempdir[] = "/tmp/mandosXXXXXX";
992
bool tempdir_created = false;
993
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
994
const char *seckey = PATHDIR "/" SECKEY;
995
const char *pubkey = PATHDIR "/" PUBKEY;
997
bool gnutls_initialized = false;
998
bool gpgme_initialized = false;
1001
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1002
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1007
/* Lower any group privileges we might have, just to be safe */
1014
/* Lower user privileges (temporarily) */
1026
struct argp_option options[] = {
1027
{ .name = "debug", .key = 128,
1028
.doc = "Debug mode", .group = 3 },
1029
{ .name = "connect", .key = 'c',
1030
.arg = "ADDRESS:PORT",
1031
.doc = "Connect directly to a specific Mandos server",
1033
{ .name = "interface", .key = 'i',
1035
.doc = "Network interface that will be used to search for"
1038
{ .name = "seckey", .key = 's',
1040
.doc = "OpenPGP secret key file base name",
1042
{ .name = "pubkey", .key = 'p',
1044
.doc = "OpenPGP public key file base name",
1046
{ .name = "dh-bits", .key = 129,
1048
.doc = "Bit length of the prime number used in the"
1049
" Diffie-Hellman key exchange",
1051
{ .name = "priority", .key = 130,
1053
.doc = "GnuTLS priority string for the TLS handshake",
1055
{ .name = "delay", .key = 131,
1057
.doc = "Maximum delay to wait for interface startup",
1062
error_t parse_opt(int key, char *arg,
1063
struct argp_state *state){
1065
case 128: /* --debug */
1068
case 'c': /* --connect */
1071
case 'i': /* --interface */
1074
case 's': /* --seckey */
1077
case 'p': /* --pubkey */
1080
case 129: /* --dh-bits */
1082
tmpmax = strtoimax(arg, &tmp, 10);
1083
if(errno != 0 or tmp == arg or *tmp != '\0'
1084
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1085
fprintf(stderr, "Bad number of DH bits\n");
1088
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1090
case 130: /* --priority */
1093
case 131: /* --delay */
1095
delay = strtof(arg, &tmp);
1096
if(errno != 0 or tmp == arg or *tmp != '\0'){
1097
fprintf(stderr, "Bad delay\n");
1106
return ARGP_ERR_UNKNOWN;
1111
struct argp argp = { .options = options, .parser = parse_opt,
1113
.doc = "Mandos client -- Get and decrypt"
1114
" passwords from a Mandos server" };
1115
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
1116
if(ret == ARGP_ERR_UNKNOWN){
1117
fprintf(stderr, "Unknown error while parsing arguments\n");
1118
exitcode = EXIT_FAILURE;
1124
avahi_set_log_function(empty_log);
1127
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1128
from the signal handler */
1129
/* Initialize the pseudo-RNG for Avahi */
1130
srand((unsigned int) time(NULL));
1131
mc.simple_poll = avahi_simple_poll_new();
1132
if(mc.simple_poll == NULL){
1133
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1134
exitcode = EXIT_FAILURE;
1138
sigemptyset(&sigterm_action.sa_mask);
1139
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1141
perror("sigaddset");
1142
exitcode = EXIT_FAILURE;
1145
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1147
perror("sigaddset");
1148
exitcode = EXIT_FAILURE;
1151
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1153
perror("sigaddset");
1154
exitcode = EXIT_FAILURE;
1157
/* Need to check if the handler is SIG_IGN before handling:
1158
| [[info:libc:Initial Signal Actions]] |
1159
| [[info:libc:Basic Signal Handling]] |
1161
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1163
perror("sigaction");
1164
return EXIT_FAILURE;
1166
if(old_sigterm_action.sa_handler != SIG_IGN){
1167
ret = sigaction(SIGINT, &sigterm_action, NULL);
1169
perror("sigaction");
1170
exitcode = EXIT_FAILURE;
1174
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1176
perror("sigaction");
1177
return EXIT_FAILURE;
1179
if(old_sigterm_action.sa_handler != SIG_IGN){
1180
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1182
perror("sigaction");
1183
exitcode = EXIT_FAILURE;
1187
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1189
perror("sigaction");
1190
return EXIT_FAILURE;
1192
if(old_sigterm_action.sa_handler != SIG_IGN){
1193
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1195
perror("sigaction");
1196
exitcode = EXIT_FAILURE;
1201
/* If the interface is down, bring it up */
1202
if(interface[0] != '\0'){
1203
if_index = (AvahiIfIndex) if_nametoindex(interface);
1205
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1206
exitcode = EXIT_FAILURE;
1214
/* Re-raise priviliges */
1222
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1223
messages to mess up the prompt */
1224
ret = klogctl(8, NULL, 5);
1225
bool restore_loglevel = true;
1227
restore_loglevel = false;
1230
#endif /* __linux__ */
1232
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1235
exitcode = EXIT_FAILURE;
1237
if(restore_loglevel){
1238
ret = klogctl(7, NULL, 0);
1243
#endif /* __linux__ */
1244
/* Lower privileges */
1252
strcpy(network.ifr_name, interface);
1253
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1255
perror("ioctl SIOCGIFFLAGS");
1257
if(restore_loglevel){
1258
ret = klogctl(7, NULL, 0);
1263
#endif /* __linux__ */
1264
exitcode = EXIT_FAILURE;
1265
/* Lower privileges */
1273
if((network.ifr_flags & IFF_UP) == 0){
1274
network.ifr_flags |= IFF_UP;
1275
take_down_interface = true;
1276
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1278
take_down_interface = false;
1279
perror("ioctl SIOCSIFFLAGS");
1280
exitcode = EXIT_FAILURE;
1282
if(restore_loglevel){
1283
ret = klogctl(7, NULL, 0);
1288
#endif /* __linux__ */
1289
/* Lower privileges */
1298
/* sleep checking until interface is running */
1299
for(int i=0; i < delay * 4; i++){
1300
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1302
perror("ioctl SIOCGIFFLAGS");
1303
} else if(network.ifr_flags & IFF_RUNNING){
1306
struct timespec sleeptime = { .tv_nsec = 250000000 };
1307
ret = nanosleep(&sleeptime, NULL);
1308
if(ret == -1 and errno != EINTR){
1309
perror("nanosleep");
1312
if(not take_down_interface){
1313
/* We won't need the socket anymore */
1314
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1320
if(restore_loglevel){
1321
/* Restores kernel loglevel to default */
1322
ret = klogctl(7, NULL, 0);
1327
#endif /* __linux__ */
1328
/* Lower privileges */
1330
if(take_down_interface){
1331
/* Lower privileges */
1337
/* Lower privileges permanently */
1349
ret = init_gnutls_global(pubkey, seckey);
1351
fprintf(stderr, "init_gnutls_global failed\n");
1352
exitcode = EXIT_FAILURE;
1355
gnutls_initialized = true;
1362
tempdir_created = true;
1363
if(mkdtemp(tempdir) == NULL){
1364
tempdir_created = false;
1373
if(not init_gpgme(pubkey, seckey, tempdir)){
1374
fprintf(stderr, "init_gpgme failed\n");
1375
exitcode = EXIT_FAILURE;
1378
gpgme_initialized = true;
1385
if(connect_to != NULL){
1386
/* Connect directly, do not use Zeroconf */
1387
/* (Mainly meant for debugging) */
1388
char *address = strrchr(connect_to, ':');
1389
if(address == NULL){
1390
fprintf(stderr, "No colon in address\n");
1391
exitcode = EXIT_FAILURE;
1401
tmpmax = strtoimax(address+1, &tmp, 10);
1402
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1403
or tmpmax != (uint16_t)tmpmax){
1404
fprintf(stderr, "Bad port number\n");
1405
exitcode = EXIT_FAILURE;
1413
port = (uint16_t)tmpmax;
1415
address = connect_to;
1416
/* Colon in address indicates IPv6 */
1418
if(strchr(address, ':') != NULL){
1428
ret = start_mandos_communication(address, port, if_index, af);
1430
exitcode = EXIT_FAILURE;
1432
exitcode = EXIT_SUCCESS;
579
static void browse_callback(
580
AvahiSServiceBrowser *b,
581
AvahiIfIndex interface,
582
AvahiProtocol protocol,
583
AvahiBrowserEvent event,
587
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
590
AvahiServer *s = userdata;
593
/* Called whenever a new services becomes available on the LAN or
594
is removed from the LAN */
598
case AVAHI_BROWSER_FAILURE:
600
fprintf(stderr, "(Browser) %s\n",
601
avahi_strerror(avahi_server_errno(server)));
602
avahi_simple_poll_quit(simple_poll);
605
case AVAHI_BROWSER_NEW:
606
/* We ignore the returned resolver object. In the callback
607
function we free it. If the server is terminated before
608
the callback function is called the server will free
609
the resolver for us. */
611
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
613
AVAHI_PROTO_INET6, 0,
614
resolve_callback, s)))
615
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
616
avahi_strerror(avahi_server_errno(s)));
619
case AVAHI_BROWSER_REMOVE:
622
case AVAHI_BROWSER_ALL_FOR_NOW:
623
case AVAHI_BROWSER_CACHE_EXHAUSTED:
628
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1442
629
AvahiServerConfig config;
1443
/* Do not publish any local Zeroconf records */
630
AvahiSServiceBrowser *sb = NULL;
633
int returncode = EXIT_SUCCESS;
634
const char *interface = "eth0";
637
static struct option long_options[] = {
638
{"debug", no_argument, (int *)&debug, 1},
639
{"interface", required_argument, 0, 'i'},
642
int option_index = 0;
643
ret = getopt_long (argc, argv, "i:", long_options,
662
avahi_set_log_function(empty_log);
665
/* Initialize the psuedo-RNG */
666
srand((unsigned int) time(NULL));
668
/* Allocate main loop object */
669
if (!(simple_poll = avahi_simple_poll_new())) {
670
fprintf(stderr, "Failed to create simple poll object.\n");
675
/* Do not publish any local records */
1444
676
avahi_server_config_init(&config);
1445
677
config.publish_hinfo = 0;
1446
678
config.publish_addresses = 0;
1447
679
config.publish_workstation = 0;
1448
680
config.publish_domain = 0;
1450
682
/* Allocate a new server */
1451
mc.server = avahi_server_new(avahi_simple_poll_get
1452
(mc.simple_poll), &config, NULL,
1455
/* Free the Avahi configuration data */
683
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
684
&config, NULL, NULL, &error);
686
/* Free the configuration data */
1456
687
avahi_server_config_free(&config);
1459
/* Check if creating the Avahi server object succeeded */
1460
if(mc.server == NULL){
1461
fprintf(stderr, "Failed to create Avahi server: %s\n",
1462
avahi_strerror(error));
1463
exitcode = EXIT_FAILURE;
1471
/* Create the Avahi service browser */
1472
sb = avahi_s_service_browser_new(mc.server, if_index,
1473
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1474
NULL, 0, browse_callback, NULL);
1476
fprintf(stderr, "Failed to create service browser: %s\n",
1477
avahi_strerror(avahi_server_errno(mc.server)));
1478
exitcode = EXIT_FAILURE;
1486
/* Run the main loop */
1489
fprintf(stderr, "Starting Avahi loop search\n");
1492
avahi_simple_poll_loop(mc.simple_poll);
1497
fprintf(stderr, "%s exiting\n", argv[0]);
1500
/* Cleanup things */
1502
avahi_s_service_browser_free(sb);
1504
if(mc.server != NULL)
1505
avahi_server_free(mc.server);
1507
if(mc.simple_poll != NULL)
1508
avahi_simple_poll_free(mc.simple_poll);
1510
if(gnutls_initialized){
1511
gnutls_certificate_free_credentials(mc.cred);
1512
gnutls_global_deinit();
1513
gnutls_dh_params_deinit(mc.dh_params);
1516
if(gpgme_initialized){
1517
gpgme_release(mc.ctx);
1520
/* Take down the network interface */
1521
if(take_down_interface){
1522
/* Re-raise priviliges */
1529
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1531
perror("ioctl SIOCGIFFLAGS");
1532
} else if(network.ifr_flags & IFF_UP) {
1533
network.ifr_flags &= ~IFF_UP; /* clear flag */
1534
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1536
perror("ioctl SIOCSIFFLAGS");
1539
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1543
/* Lower privileges permanently */
1552
/* Removes the temp directory used by GPGME */
1553
if(tempdir_created){
1555
struct dirent *direntry;
1556
d = opendir(tempdir);
1558
if(errno != ENOENT){
1563
direntry = readdir(d);
1564
if(direntry == NULL){
1567
/* Skip "." and ".." */
1568
if(direntry->d_name[0] == '.'
1569
and (direntry->d_name[1] == '\0'
1570
or (direntry->d_name[1] == '.'
1571
and direntry->d_name[2] == '\0'))){
1574
char *fullname = NULL;
1575
ret = asprintf(&fullname, "%s/%s", tempdir,
1581
ret = remove(fullname);
1583
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1590
ret = rmdir(tempdir);
1591
if(ret == -1 and errno != ENOENT){
1597
sigemptyset(&old_sigterm_action.sa_mask);
1598
old_sigterm_action.sa_handler = SIG_DFL;
1599
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1600
&old_sigterm_action,
1603
perror("sigaction");
1606
ret = raise(signal_received);
1607
} while(ret != 0 and errno == EINTR);
1612
TEMP_FAILURE_RETRY(pause());
689
/* Check if creating the server object succeeded */
691
fprintf(stderr, "Failed to create server: %s\n",
692
avahi_strerror(error));
693
returncode = EXIT_FAILURE;
697
/* Create the service browser */
698
sb = avahi_s_service_browser_new(server,
700
if_nametoindex(interface),
702
"_mandos._tcp", NULL, 0,
703
browse_callback, server);
705
fprintf(stderr, "Failed to create service browser: %s\n",
706
avahi_strerror(avahi_server_errno(server)));
707
returncode = EXIT_FAILURE;
711
/* Run the main loop */
714
fprintf(stderr, "Starting avahi loop search\n");
717
avahi_simple_poll_loop(simple_poll);
722
fprintf(stderr, "%s exiting\n", argv[0]);
727
avahi_s_service_browser_free(sb);
730
avahi_server_free(server);
733
avahi_simple_poll_free(simple_poll);