119
284
/* Create new empty GPGME data buffer for the plaintext */
120
285
rc = gpgme_data_new(&dh_plain);
121
if (rc != GPG_ERR_NO_ERROR){
286
if(rc != GPG_ERR_NO_ERROR){
122
287
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
123
288
gpgme_strsource(rc), gpgme_strerror(rc));
127
/* Create new GPGME "context" */
128
rc = gpgme_new(&ctx);
129
if (rc != GPG_ERR_NO_ERROR){
130
fprintf(stderr, "bad gpgme_new: %s: %s\n",
131
gpgme_strsource(rc), gpgme_strerror(rc));
135
/* Decrypt data from the FILE pointer to the plaintext data buffer */
136
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
137
if (rc != GPG_ERR_NO_ERROR){
289
gpgme_data_release(dh_crypto);
293
/* Decrypt data from the cryptotext data buffer to the plaintext
295
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
296
if(rc != GPG_ERR_NO_ERROR){
138
297
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
139
298
gpgme_strsource(rc), gpgme_strerror(rc));
144
fprintf(stderr, "decryption of gpg packet succeeded\n");
148
gpgme_decrypt_result_t result;
149
result = gpgme_op_decrypt_result(ctx);
151
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
153
fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
154
fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
155
if(result->file_name != NULL){
156
fprintf(stderr, "File name: %s\n", result->file_name);
158
gpgme_recipient_t recipient;
159
recipient = result->recipients;
299
plaintext_length = -1;
301
gpgme_decrypt_result_t result;
302
result = gpgme_op_decrypt_result(mc.ctx);
304
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
306
fprintf(stderr, "Unsupported algorithm: %s\n",
307
result->unsupported_algorithm);
308
fprintf(stderr, "Wrong key usage: %u\n",
309
result->wrong_key_usage);
310
if(result->file_name != NULL){
311
fprintf(stderr, "File name: %s\n", result->file_name);
313
gpgme_recipient_t recipient;
314
recipient = result->recipients;
161
315
while(recipient != NULL){
162
316
fprintf(stderr, "Public key algorithm: %s\n",
163
317
gpgme_pubkey_algo_name(recipient->pubkey_algo));
164
318
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
165
319
fprintf(stderr, "Secret key available: %s\n",
166
recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
320
recipient->status == GPG_ERR_NO_SECKEY
167
322
recipient = recipient->next;
173
/* Delete the GPGME FILE pointer cryptotext data buffer */
174
gpgme_data_release(dh_crypto);
330
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
176
333
/* Seek back to the beginning of the GPGME plaintext data buffer */
177
gpgme_data_seek(dh_plain, 0, SEEK_SET);
334
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
335
perror("gpgme_data_seek");
336
plaintext_length = -1;
181
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
182
*new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
183
if (*new_packet == NULL){
187
new_packet_capacity += BUFFER_SIZE;
342
plaintext_capacity = incbuffer(plaintext,
343
(size_t)plaintext_length,
345
if(plaintext_capacity == 0){
347
plaintext_length = -1;
190
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
351
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
191
353
/* Print the data, if any */
193
/* If password is empty, then a incorrect error will be printed */
197
359
perror("gpgme_data_read");
200
new_packet_length += ret;
203
/* FIXME: check characters before printing to screen so to not print
204
terminal control characters */
206
/* fprintf(stderr, "decrypted password is: "); */
207
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
208
/* fprintf(stderr, "\n"); */
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);
211
379
/* Delete the GPGME plaintext data buffer */
212
380
gpgme_data_release(dh_plain);
213
return new_packet_length;
381
return plaintext_length;
216
static const char * safer_gnutls_strerror (int value) {
217
const char *ret = gnutls_strerror (value);
384
static const char * safer_gnutls_strerror(int value){
385
const char *ret = gnutls_strerror(value); /* Spurious warning from
386
-Wunreachable-code */
219
388
ret = "(unknown)";
223
void debuggnutls(int level, const char* string){
224
fprintf(stderr, "%s", string);
392
/* GnuTLS log function callback */
393
static void debuggnutls(__attribute__((unused)) int level,
395
fprintf(stderr, "GnuTLS: %s", string);
227
int initgnutls(encrypted_session *es){
398
static int init_gnutls_global(const char *pubkeyfilename,
399
const char *seckeyfilename){
232
fprintf(stderr, "Initializing gnutls\n");
403
fprintf(stderr, "Initializing GnuTLS\n");
236
if ((ret = gnutls_global_init ())
237
!= GNUTLS_E_SUCCESS) {
238
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
406
ret = gnutls_global_init();
407
if(ret != GNUTLS_E_SUCCESS){
408
fprintf(stderr, "GnuTLS global_init: %s\n",
409
safer_gnutls_strerror(ret));
414
/* "Use a log level over 10 to enable all debugging options."
243
417
gnutls_global_set_log_level(11);
244
418
gnutls_global_set_log_function(debuggnutls);
248
/* openpgp credentials */
249
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
250
!= GNUTLS_E_SUCCESS) {
251
fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
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();
256
fprintf(stderr, "Attempting to use openpgp certificate %s"
257
" and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
434
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
435
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
260
439
ret = gnutls_certificate_set_openpgp_key_file
261
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
262
if (ret != GNUTLS_E_SUCCESS) {
264
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
265
ret, CERTFILE, KEYFILE);
266
fprintf(stdout, "The Error is: %s\n",
267
safer_gnutls_strerror(ret));
271
//Gnutls server initialization
272
if ((ret = gnutls_dh_params_init (&es->dh_params))
273
!= GNUTLS_E_SUCCESS) {
274
fprintf (stderr, "Error in dh parameter initialization: %s\n",
275
safer_gnutls_strerror(ret));
279
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
280
!= GNUTLS_E_SUCCESS) {
281
fprintf (stderr, "Error in prime generation: %s\n",
282
safer_gnutls_strerror(ret));
286
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
288
// Gnutls session creation
289
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
290
!= GNUTLS_E_SUCCESS){
291
fprintf(stderr, "Error in gnutls session initialization: %s\n",
292
safer_gnutls_strerror(ret));
295
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
296
!= GNUTLS_E_SUCCESS) {
297
fprintf(stderr, "Syntax error at: %s\n", err);
298
fprintf(stderr, "Gnutls error: %s\n",
299
safer_gnutls_strerror(ret));
303
if ((ret = gnutls_credentials_set
304
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
305
!= GNUTLS_E_SUCCESS) {
306
fprintf(stderr, "Error setting a credentials set: %s\n",
307
safer_gnutls_strerror(ret));
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){
487
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
488
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);
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",
519
safer_gnutls_strerror(ret));
520
gnutls_deinit(*session);
311
524
/* ignore client certificate if any. */
312
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
525
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
314
gnutls_dh_set_prime_bits (es->session, DH_BITS);
527
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
319
void empty_log(AvahiLogLevel level, const char *txt){}
532
/* Avahi log function callback */
533
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
534
__attribute__((unused)) const char *txt){}
321
int start_mandos_communication(char *ip, uint16_t port){
323
struct sockaddr_in6 to;
324
encrypted_session es;
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;
325
546
char *buffer = NULL;
326
char *decrypted_buffer;
547
char *decrypted_buffer = NULL;
327
548
size_t buffer_length = 0;
328
549
size_t buffer_capacity = 0;
329
ssize_t decrypted_buffer_size;
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);
333
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
577
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
336
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
581
tcp_sd = socket(pf, SOCK_STREAM, 0);
338
583
perror("socket");
343
fprintf(stderr, "Binding to interface %s\n", interface);
346
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
348
perror("setsockopt bindtodevice");
352
memset(&to,0,sizeof(to));
353
to.sin6_family = AF_INET6;
354
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
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);
356
600
perror("inet_pton");
360
604
fprintf(stderr, "Bad address: %s\n", ip);
363
to.sin6_port = htons(port);
364
to.sin6_scope_id = if_nametoindex(interface);
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 */
367
fprintf(stderr, "Connection to: %s\n", ip);
370
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
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 */
372
675
perror("connect");
376
ret = initgnutls (&es);
383
gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
386
fprintf(stderr, "Establishing tls session with %s\n", ip);
390
ret = gnutls_handshake (es.session);
392
if (ret != GNUTLS_E_SUCCESS){
393
fprintf(stderr, "\n*** Handshake failed ***\n");
399
//Retrieve gpg packet that contains the wanted password
402
fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
683
const char *out = mandos_protocol_version;
406
if (buffer_length + BUFFER_SIZE > buffer_capacity){
407
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
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){
412
buffer_capacity += BUFFER_SIZE;
415
ret = gnutls_record_recv
416
(es.session, buffer+buffer_length, BUFFER_SIZE);
711
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 */
742
fprintf(stderr, "Retrieving OpenPGP 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,
422
770
case GNUTLS_E_INTERRUPTED:
423
771
case GNUTLS_E_AGAIN:
425
773
case GNUTLS_E_REHANDSHAKE:
426
ret = gnutls_handshake (es.session);
428
fprintf(stderr, "\n*** Handshake failed ***\n");
775
ret = gnutls_handshake(session);
780
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
782
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
435
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
437
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
788
fprintf(stderr, "Unknown error while reading data from"
789
" encrypted session with Mandos server\n");
790
gnutls_bye(session, GNUTLS_SHUT_RDWR);
441
buffer_length += ret;
794
buffer_length += (size_t) sret;
445
if (buffer_length > 0){
446
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
447
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
448
free(decrypted_buffer);
457
fprintf(stderr, "Closing tls session\n");
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;
815
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,
829
if(ret == 0 and ferror(stdout)){
831
fprintf(stderr, "Error writing encrypted data: %s\n",
836
written += (size_t)ret;
842
/* Shutdown procedure */
845
free(decrypted_buffer);
461
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
464
gnutls_deinit (es.session);
465
gnutls_certificate_free_credentials (es.cred);
466
gnutls_global_deinit ();
848
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
853
gnutls_deinit(session);
470
static AvahiSimplePoll *simple_poll = NULL;
471
static AvahiServer *server = NULL;
473
static void resolve_callback(
474
AvahiSServiceResolver *r,
475
AVAHI_GCC_UNUSED AvahiIfIndex interface,
476
AVAHI_GCC_UNUSED AvahiProtocol protocol,
477
AvahiResolverEvent event,
481
const char *host_name,
482
const AvahiAddress *address,
484
AvahiStringList *txt,
485
AvahiLookupResultFlags flags,
486
AVAHI_GCC_UNUSED void* userdata) {
490
/* Called whenever a service has been resolved successfully or timed out */
493
case AVAHI_RESOLVER_FAILURE:
494
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)));
497
case AVAHI_RESOLVER_FOUND: {
498
char ip[AVAHI_ADDRESS_STR_MAX];
499
avahi_address_snprint(ip, sizeof(ip), address);
501
fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
503
int ret = start_mandos_communication(ip, port);
511
avahi_s_service_resolver_free(r);
514
static void browse_callback(
515
AvahiSServiceBrowser *b,
516
AvahiIfIndex interface,
517
AvahiProtocol protocol,
518
AvahiBrowserEvent event,
522
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
525
AvahiServer *s = userdata;
528
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
532
case AVAHI_BROWSER_FAILURE:
534
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
535
avahi_simple_poll_quit(simple_poll);
538
case AVAHI_BROWSER_NEW:
539
/* We ignore the returned resolver object. In the callback
540
function we free it. If the server is terminated before
541
the callback function is called the server will free
542
the resolver for us. */
544
if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
545
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
549
case AVAHI_BROWSER_REMOVE:
552
case AVAHI_BROWSER_ALL_FOR_NOW:
553
case AVAHI_BROWSER_CACHE_EXHAUSTED:
558
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
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){
876
/* Called whenever a service has been resolved successfully or
885
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)));
891
case AVAHI_RESOLVER_FOUND:
893
char ip[AVAHI_ADDRESS_STR_MAX];
894
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);
900
int ret = start_mandos_communication(ip, port, interface,
901
avahi_proto_to_af(proto));
903
avahi_simple_poll_quit(mc.simple_poll);
907
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;
559
1442
AvahiServerConfig config;
560
AvahiSServiceBrowser *sb = NULL;
563
int returncode = EXIT_SUCCESS;
566
static struct option long_options[] = {
567
{"debug", no_argument, (int *)&debug, 1},
568
{"interface", required_argument, 0, 'i'},
571
int option_index = 0;
572
ret = getopt_long (argc, argv, "i:", long_options, &option_index);
590
avahi_set_log_function(empty_log);
593
/* Initialize the psuedo-RNG */
596
/* Allocate main loop object */
597
if (!(simple_poll = avahi_simple_poll_new())) {
598
fprintf(stderr, "Failed to create simple poll object.\n");
603
/* Do not publish any local records */
1443
/* Do not publish any local Zeroconf records */
604
1444
avahi_server_config_init(&config);
605
1445
config.publish_hinfo = 0;
606
1446
config.publish_addresses = 0;
607
1447
config.publish_workstation = 0;
608
1448
config.publish_domain = 0;
610
1450
/* Allocate a new server */
611
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
613
/* Free the configuration data */
1451
mc.server = avahi_server_new(avahi_simple_poll_get
1452
(mc.simple_poll), &config, NULL,
1455
/* Free the Avahi configuration data */
614
1456
avahi_server_config_free(&config);
616
/* Check if creating the server object succeeded */
618
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
619
returncode = EXIT_FAILURE;
623
/* Create the service browser */
624
if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
625
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
626
returncode = EXIT_FAILURE;
630
/* Run the main loop */
633
fprintf(stderr, "Starting avahi loop search\n");
636
avahi_simple_poll_loop(simple_poll);
641
fprintf(stderr, "%s exiting\n", argv[0]);
646
avahi_s_service_browser_free(sb);
649
avahi_server_free(server);
652
avahi_simple_poll_free(simple_poll);
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());