116
281
/* Create new empty GPGME data buffer for the plaintext */
117
282
rc = gpgme_data_new(&dh_plain);
118
if (rc != GPG_ERR_NO_ERROR){
283
if(rc != GPG_ERR_NO_ERROR){
119
284
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
120
285
gpgme_strsource(rc), gpgme_strerror(rc));
124
/* Create new GPGME "context" */
125
rc = gpgme_new(&ctx);
126
if (rc != GPG_ERR_NO_ERROR){
127
fprintf(stderr, "bad gpgme_new: %s: %s\n",
128
gpgme_strsource(rc), gpgme_strerror(rc));
132
/* Decrypt data from the FILE pointer to the plaintext data buffer */
133
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
134
if (rc != GPG_ERR_NO_ERROR){
286
gpgme_data_release(dh_crypto);
290
/* Decrypt data from the cryptotext data buffer to the plaintext
292
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
293
if(rc != GPG_ERR_NO_ERROR){
135
294
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
136
295
gpgme_strsource(rc), gpgme_strerror(rc));
141
fprintf(stderr, "decryption of gpg packet succeeded\n");
145
gpgme_decrypt_result_t result;
146
result = gpgme_op_decrypt_result(ctx);
148
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
150
fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
151
fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
152
if(result->file_name != NULL){
153
fprintf(stderr, "File name: %s\n", result->file_name);
155
gpgme_recipient_t recipient;
156
recipient = result->recipients;
296
plaintext_length = -1;
298
gpgme_decrypt_result_t result;
299
result = gpgme_op_decrypt_result(mc.ctx);
301
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
303
fprintf(stderr, "Unsupported algorithm: %s\n",
304
result->unsupported_algorithm);
305
fprintf(stderr, "Wrong key usage: %u\n",
306
result->wrong_key_usage);
307
if(result->file_name != NULL){
308
fprintf(stderr, "File name: %s\n", result->file_name);
310
gpgme_recipient_t recipient;
311
recipient = result->recipients;
158
312
while(recipient != NULL){
159
313
fprintf(stderr, "Public key algorithm: %s\n",
160
314
gpgme_pubkey_algo_name(recipient->pubkey_algo));
161
315
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
162
316
fprintf(stderr, "Secret key available: %s\n",
163
recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
317
recipient->status == GPG_ERR_NO_SECKEY
164
319
recipient = recipient->next;
170
/* Delete the GPGME FILE pointer cryptotext data buffer */
171
gpgme_data_release(dh_crypto);
327
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
173
330
/* Seek back to the beginning of the GPGME plaintext data buffer */
174
gpgme_data_seek(dh_plain, 0, SEEK_SET);
331
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
332
perror("gpgme_data_seek");
333
plaintext_length = -1;
178
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
179
*new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
180
if (*new_packet == NULL){
184
new_packet_capacity += BUFFER_SIZE;
339
plaintext_capacity = incbuffer(plaintext,
340
(size_t)plaintext_length,
342
if(plaintext_capacity == 0){
344
plaintext_length = -1;
187
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
348
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
188
350
/* Print the data, if any */
190
/* If password is empty, then a incorrect error will be printed */
194
356
perror("gpgme_data_read");
357
plaintext_length = -1;
197
new_packet_length += ret;
360
plaintext_length += ret;
201
fprintf(stderr, "decrypted password is: %s\n", *new_packet);
364
fprintf(stderr, "Decrypted password is: ");
365
for(ssize_t i = 0; i < plaintext_length; i++){
366
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
368
fprintf(stderr, "\n");
204
/* Delete the GPGME plaintext data buffer */
373
/* Delete the GPGME cryptotext data buffer */
374
gpgme_data_release(dh_crypto);
376
/* Delete the GPGME plaintext data buffer */
205
377
gpgme_data_release(dh_plain);
206
return new_packet_length;
378
return plaintext_length;
209
static const char * safer_gnutls_strerror (int value) {
210
const char *ret = gnutls_strerror (value);
381
static const char * safer_gnutls_strerror(int value){
382
const char *ret = gnutls_strerror(value); /* Spurious warning from
383
-Wunreachable-code */
212
385
ret = "(unknown)";
216
void debuggnutls(int level, const char* string){
217
fprintf(stderr, "%s", string);
389
/* GnuTLS log function callback */
390
static void debuggnutls(__attribute__((unused)) int level,
392
fprintf(stderr, "GnuTLS: %s", string);
220
int initgnutls(encrypted_session *es){
395
static int init_gnutls_global(const char *pubkeyfilename,
396
const char *seckeyfilename){
225
fprintf(stderr, "Initializing gnutls\n");
400
fprintf(stderr, "Initializing GnuTLS\n");
229
if ((ret = gnutls_global_init ())
230
!= GNUTLS_E_SUCCESS) {
231
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
403
ret = gnutls_global_init();
404
if(ret != GNUTLS_E_SUCCESS){
405
fprintf(stderr, "GnuTLS global_init: %s\n",
406
safer_gnutls_strerror(ret));
411
/* "Use a log level over 10 to enable all debugging options."
236
414
gnutls_global_set_log_level(11);
237
415
gnutls_global_set_log_function(debuggnutls);
241
/* openpgp credentials */
242
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
243
!= GNUTLS_E_SUCCESS) {
244
fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
418
/* OpenPGP credentials */
419
gnutls_certificate_allocate_credentials(&mc.cred);
420
if(ret != GNUTLS_E_SUCCESS){
421
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
425
safer_gnutls_strerror(ret));
426
gnutls_global_deinit();
249
fprintf(stderr, "Attempting to use openpgp certificate %s"
250
" and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
431
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
432
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
253
436
ret = gnutls_certificate_set_openpgp_key_file
254
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
255
if (ret != GNUTLS_E_SUCCESS) {
257
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
258
ret, CERTFILE, KEYFILE);
259
fprintf(stdout, "The Error is: %s\n",
260
safer_gnutls_strerror(ret));
264
//Gnutls server initialization
265
if ((ret = gnutls_dh_params_init (&es->dh_params))
266
!= GNUTLS_E_SUCCESS) {
267
fprintf (stderr, "Error in dh parameter initialization: %s\n",
268
safer_gnutls_strerror(ret));
272
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
273
!= GNUTLS_E_SUCCESS) {
274
fprintf (stderr, "Error in prime generation: %s\n",
275
safer_gnutls_strerror(ret));
279
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
281
// Gnutls session creation
282
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
283
!= GNUTLS_E_SUCCESS){
284
fprintf(stderr, "Error in gnutls session initialization: %s\n",
285
safer_gnutls_strerror(ret));
288
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
289
!= GNUTLS_E_SUCCESS) {
290
fprintf(stderr, "Syntax error at: %s\n", err);
291
fprintf(stderr, "Gnutls error: %s\n",
292
safer_gnutls_strerror(ret));
296
if ((ret = gnutls_credentials_set
297
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
298
!= GNUTLS_E_SUCCESS) {
299
fprintf(stderr, "Error setting a credentials set: %s\n",
300
safer_gnutls_strerror(ret));
437
(mc.cred, pubkeyfilename, seckeyfilename,
438
GNUTLS_OPENPGP_FMT_BASE64);
439
if(ret != GNUTLS_E_SUCCESS){
441
"Error[%d] while reading the OpenPGP key pair ('%s',"
442
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
443
fprintf(stderr, "The GnuTLS error is: %s\n",
444
safer_gnutls_strerror(ret));
448
/* GnuTLS server initialization */
449
ret = gnutls_dh_params_init(&mc.dh_params);
450
if(ret != GNUTLS_E_SUCCESS){
451
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
452
" %s\n", safer_gnutls_strerror(ret));
455
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
456
if(ret != GNUTLS_E_SUCCESS){
457
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
458
safer_gnutls_strerror(ret));
462
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
468
gnutls_certificate_free_credentials(mc.cred);
469
gnutls_global_deinit();
470
gnutls_dh_params_deinit(mc.dh_params);
474
static int init_gnutls_session(gnutls_session_t *session){
476
/* GnuTLS session creation */
477
ret = gnutls_init(session, GNUTLS_SERVER);
478
if(ret != GNUTLS_E_SUCCESS){
479
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
480
safer_gnutls_strerror(ret));
485
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
486
if(ret != GNUTLS_E_SUCCESS){
487
fprintf(stderr, "Syntax error at: %s\n", err);
488
fprintf(stderr, "GnuTLS error: %s\n",
489
safer_gnutls_strerror(ret));
490
gnutls_deinit(*session);
495
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
497
if(ret != GNUTLS_E_SUCCESS){
498
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
499
safer_gnutls_strerror(ret));
500
gnutls_deinit(*session);
304
504
/* ignore client certificate if any. */
305
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
505
gnutls_certificate_server_set_request(*session,
307
gnutls_dh_set_prime_bits (es->session, DH_BITS);
508
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
312
void empty_log(AvahiLogLevel level, const char *txt){}
314
int start_mandos_communication(char *ip, uint16_t port){
316
struct sockaddr_in6 to;
317
encrypted_session es;
513
/* Avahi log function callback */
514
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
515
__attribute__((unused)) const char *txt){}
517
sig_atomic_t quit_now = 0;
518
int signal_received = 0;
520
/* Called when a Mandos server is found */
521
static int start_mandos_communication(const char *ip, uint16_t port,
522
AvahiIfIndex if_index,
524
int ret, tcp_sd = -1;
527
struct sockaddr_in in;
528
struct sockaddr_in6 in6;
318
530
char *buffer = NULL;
319
531
char *decrypted_buffer;
320
532
size_t buffer_length = 0;
321
533
size_t buffer_capacity = 0;
322
ssize_t decrypted_buffer_size;
324
const char interface[] = "eth0";
536
gnutls_session_t session;
537
int pf; /* Protocol family */
551
fprintf(stderr, "Bad address family: %d\n", af);
555
ret = init_gnutls_session(&session);
327
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
561
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
330
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
565
tcp_sd = socket(pf, SOCK_STREAM, 0);
332
567
perror("socket");
337
fprintf(stderr, "Binding to interface %s\n", interface);
340
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
342
perror("setsockopt bindtodevice");
346
memset(&to,0,sizeof(to));
347
to.sin6_family = AF_INET6;
348
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
576
memset(&to, 0, sizeof(to));
578
to.in6.sin6_family = (sa_family_t)af;
579
ret = inet_pton(af, ip, &to.in6.sin6_addr);
581
to.in.sin_family = (sa_family_t)af;
582
ret = inet_pton(af, ip, &to.in.sin_addr);
350
585
perror("inet_pton");
354
590
fprintf(stderr, "Bad address: %s\n", ip);
357
to.sin6_port = htons(port);
358
to.sin6_scope_id = if_nametoindex(interface);
595
to.in6.sin6_port = htons(port); /* Spurious warnings from
597
-Wunreachable-code */
599
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
600
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
602
if(if_index == AVAHI_IF_UNSPEC){
603
fprintf(stderr, "An IPv6 link-local address is incomplete"
604
" without a network interface\n");
608
/* Set the network interface number as scope */
609
to.in6.sin6_scope_id = (uint32_t)if_index;
612
to.in.sin_port = htons(port); /* Spurious warnings from
614
-Wunreachable-code */
361
fprintf(stderr, "Connection to: %s\n", ip);
364
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
622
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
623
char interface[IF_NAMESIZE];
624
if(if_indextoname((unsigned int)if_index, interface) == NULL){
625
perror("if_indextoname");
627
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
628
ip, interface, port);
631
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
634
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
635
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
638
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
641
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
647
if(strcmp(addrstr, ip) != 0){
648
fprintf(stderr, "Canonical address form: %s\n", addrstr);
658
ret = connect(tcp_sd, &to.in6, sizeof(to));
660
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
366
663
perror("connect");
370
ret = initgnutls (&es);
377
gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
380
fprintf(stderr, "Establishing tls session with %s\n", ip);
384
ret = gnutls_handshake (es.session);
386
if (ret != GNUTLS_E_SUCCESS){
387
fprintf(stderr, "\n*** Handshake failed ***\n");
393
//Retrieve gpg packet that contains the wanted password
396
fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
672
const char *out = mandos_protocol_version;
400
if (buffer_length + BUFFER_SIZE > buffer_capacity){
401
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
675
size_t out_size = strlen(out);
676
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
677
out_size - written));
683
written += (size_t)ret;
684
if(written < out_size){
687
if(out == mandos_protocol_version){
406
buffer_capacity += BUFFER_SIZE;
409
ret = gnutls_record_recv
410
(es.session, buffer+buffer_length, BUFFER_SIZE);
701
fprintf(stderr, "Establishing TLS session with %s\n", ip);
708
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
715
ret = gnutls_handshake(session);
719
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
721
if(ret != GNUTLS_E_SUCCESS){
723
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
730
/* Read OpenPGP packet that contains the wanted password */
733
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
743
buffer_capacity = incbuffer(&buffer, buffer_length,
745
if(buffer_capacity == 0){
755
sret = gnutls_record_recv(session, buffer+buffer_length,
416
762
case GNUTLS_E_INTERRUPTED:
417
763
case GNUTLS_E_AGAIN:
419
765
case GNUTLS_E_REHANDSHAKE:
420
ret = gnutls_handshake (es.session);
422
fprintf(stderr, "\n*** Handshake failed ***\n");
767
ret = gnutls_handshake(session);
772
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
774
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
429
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
781
fprintf(stderr, "Unknown error while reading data from"
782
" encrypted session with Mandos server\n");
431
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
784
gnutls_bye(session, GNUTLS_SHUT_RDWR);
435
buffer_length += ret;
788
buffer_length += (size_t) sret;
439
if (buffer_length > 0){
440
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
441
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
793
fprintf(stderr, "Closing TLS session\n");
800
gnutls_bye(session, GNUTLS_SHUT_RDWR);
806
if(buffer_length > 0){
807
ssize_t decrypted_buffer_size;
808
decrypted_buffer_size = pgp_packet_decrypt(buffer,
811
if(decrypted_buffer_size >= 0){
814
while(written < (size_t) decrypted_buffer_size){
819
ret = (int)fwrite(decrypted_buffer + written, 1,
820
(size_t)decrypted_buffer_size - written,
822
if(ret == 0 and ferror(stdout)){
824
fprintf(stderr, "Error writing encrypted data: %s\n",
830
written += (size_t)ret;
442
832
free(decrypted_buffer);
451
fprintf(stderr, "Closing tls session\n");
840
/* Shutdown procedure */
455
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
458
gnutls_deinit (es.session);
459
gnutls_certificate_free_credentials (es.cred);
460
gnutls_global_deinit ();
845
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
850
gnutls_deinit(session);
464
static AvahiSimplePoll *simple_poll = NULL;
465
static AvahiServer *server = NULL;
467
static void resolve_callback(
468
AvahiSServiceResolver *r,
469
AVAHI_GCC_UNUSED AvahiIfIndex interface,
470
AVAHI_GCC_UNUSED AvahiProtocol protocol,
471
AvahiResolverEvent event,
475
const char *host_name,
476
const AvahiAddress *address,
478
AvahiStringList *txt,
479
AvahiLookupResultFlags flags,
480
AVAHI_GCC_UNUSED void* userdata) {
484
/* Called whenever a service has been resolved successfully or timed out */
487
case AVAHI_RESOLVER_FAILURE:
488
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)));
491
case AVAHI_RESOLVER_FOUND: {
492
char ip[AVAHI_ADDRESS_STR_MAX];
493
avahi_address_snprint(ip, sizeof(ip), address);
495
fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
497
int ret = start_mandos_communication(ip, port);
505
avahi_s_service_resolver_free(r);
508
static void browse_callback(
509
AvahiSServiceBrowser *b,
510
AvahiIfIndex interface,
511
AvahiProtocol protocol,
512
AvahiBrowserEvent event,
516
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
519
AvahiServer *s = userdata;
522
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
526
case AVAHI_BROWSER_FAILURE:
528
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
529
avahi_simple_poll_quit(simple_poll);
532
case AVAHI_BROWSER_NEW:
533
/* We ignore the returned resolver object. In the callback
534
function we free it. If the server is terminated before
535
the callback function is called the server will free
536
the resolver for us. */
538
if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
539
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
543
case AVAHI_BROWSER_REMOVE:
546
case AVAHI_BROWSER_ALL_FOR_NOW:
547
case AVAHI_BROWSER_CACHE_EXHAUSTED:
552
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
857
static void resolve_callback(AvahiSServiceResolver *r,
858
AvahiIfIndex interface,
860
AvahiResolverEvent event,
864
const char *host_name,
865
const AvahiAddress *address,
867
AVAHI_GCC_UNUSED AvahiStringList *txt,
868
AVAHI_GCC_UNUSED AvahiLookupResultFlags
870
AVAHI_GCC_UNUSED void* userdata){
873
/* Called whenever a service has been resolved successfully or
882
case AVAHI_RESOLVER_FAILURE:
883
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
884
" of type '%s' in domain '%s': %s\n", name, type, domain,
885
avahi_strerror(avahi_server_errno(mc.server)));
888
case AVAHI_RESOLVER_FOUND:
890
char ip[AVAHI_ADDRESS_STR_MAX];
891
avahi_address_snprint(ip, sizeof(ip), address);
893
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
894
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
895
ip, (intmax_t)interface, port);
897
int ret = start_mandos_communication(ip, port, interface,
898
avahi_proto_to_af(proto));
900
avahi_simple_poll_quit(mc.simple_poll);
904
avahi_s_service_resolver_free(r);
907
static void browse_callback(AvahiSServiceBrowser *b,
908
AvahiIfIndex interface,
909
AvahiProtocol protocol,
910
AvahiBrowserEvent event,
914
AVAHI_GCC_UNUSED AvahiLookupResultFlags
916
AVAHI_GCC_UNUSED void* userdata){
919
/* Called whenever a new services becomes available on the LAN or
920
is removed from the LAN */
928
case AVAHI_BROWSER_FAILURE:
930
fprintf(stderr, "(Avahi browser) %s\n",
931
avahi_strerror(avahi_server_errno(mc.server)));
932
avahi_simple_poll_quit(mc.simple_poll);
935
case AVAHI_BROWSER_NEW:
936
/* We ignore the returned Avahi resolver object. In the callback
937
function we free it. If the Avahi server is terminated before
938
the callback function is called the Avahi server will free the
941
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
942
name, type, domain, protocol, 0,
943
resolve_callback, NULL) == NULL)
944
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
945
name, avahi_strerror(avahi_server_errno(mc.server)));
948
case AVAHI_BROWSER_REMOVE:
951
case AVAHI_BROWSER_ALL_FOR_NOW:
952
case AVAHI_BROWSER_CACHE_EXHAUSTED:
954
fprintf(stderr, "No Mandos server found, still searching...\n");
960
/* stop main loop after sigterm has been called */
961
static void handle_sigterm(int sig){
966
signal_received = sig;
967
int old_errno = errno;
968
if(mc.simple_poll != NULL){
969
avahi_simple_poll_quit(mc.simple_poll);
974
int main(int argc, char *argv[]){
975
AvahiSServiceBrowser *sb = NULL;
980
int exitcode = EXIT_SUCCESS;
981
const char *interface = "eth0";
982
struct ifreq network;
984
bool take_down_interface = false;
987
char *connect_to = NULL;
988
char tempdir[] = "/tmp/mandosXXXXXX";
989
bool tempdir_created = false;
990
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
991
const char *seckey = PATHDIR "/" SECKEY;
992
const char *pubkey = PATHDIR "/" PUBKEY;
994
bool gnutls_initialized = false;
995
bool gpgme_initialized = false;
998
struct sigaction old_sigterm_action;
999
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1002
struct argp_option options[] = {
1003
{ .name = "debug", .key = 128,
1004
.doc = "Debug mode", .group = 3 },
1005
{ .name = "connect", .key = 'c',
1006
.arg = "ADDRESS:PORT",
1007
.doc = "Connect directly to a specific Mandos server",
1009
{ .name = "interface", .key = 'i',
1011
.doc = "Network interface that will be used to search for"
1014
{ .name = "seckey", .key = 's',
1016
.doc = "OpenPGP secret key file base name",
1018
{ .name = "pubkey", .key = 'p',
1020
.doc = "OpenPGP public key file base name",
1022
{ .name = "dh-bits", .key = 129,
1024
.doc = "Bit length of the prime number used in the"
1025
" Diffie-Hellman key exchange",
1027
{ .name = "priority", .key = 130,
1029
.doc = "GnuTLS priority string for the TLS handshake",
1031
{ .name = "delay", .key = 131,
1033
.doc = "Maximum delay to wait for interface startup",
1038
error_t parse_opt(int key, char *arg,
1039
struct argp_state *state){
1041
case 128: /* --debug */
1044
case 'c': /* --connect */
1047
case 'i': /* --interface */
1050
case 's': /* --seckey */
1053
case 'p': /* --pubkey */
1056
case 129: /* --dh-bits */
1058
tmpmax = strtoimax(arg, &tmp, 10);
1059
if(errno != 0 or tmp == arg or *tmp != '\0'
1060
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1061
fprintf(stderr, "Bad number of DH bits\n");
1064
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1066
case 130: /* --priority */
1069
case 131: /* --delay */
1071
delay = strtof(arg, &tmp);
1072
if(errno != 0 or tmp == arg or *tmp != '\0'){
1073
fprintf(stderr, "Bad delay\n");
1082
return ARGP_ERR_UNKNOWN;
1087
struct argp argp = { .options = options, .parser = parse_opt,
1089
.doc = "Mandos client -- Get and decrypt"
1090
" passwords from a Mandos server" };
1091
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
1092
if(ret == ARGP_ERR_UNKNOWN){
1093
fprintf(stderr, "Unknown error while parsing arguments\n");
1094
exitcode = EXIT_FAILURE;
1100
avahi_set_log_function(empty_log);
1103
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1104
from the signal handler */
1105
/* Initialize the pseudo-RNG for Avahi */
1106
srand((unsigned int) time(NULL));
1107
mc.simple_poll = avahi_simple_poll_new();
1108
if(mc.simple_poll == NULL){
1109
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1110
exitcode = EXIT_FAILURE;
1114
sigemptyset(&sigterm_action.sa_mask);
1115
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1117
perror("sigaddset");
1118
exitcode = EXIT_FAILURE;
1121
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1123
perror("sigaddset");
1124
exitcode = EXIT_FAILURE;
1127
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1129
perror("sigaddset");
1130
exitcode = EXIT_FAILURE;
1133
/* Need to check if the handler is SIG_IGN before handling:
1134
| [[info:libc:Initial Signal Actions]] |
1135
| [[info:libc:Basic Signal Handling]] |
1137
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1139
perror("sigaction");
1140
return EXIT_FAILURE;
1142
if(old_sigterm_action.sa_handler != SIG_IGN){
1143
ret = sigaction(SIGINT, &sigterm_action, NULL);
1145
perror("sigaction");
1146
exitcode = EXIT_FAILURE;
1150
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1152
perror("sigaction");
1153
return EXIT_FAILURE;
1155
if(old_sigterm_action.sa_handler != SIG_IGN){
1156
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1158
perror("sigaction");
1159
exitcode = EXIT_FAILURE;
1163
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1165
perror("sigaction");
1166
return EXIT_FAILURE;
1168
if(old_sigterm_action.sa_handler != SIG_IGN){
1169
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1171
perror("sigaction");
1172
exitcode = EXIT_FAILURE;
1177
/* If the interface is down, bring it up */
1178
if(interface[0] != '\0'){
1179
if_index = (AvahiIfIndex) if_nametoindex(interface);
1181
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1182
exitcode = EXIT_FAILURE;
1191
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1192
messages to mess up the prompt */
1193
ret = klogctl(8, NULL, 5);
1194
bool restore_loglevel = true;
1196
restore_loglevel = false;
1199
#endif /* __linux__ */
1201
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1204
exitcode = EXIT_FAILURE;
1206
if(restore_loglevel){
1207
ret = klogctl(7, NULL, 0);
1212
#endif /* __linux__ */
1215
strcpy(network.ifr_name, interface);
1216
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1218
perror("ioctl SIOCGIFFLAGS");
1220
if(restore_loglevel){
1221
ret = klogctl(7, NULL, 0);
1226
#endif /* __linux__ */
1227
exitcode = EXIT_FAILURE;
1230
if((network.ifr_flags & IFF_UP) == 0){
1231
network.ifr_flags |= IFF_UP;
1232
take_down_interface = true;
1233
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1235
take_down_interface = false;
1236
perror("ioctl SIOCSIFFLAGS");
1237
exitcode = EXIT_FAILURE;
1239
if(restore_loglevel){
1240
ret = klogctl(7, NULL, 0);
1245
#endif /* __linux__ */
1249
/* sleep checking until interface is running */
1250
for(int i=0; i < delay * 4; i++){
1251
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1253
perror("ioctl SIOCGIFFLAGS");
1254
} else if(network.ifr_flags & IFF_RUNNING){
1257
struct timespec sleeptime = { .tv_nsec = 250000000 };
1258
ret = nanosleep(&sleeptime, NULL);
1259
if(ret == -1 and errno != EINTR){
1260
perror("nanosleep");
1263
if(not take_down_interface){
1264
/* We won't need the socket anymore */
1265
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1271
if(restore_loglevel){
1272
/* Restores kernel loglevel to default */
1273
ret = klogctl(7, NULL, 0);
1278
#endif /* __linux__ */
1288
/* Drop any group privileges we might have, just to be safe */
1295
/* Drop user privileges */
1297
/* Will we need privileges later? */
1298
if(take_down_interface){
1299
/* Drop user privileges temporarily */
1305
/* Drop user privileges permanently */
1316
ret = init_gnutls_global(pubkey, seckey);
1318
fprintf(stderr, "init_gnutls_global failed\n");
1319
exitcode = EXIT_FAILURE;
1322
gnutls_initialized = true;
1329
tempdir_created = true;
1330
if(mkdtemp(tempdir) == NULL){
1331
tempdir_created = false;
1340
if(not init_gpgme(pubkey, seckey, tempdir)){
1341
fprintf(stderr, "init_gpgme failed\n");
1342
exitcode = EXIT_FAILURE;
1345
gpgme_initialized = true;
1352
if(connect_to != NULL){
1353
/* Connect directly, do not use Zeroconf */
1354
/* (Mainly meant for debugging) */
1355
char *address = strrchr(connect_to, ':');
1356
if(address == NULL){
1357
fprintf(stderr, "No colon in address\n");
1358
exitcode = EXIT_FAILURE;
1368
tmpmax = strtoimax(address+1, &tmp, 10);
1369
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1370
or tmpmax != (uint16_t)tmpmax){
1371
fprintf(stderr, "Bad port number\n");
1372
exitcode = EXIT_FAILURE;
1380
port = (uint16_t)tmpmax;
1382
address = connect_to;
1383
/* Colon in address indicates IPv6 */
1385
if(strchr(address, ':') != NULL){
1395
ret = start_mandos_communication(address, port, if_index, af);
1397
exitcode = EXIT_FAILURE;
1399
exitcode = EXIT_SUCCESS;
553
1409
AvahiServerConfig config;
554
AvahiSServiceBrowser *sb = NULL;
555
const char db[] = "--debug";
558
int returncode = EXIT_SUCCESS;
559
char *basename = rindex(argv[0], '/');
560
if(basename == NULL){
566
char *program_name = malloc(strlen(basename) + sizeof(db));
568
if (program_name == NULL){
573
program_name[0] = '\0';
575
for (int i = 1; i < argc; i++){
576
if (not strncmp(argv[i], db, 5)){
577
strcat(strcat(strcat(program_name, db ), "="), basename);
578
if(not strcmp(argv[i], db) or not strcmp(argv[i], program_name)){
586
avahi_set_log_function(empty_log);
589
/* Initialize the psuedo-RNG */
592
/* Allocate main loop object */
593
if (!(simple_poll = avahi_simple_poll_new())) {
594
fprintf(stderr, "Failed to create simple poll object.\n");
599
/* Do not publish any local records */
1410
/* Do not publish any local Zeroconf records */
600
1411
avahi_server_config_init(&config);
601
1412
config.publish_hinfo = 0;
602
1413
config.publish_addresses = 0;
603
1414
config.publish_workstation = 0;
604
1415
config.publish_domain = 0;
606
1417
/* Allocate a new server */
607
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
609
/* Free the configuration data */
1418
mc.server = avahi_server_new(avahi_simple_poll_get
1419
(mc.simple_poll), &config, NULL,
1422
/* Free the Avahi configuration data */
610
1423
avahi_server_config_free(&config);
612
/* Check if creating the server object succeeded */
614
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
615
returncode = EXIT_FAILURE;
619
/* Create the service browser */
620
if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
621
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
622
returncode = EXIT_FAILURE;
626
/* Run the main loop */
629
fprintf(stderr, "Starting avahi loop search\n");
632
avahi_simple_poll_loop(simple_poll);
637
fprintf(stderr, "%s exiting\n", argv[0]);
642
avahi_s_service_browser_free(sb);
645
avahi_server_free(server);
648
avahi_simple_poll_free(simple_poll);
1426
/* Check if creating the Avahi server object succeeded */
1427
if(mc.server == NULL){
1428
fprintf(stderr, "Failed to create Avahi server: %s\n",
1429
avahi_strerror(error));
1430
exitcode = EXIT_FAILURE;
1438
/* Create the Avahi service browser */
1439
sb = avahi_s_service_browser_new(mc.server, if_index,
1440
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1441
NULL, 0, browse_callback, NULL);
1443
fprintf(stderr, "Failed to create service browser: %s\n",
1444
avahi_strerror(avahi_server_errno(mc.server)));
1445
exitcode = EXIT_FAILURE;
1453
/* Run the main loop */
1456
fprintf(stderr, "Starting Avahi loop search\n");
1459
avahi_simple_poll_loop(mc.simple_poll);
1464
fprintf(stderr, "%s exiting\n", argv[0]);
1467
/* Cleanup things */
1469
avahi_s_service_browser_free(sb);
1471
if(mc.server != NULL)
1472
avahi_server_free(mc.server);
1474
if(mc.simple_poll != NULL)
1475
avahi_simple_poll_free(mc.simple_poll);
1477
if(gnutls_initialized){
1478
gnutls_certificate_free_credentials(mc.cred);
1479
gnutls_global_deinit();
1480
gnutls_dh_params_deinit(mc.dh_params);
1483
if(gpgme_initialized){
1484
gpgme_release(mc.ctx);
1487
/* Take down the network interface */
1488
if(take_down_interface){
1489
/* Re-raise priviliges */
1496
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1498
perror("ioctl SIOCGIFFLAGS");
1499
} else if(network.ifr_flags & IFF_UP) {
1500
network.ifr_flags &= ~IFF_UP; /* clear flag */
1501
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1503
perror("ioctl SIOCSIFFLAGS");
1506
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1510
/* Lower privileges, permanently this time */
1519
/* Removes the temp directory used by GPGME */
1520
if(tempdir_created){
1522
struct dirent *direntry;
1523
d = opendir(tempdir);
1525
if(errno != ENOENT){
1530
direntry = readdir(d);
1531
if(direntry == NULL){
1534
/* Skip "." and ".." */
1535
if(direntry->d_name[0] == '.'
1536
and (direntry->d_name[1] == '\0'
1537
or (direntry->d_name[1] == '.'
1538
and direntry->d_name[2] == '\0'))){
1541
char *fullname = NULL;
1542
ret = asprintf(&fullname, "%s/%s", tempdir,
1548
ret = remove(fullname);
1550
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1557
ret = rmdir(tempdir);
1558
if(ret == -1 and errno != ENOENT){
1564
sigemptyset(&old_sigterm_action.sa_mask);
1565
old_sigterm_action.sa_handler = SIG_DFL;
1566
ret = sigaction(signal_received, &old_sigterm_action, NULL);
1568
perror("sigaction");
1570
raise(signal_received);