194
/* Delete the GPGME FILE pointer cryptotext data buffer */
195
gpgme_data_release(dh_crypto);
332
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
197
335
/* Seek back to the beginning of the GPGME plaintext data buffer */
198
gpgme_data_seek(dh_plain, 0, SEEK_SET);
336
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
337
perror("gpgme_data_seek");
338
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;
344
plaintext_capacity = incbuffer(plaintext,
345
(size_t)plaintext_length,
347
if(plaintext_capacity == 0){
349
plaintext_length = -1;
213
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
353
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
215
355
/* Print the data, if any */
220
361
perror("gpgme_data_read");
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"); */
362
plaintext_length = -1;
365
plaintext_length += ret;
369
fprintf(stderr, "Decrypted password is: ");
370
for(ssize_t i = 0; i < plaintext_length; i++){
371
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
373
fprintf(stderr, "\n");
378
/* Delete the GPGME cryptotext data buffer */
379
gpgme_data_release(dh_crypto);
234
381
/* Delete the GPGME plaintext data buffer */
235
382
gpgme_data_release(dh_plain);
236
return new_packet_length;
383
return plaintext_length;
239
static const char * safer_gnutls_strerror (int value) {
240
const char *ret = gnutls_strerror (value);
386
static const char * safer_gnutls_strerror(int value){
387
const char *ret = gnutls_strerror(value); /* Spurious warning from
388
-Wunreachable-code */
242
390
ret = "(unknown)";
246
void debuggnutls(__attribute__((unused)) int level,
248
fprintf(stderr, "%s", string);
394
/* GnuTLS log function callback */
395
static void debuggnutls(__attribute__((unused)) int level,
397
fprintf(stderr, "GnuTLS: %s", string);
251
int initgnutls(encrypted_session *es){
400
static int init_gnutls_global(const char *pubkeyfilename,
401
const char *seckeyfilename){
256
405
fprintf(stderr, "Initializing GnuTLS\n");
259
if ((ret = gnutls_global_init ())
260
!= GNUTLS_E_SUCCESS) {
261
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
408
ret = gnutls_global_init();
409
if(ret != GNUTLS_E_SUCCESS){
410
fprintf(stderr, "GnuTLS global_init: %s\n",
411
safer_gnutls_strerror(ret));
416
/* "Use a log level over 10 to enable all debugging options."
266
419
gnutls_global_set_log_level(11);
267
420
gnutls_global_set_log_function(debuggnutls);
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));
423
/* OpenPGP credentials */
424
gnutls_certificate_allocate_credentials(&mc.cred);
425
if(ret != GNUTLS_E_SUCCESS){
426
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
430
safer_gnutls_strerror(ret));
431
gnutls_global_deinit();
279
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
280
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
436
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
437
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
284
441
ret = gnutls_certificate_set_openpgp_key_file
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){
442
(mc.cred, pubkeyfilename, seckeyfilename,
443
GNUTLS_OPENPGP_FMT_BASE64);
444
if(ret != GNUTLS_E_SUCCESS){
446
"Error[%d] while reading the OpenPGP key pair ('%s',"
447
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
448
fprintf(stderr, "The GnuTLS error is: %s\n",
449
safer_gnutls_strerror(ret));
453
/* GnuTLS server initialization */
454
ret = gnutls_dh_params_init(&mc.dh_params);
455
if(ret != GNUTLS_E_SUCCESS){
456
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
457
" %s\n", safer_gnutls_strerror(ret));
460
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
461
if(ret != GNUTLS_E_SUCCESS){
462
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
463
safer_gnutls_strerror(ret));
467
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
473
gnutls_certificate_free_credentials(mc.cred);
474
gnutls_global_deinit();
475
gnutls_dh_params_deinit(mc.dh_params);
479
static int init_gnutls_session(gnutls_session_t *session){
481
/* GnuTLS session creation */
483
ret = gnutls_init(session, GNUTLS_SERVER);
487
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
488
if(ret != GNUTLS_E_SUCCESS){
316
489
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
317
490
safer_gnutls_strerror(ret));
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));
496
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
498
gnutls_deinit(*session);
501
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
502
if(ret != GNUTLS_E_SUCCESS){
503
fprintf(stderr, "Syntax error at: %s\n", err);
504
fprintf(stderr, "GnuTLS error: %s\n",
505
safer_gnutls_strerror(ret));
506
gnutls_deinit(*session);
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",
512
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
515
gnutls_deinit(*session);
518
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
519
if(ret != GNUTLS_E_SUCCESS){
520
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
332
521
safer_gnutls_strerror(ret));
522
gnutls_deinit(*session);
336
526
/* ignore client certificate if any. */
337
gnutls_certificate_server_set_request (es->session,
527
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
340
gnutls_dh_set_prime_bits (es->session, DH_BITS);
529
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
345
void empty_log(__attribute__((unused)) AvahiLogLevel level,
346
__attribute__((unused)) const char *txt){}
534
/* Avahi log function callback */
535
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
536
__attribute__((unused)) const char *txt){}
348
int start_mandos_communication(char *ip, uint16_t port,
349
unsigned int if_index){
351
struct sockaddr_in6 to;
352
encrypted_session es;
538
/* Called when a Mandos server is found */
539
static int start_mandos_communication(const char *ip, uint16_t port,
540
AvahiIfIndex if_index,
542
int ret, tcp_sd = -1;
545
struct sockaddr_in in;
546
struct sockaddr_in6 in6;
353
548
char *buffer = NULL;
354
char *decrypted_buffer;
549
char *decrypted_buffer = NULL;
355
550
size_t buffer_length = 0;
356
551
size_t buffer_capacity = 0;
357
ssize_t decrypted_buffer_size;
359
char interface[IF_NAMESIZE];
554
gnutls_session_t session;
555
int pf; /* Protocol family */
569
fprintf(stderr, "Bad address family: %d\n", af);
573
ret = init_gnutls_session(&session);
362
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
579
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
365
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
583
tcp_sd = socket(pf, SOCK_STREAM, 0);
367
585
perror("socket");
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);
593
memset(&to, 0, sizeof(to));
595
to.in6.sin6_family = (sa_family_t)af;
596
ret = inet_pton(af, ip, &to.in6.sin6_addr);
598
to.in.sin_family = (sa_family_t)af;
599
ret = inet_pton(af, ip, &to.in.sin_addr);
392
602
perror("inet_pton");
396
606
fprintf(stderr, "Bad address: %s\n", ip);
399
/* Spurious warnings for the next line, see for instance
400
<http://bugs.debian.org/488884> */
401
to.sin6_port = htons(port);
610
to.in6.sin6_port = htons(port); /* Spurious warnings from
612
-Wunreachable-code */
614
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
615
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
617
if(if_index == AVAHI_IF_UNSPEC){
618
fprintf(stderr, "An IPv6 link-local address is incomplete"
619
" without a network interface\n");
622
/* Set the network interface number as scope */
623
to.in6.sin6_scope_id = (uint32_t)if_index;
626
to.in.sin_port = htons(port); /* Spurious warnings from
628
-Wunreachable-code */
403
to.sin6_scope_id = (uint32_t)if_index;
406
fprintf(stderr, "Connection to: %s\n", ip);
409
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
636
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
637
char interface[IF_NAMESIZE];
638
if(if_indextoname((unsigned int)if_index, interface) == NULL){
639
perror("if_indextoname");
641
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
642
ip, interface, port);
645
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
648
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
649
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
652
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
655
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
661
if(strcmp(addrstr, ip) != 0){
662
fprintf(stderr, "Canonical address form: %s\n", addrstr);
672
ret = connect(tcp_sd, &to.in6, sizeof(to));
674
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
411
677
perror("connect");
415
ret = initgnutls (&es);
421
gnutls_transport_set_ptr (es.session,
422
(gnutls_transport_ptr_t) tcp_sd);
685
const char *out = mandos_protocol_version;
688
size_t out_size = strlen(out);
689
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
690
out_size - written));
695
written += (size_t)ret;
696
if(written < out_size){
699
if(out == mandos_protocol_version){
425
713
fprintf(stderr, "Establishing TLS session with %s\n", ip);
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
720
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
727
ret = gnutls_handshake(session);
731
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
733
if(ret != GNUTLS_E_SUCCESS){
735
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
741
/* Read OpenPGP packet that contains the wanted password */
440
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
744
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
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);
754
buffer_capacity = incbuffer(&buffer, buffer_length,
756
if(buffer_capacity == 0){
765
sret = gnutls_record_recv(session, buffer+buffer_length,
461
772
case GNUTLS_E_INTERRUPTED:
462
773
case GNUTLS_E_AGAIN:
464
775
case GNUTLS_E_REHANDSHAKE:
465
ret = gnutls_handshake (es.session);
467
fprintf(stderr, "\n*** Handshake failed ***\n");
777
ret = gnutls_handshake(session);
782
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
784
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
474
790
fprintf(stderr, "Unknown error while reading data from"
475
" encrypted session with mandos server\n");
477
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
791
" encrypted session with Mandos server\n");
792
gnutls_bye(session, GNUTLS_SHUT_RDWR);
481
buffer_length += (size_t) ret;
485
if (buffer_length > 0){
796
buffer_length += (size_t) sret;
801
fprintf(stderr, "Closing TLS session\n");
809
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
813
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
815
if(buffer_length > 0){
816
ssize_t decrypted_buffer_size;
486
817
decrypted_buffer_size = pgp_packet_decrypt(buffer,
490
if (decrypted_buffer_size >= 0){
491
while(decrypted_buffer_size > 0){
492
ret = fwrite (decrypted_buffer, 1, (size_t)decrypted_buffer_size,
820
if(decrypted_buffer_size >= 0){
823
while(written < (size_t) decrypted_buffer_size){
828
ret = (int)fwrite(decrypted_buffer + written, 1,
829
(size_t)decrypted_buffer_size - written,
494
831
if(ret == 0 and ferror(stdout)){
496
833
fprintf(stderr, "Error writing encrypted data: %s\n",
497
834
strerror(errno));
502
decrypted_buffer += ret;
503
decrypted_buffer_size -= ret;
838
written += (size_t)ret;
505
free(decrypted_buffer);
514
fprintf(stderr, "Closing TLS session\n");
844
/* Shutdown procedure */
847
free(decrypted_buffer);
518
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
521
gnutls_deinit (es.session);
522
gnutls_certificate_free_credentials (es.cred);
523
gnutls_global_deinit ();
850
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
855
gnutls_deinit(session);
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) {
862
static void resolve_callback(AvahiSServiceResolver *r,
863
AvahiIfIndex interface,
865
AvahiResolverEvent event,
869
const char *host_name,
870
const AvahiAddress *address,
872
AVAHI_GCC_UNUSED AvahiStringList *txt,
873
AVAHI_GCC_UNUSED AvahiLookupResultFlags
875
AVAHI_GCC_UNUSED void* userdata){
547
878
/* Called whenever a service has been resolved successfully or
552
887
case AVAHI_RESOLVER_FAILURE:
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)));
888
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
889
" of type '%s' in domain '%s': %s\n", name, type, domain,
890
avahi_strerror(avahi_server_errno(mc.server)));
558
893
case AVAHI_RESOLVER_FOUND:
560
895
char ip[AVAHI_ADDRESS_STR_MAX];
561
896
avahi_address_snprint(ip, sizeof(ip), address);
563
fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
564
host_name, ip, port);
898
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
899
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
900
ip, (intmax_t)interface, port);
566
int ret = start_mandos_communication(ip, port,
902
int ret = start_mandos_communication(ip, port, interface,
903
avahi_proto_to_af(proto));
905
avahi_simple_poll_quit(mc.simple_poll);
576
909
avahi_s_service_resolver_free(r);
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[]) {
912
static void browse_callback(AvahiSServiceBrowser *b,
913
AvahiIfIndex interface,
914
AvahiProtocol protocol,
915
AvahiBrowserEvent event,
919
AVAHI_GCC_UNUSED AvahiLookupResultFlags
921
AVAHI_GCC_UNUSED void* userdata){
924
/* Called whenever a new services becomes available on the LAN or
925
is removed from the LAN */
933
case AVAHI_BROWSER_FAILURE:
935
fprintf(stderr, "(Avahi browser) %s\n",
936
avahi_strerror(avahi_server_errno(mc.server)));
937
avahi_simple_poll_quit(mc.simple_poll);
940
case AVAHI_BROWSER_NEW:
941
/* We ignore the returned Avahi resolver object. In the callback
942
function we free it. If the Avahi server is terminated before
943
the callback function is called the Avahi server will free the
946
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
947
name, type, domain, protocol, 0,
948
resolve_callback, NULL) == NULL)
949
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
950
name, avahi_strerror(avahi_server_errno(mc.server)));
953
case AVAHI_BROWSER_REMOVE:
956
case AVAHI_BROWSER_ALL_FOR_NOW:
957
case AVAHI_BROWSER_CACHE_EXHAUSTED:
959
fprintf(stderr, "No Mandos server found, still searching...\n");
965
/* stop main loop after sigterm has been called */
966
static void handle_sigterm(int sig){
971
signal_received = sig;
972
int old_errno = errno;
973
if(mc.simple_poll != NULL){
974
avahi_simple_poll_quit(mc.simple_poll);
980
* This function determines if a directory entry in /sys/class/net
981
* corresponds to an acceptable network device.
982
* (This function is passed to scandir(3) as a filter function.)
984
int good_interface(const struct dirent *if_entry){
986
char *flagname = NULL;
987
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
993
if(if_entry->d_name[0] == '.'){
996
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1001
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1002
/* read line from flags_fd */
1003
ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1004
char *flagstring = malloc((size_t)to_read);
1005
if(flagstring == NULL){
1011
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1028
tmpmax = strtoimax(flagstring, &tmp, 0);
1029
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1030
and not (isspace(*tmp)))
1031
or tmpmax != (ifreq_flags)tmpmax){
1036
ifreq_flags flags = (ifreq_flags)tmpmax;
1037
/* Reject the loopback device */
1038
if(flags & IFF_LOOPBACK){
1041
/* Accept point-to-point devices only if connect_to is specified */
1042
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1045
/* Otherwise, reject non-broadcast-capable devices */
1046
if(not (flags & IFF_BROADCAST)){
1049
/* Accept this device */
1053
int main(int argc, char *argv[]){
1054
AvahiSServiceBrowser *sb = NULL;
1059
int exitcode = EXIT_SUCCESS;
1060
const char *interface = "";
1061
struct ifreq network;
1063
bool take_down_interface = false;
1066
char tempdir[] = "/tmp/mandosXXXXXX";
1067
bool tempdir_created = false;
1068
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1069
const char *seckey = PATHDIR "/" SECKEY;
1070
const char *pubkey = PATHDIR "/" PUBKEY;
1072
bool gnutls_initialized = false;
1073
bool gpgme_initialized = false;
1076
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1077
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1082
/* Lower any group privileges we might have, just to be safe */
1089
/* Lower user privileges (temporarily) */
1101
struct argp_option options[] = {
1102
{ .name = "debug", .key = 128,
1103
.doc = "Debug mode", .group = 3 },
1104
{ .name = "connect", .key = 'c',
1105
.arg = "ADDRESS:PORT",
1106
.doc = "Connect directly to a specific Mandos server",
1108
{ .name = "interface", .key = 'i',
1110
.doc = "Network interface that will be used to search for"
1113
{ .name = "seckey", .key = 's',
1115
.doc = "OpenPGP secret key file base name",
1117
{ .name = "pubkey", .key = 'p',
1119
.doc = "OpenPGP public key file base name",
1121
{ .name = "dh-bits", .key = 129,
1123
.doc = "Bit length of the prime number used in the"
1124
" Diffie-Hellman key exchange",
1126
{ .name = "priority", .key = 130,
1128
.doc = "GnuTLS priority string for the TLS handshake",
1130
{ .name = "delay", .key = 131,
1132
.doc = "Maximum delay to wait for interface startup",
1137
error_t parse_opt(int key, char *arg,
1138
struct argp_state *state){
1140
case 128: /* --debug */
1143
case 'c': /* --connect */
1146
case 'i': /* --interface */
1149
case 's': /* --seckey */
1152
case 'p': /* --pubkey */
1155
case 129: /* --dh-bits */
1157
tmpmax = strtoimax(arg, &tmp, 10);
1158
if(errno != 0 or tmp == arg or *tmp != '\0'
1159
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1160
fprintf(stderr, "Bad number of DH bits\n");
1163
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1165
case 130: /* --priority */
1168
case 131: /* --delay */
1170
delay = strtof(arg, &tmp);
1171
if(errno != 0 or tmp == arg or *tmp != '\0'){
1172
fprintf(stderr, "Bad delay\n");
1181
return ARGP_ERR_UNKNOWN;
1186
struct argp argp = { .options = options, .parser = parse_opt,
1188
.doc = "Mandos client -- Get and decrypt"
1189
" passwords from a Mandos server" };
1190
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
1191
if(ret == ARGP_ERR_UNKNOWN){
1192
fprintf(stderr, "Unknown error while parsing arguments\n");
1193
exitcode = EXIT_FAILURE;
1199
avahi_set_log_function(empty_log);
1202
if(interface[0] == '\0'){
1203
struct dirent **direntries;
1204
ret = scandir(sys_class_net, &direntries, good_interface,
1207
/* Pick the first good interface */
1208
interface = strdup(direntries[0]->d_name);
1209
if(interface == NULL){
1212
exitcode = EXIT_FAILURE;
1218
fprintf(stderr, "Could not find a network interface\n");
1219
exitcode = EXIT_FAILURE;
1224
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1225
from the signal handler */
1226
/* Initialize the pseudo-RNG for Avahi */
1227
srand((unsigned int) time(NULL));
1228
mc.simple_poll = avahi_simple_poll_new();
1229
if(mc.simple_poll == NULL){
1230
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1231
exitcode = EXIT_FAILURE;
1235
sigemptyset(&sigterm_action.sa_mask);
1236
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1238
perror("sigaddset");
1239
exitcode = EXIT_FAILURE;
1242
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1244
perror("sigaddset");
1245
exitcode = EXIT_FAILURE;
1248
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1250
perror("sigaddset");
1251
exitcode = EXIT_FAILURE;
1254
/* Need to check if the handler is SIG_IGN before handling:
1255
| [[info:libc:Initial Signal Actions]] |
1256
| [[info:libc:Basic Signal Handling]] |
1258
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1260
perror("sigaction");
1261
return EXIT_FAILURE;
1263
if(old_sigterm_action.sa_handler != SIG_IGN){
1264
ret = sigaction(SIGINT, &sigterm_action, NULL);
1266
perror("sigaction");
1267
exitcode = EXIT_FAILURE;
1271
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1273
perror("sigaction");
1274
return EXIT_FAILURE;
1276
if(old_sigterm_action.sa_handler != SIG_IGN){
1277
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1279
perror("sigaction");
1280
exitcode = EXIT_FAILURE;
1284
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1286
perror("sigaction");
1287
return EXIT_FAILURE;
1289
if(old_sigterm_action.sa_handler != SIG_IGN){
1290
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1292
perror("sigaction");
1293
exitcode = EXIT_FAILURE;
1298
/* If the interface is down, bring it up */
1299
if(strcmp(interface, "none") != 0){
1300
if_index = (AvahiIfIndex) if_nametoindex(interface);
1302
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1303
exitcode = EXIT_FAILURE;
1311
/* Re-raise priviliges */
1319
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1320
messages to mess up the prompt */
1321
ret = klogctl(8, NULL, 5);
1322
bool restore_loglevel = true;
1324
restore_loglevel = false;
1327
#endif /* __linux__ */
1329
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1332
exitcode = EXIT_FAILURE;
1334
if(restore_loglevel){
1335
ret = klogctl(7, NULL, 0);
1340
#endif /* __linux__ */
1341
/* Lower privileges */
1349
strcpy(network.ifr_name, interface);
1350
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1352
perror("ioctl SIOCGIFFLAGS");
1354
if(restore_loglevel){
1355
ret = klogctl(7, NULL, 0);
1360
#endif /* __linux__ */
1361
exitcode = EXIT_FAILURE;
1362
/* Lower privileges */
1370
if((network.ifr_flags & IFF_UP) == 0){
1371
network.ifr_flags |= IFF_UP;
1372
take_down_interface = true;
1373
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1375
take_down_interface = false;
1376
perror("ioctl SIOCSIFFLAGS");
1377
exitcode = EXIT_FAILURE;
1379
if(restore_loglevel){
1380
ret = klogctl(7, NULL, 0);
1385
#endif /* __linux__ */
1386
/* Lower privileges */
1395
/* sleep checking until interface is running */
1396
for(int i=0; i < delay * 4; i++){
1397
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1399
perror("ioctl SIOCGIFFLAGS");
1400
} else if(network.ifr_flags & IFF_RUNNING){
1403
struct timespec sleeptime = { .tv_nsec = 250000000 };
1404
ret = nanosleep(&sleeptime, NULL);
1405
if(ret == -1 and errno != EINTR){
1406
perror("nanosleep");
1409
if(not take_down_interface){
1410
/* We won't need the socket anymore */
1411
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1417
if(restore_loglevel){
1418
/* Restores kernel loglevel to default */
1419
ret = klogctl(7, NULL, 0);
1424
#endif /* __linux__ */
1425
/* Lower privileges */
1427
if(take_down_interface){
1428
/* Lower privileges */
1434
/* Lower privileges permanently */
1446
ret = init_gnutls_global(pubkey, seckey);
1448
fprintf(stderr, "init_gnutls_global failed\n");
1449
exitcode = EXIT_FAILURE;
1452
gnutls_initialized = true;
1459
tempdir_created = true;
1460
if(mkdtemp(tempdir) == NULL){
1461
tempdir_created = false;
1470
if(not init_gpgme(pubkey, seckey, tempdir)){
1471
fprintf(stderr, "init_gpgme failed\n");
1472
exitcode = EXIT_FAILURE;
1475
gpgme_initialized = true;
1482
if(connect_to != NULL){
1483
/* Connect directly, do not use Zeroconf */
1484
/* (Mainly meant for debugging) */
1485
char *address = strrchr(connect_to, ':');
1486
if(address == NULL){
1487
fprintf(stderr, "No colon in address\n");
1488
exitcode = EXIT_FAILURE;
1498
tmpmax = strtoimax(address+1, &tmp, 10);
1499
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1500
or tmpmax != (uint16_t)tmpmax){
1501
fprintf(stderr, "Bad port number\n");
1502
exitcode = EXIT_FAILURE;
1510
port = (uint16_t)tmpmax;
1512
address = connect_to;
1513
/* Colon in address indicates IPv6 */
1515
if(strchr(address, ':') != NULL){
1525
ret = start_mandos_communication(address, port, if_index, af);
1527
exitcode = EXIT_FAILURE;
1529
exitcode = EXIT_SUCCESS;
629
1539
AvahiServerConfig config;
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 */
1540
/* Do not publish any local Zeroconf records */
676
1541
avahi_server_config_init(&config);
677
1542
config.publish_hinfo = 0;
678
1543
config.publish_addresses = 0;
679
1544
config.publish_workstation = 0;
680
1545
config.publish_domain = 0;
682
1547
/* Allocate a new server */
683
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
684
&config, NULL, NULL, &error);
686
/* Free the configuration data */
1548
mc.server = avahi_server_new(avahi_simple_poll_get
1549
(mc.simple_poll), &config, NULL,
1552
/* Free the Avahi configuration data */
687
1553
avahi_server_config_free(&config);
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);
1556
/* Check if creating the Avahi server object succeeded */
1557
if(mc.server == NULL){
1558
fprintf(stderr, "Failed to create Avahi server: %s\n",
1559
avahi_strerror(error));
1560
exitcode = EXIT_FAILURE;
1568
/* Create the Avahi service browser */
1569
sb = avahi_s_service_browser_new(mc.server, if_index,
1570
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1571
NULL, 0, browse_callback, NULL);
1573
fprintf(stderr, "Failed to create service browser: %s\n",
1574
avahi_strerror(avahi_server_errno(mc.server)));
1575
exitcode = EXIT_FAILURE;
1583
/* Run the main loop */
1586
fprintf(stderr, "Starting Avahi loop search\n");
1589
avahi_simple_poll_loop(mc.simple_poll);
1594
fprintf(stderr, "%s exiting\n", argv[0]);
1597
/* Cleanup things */
1599
avahi_s_service_browser_free(sb);
1601
if(mc.server != NULL)
1602
avahi_server_free(mc.server);
1604
if(mc.simple_poll != NULL)
1605
avahi_simple_poll_free(mc.simple_poll);
1607
if(gnutls_initialized){
1608
gnutls_certificate_free_credentials(mc.cred);
1609
gnutls_global_deinit();
1610
gnutls_dh_params_deinit(mc.dh_params);
1613
if(gpgme_initialized){
1614
gpgme_release(mc.ctx);
1617
/* Take down the network interface */
1618
if(take_down_interface){
1619
/* Re-raise priviliges */
1626
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1628
perror("ioctl SIOCGIFFLAGS");
1629
} else if(network.ifr_flags & IFF_UP) {
1630
network.ifr_flags &= ~IFF_UP; /* clear flag */
1631
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1633
perror("ioctl SIOCSIFFLAGS");
1636
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1640
/* Lower privileges permanently */
1649
/* Removes the temp directory used by GPGME */
1650
if(tempdir_created){
1652
struct dirent *direntry;
1653
d = opendir(tempdir);
1655
if(errno != ENOENT){
1660
direntry = readdir(d);
1661
if(direntry == NULL){
1664
/* Skip "." and ".." */
1665
if(direntry->d_name[0] == '.'
1666
and (direntry->d_name[1] == '\0'
1667
or (direntry->d_name[1] == '.'
1668
and direntry->d_name[2] == '\0'))){
1671
char *fullname = NULL;
1672
ret = asprintf(&fullname, "%s/%s", tempdir,
1678
ret = remove(fullname);
1680
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1687
ret = rmdir(tempdir);
1688
if(ret == -1 and errno != ENOENT){
1694
sigemptyset(&old_sigterm_action.sa_mask);
1695
old_sigterm_action.sa_handler = SIG_DFL;
1696
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1697
&old_sigterm_action,
1700
perror("sigaction");
1703
ret = raise(signal_received);
1704
} while(ret != 0 and errno == EINTR);
1709
TEMP_FAILURE_RETRY(pause());