116
288
/* Create new empty GPGME data buffer for the plaintext */
117
289
rc = gpgme_data_new(&dh_plain);
118
if (rc != GPG_ERR_NO_ERROR){
290
if(rc != GPG_ERR_NO_ERROR){
119
291
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
120
292
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){
293
gpgme_data_release(dh_crypto);
297
/* Decrypt data from the cryptotext data buffer to the plaintext
299
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
300
if(rc != GPG_ERR_NO_ERROR){
135
301
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
136
302
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;
303
plaintext_length = -1;
305
gpgme_decrypt_result_t result;
306
result = gpgme_op_decrypt_result(mc.ctx);
308
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
310
fprintf(stderr, "Unsupported algorithm: %s\n",
311
result->unsupported_algorithm);
312
fprintf(stderr, "Wrong key usage: %u\n",
313
result->wrong_key_usage);
314
if(result->file_name != NULL){
315
fprintf(stderr, "File name: %s\n", result->file_name);
317
gpgme_recipient_t recipient;
318
recipient = result->recipients;
158
319
while(recipient != NULL){
159
320
fprintf(stderr, "Public key algorithm: %s\n",
160
321
gpgme_pubkey_algo_name(recipient->pubkey_algo));
161
322
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
162
323
fprintf(stderr, "Secret key available: %s\n",
163
recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
324
recipient->status == GPG_ERR_NO_SECKEY
164
326
recipient = recipient->next;
170
/* Delete the GPGME FILE pointer cryptotext data buffer */
171
gpgme_data_release(dh_crypto);
334
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
173
337
/* Seek back to the beginning of the GPGME plaintext data buffer */
174
gpgme_data_seek(dh_plain, 0, SEEK_SET);
338
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
339
perror("gpgme_data_seek");
340
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;
346
plaintext_capacity = incbuffer(plaintext,
347
(size_t)plaintext_length,
349
if(plaintext_capacity == 0){
351
plaintext_length = -1;
187
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
355
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
188
357
/* Print the data, if any */
190
/* If password is empty, then a incorrect error will be printed */
194
363
perror("gpgme_data_read");
364
plaintext_length = -1;
197
new_packet_length += ret;
367
plaintext_length += ret;
201
fprintf(stderr, "decrypted password is: %s\n", *new_packet);
371
fprintf(stderr, "Decrypted password is: ");
372
for(ssize_t i = 0; i < plaintext_length; i++){
373
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
375
fprintf(stderr, "\n");
204
/* Delete the GPGME plaintext data buffer */
380
/* Delete the GPGME cryptotext data buffer */
381
gpgme_data_release(dh_crypto);
383
/* Delete the GPGME plaintext data buffer */
205
384
gpgme_data_release(dh_plain);
206
return new_packet_length;
385
return plaintext_length;
209
static const char * safer_gnutls_strerror (int value) {
210
const char *ret = gnutls_strerror (value);
388
static const char * safer_gnutls_strerror(int value){
389
const char *ret = gnutls_strerror(value); /* Spurious warning from
390
-Wunreachable-code */
212
392
ret = "(unknown)";
216
void debuggnutls(int level, const char* string){
217
fprintf(stderr, "%s", string);
396
/* GnuTLS log function callback */
397
static void debuggnutls(__attribute__((unused)) int level,
399
fprintf(stderr, "GnuTLS: %s", string);
220
int initgnutls(encrypted_session *es){
402
static int init_gnutls_global(const char *pubkeyfilename,
403
const char *seckeyfilename){
225
fprintf(stderr, "Initializing gnutls\n");
407
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));
410
ret = gnutls_global_init();
411
if(ret != GNUTLS_E_SUCCESS){
412
fprintf(stderr, "GnuTLS global_init: %s\n",
413
safer_gnutls_strerror(ret));
418
/* "Use a log level over 10 to enable all debugging options."
236
421
gnutls_global_set_log_level(11);
237
422
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));
425
/* OpenPGP credentials */
426
gnutls_certificate_allocate_credentials(&mc.cred);
427
if(ret != GNUTLS_E_SUCCESS){
428
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
432
safer_gnutls_strerror(ret));
433
gnutls_global_deinit();
249
fprintf(stderr, "Attempting to use openpgp certificate %s"
250
" and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
438
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
439
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
253
443
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));
444
(mc.cred, pubkeyfilename, seckeyfilename,
445
GNUTLS_OPENPGP_FMT_BASE64);
446
if(ret != GNUTLS_E_SUCCESS){
448
"Error[%d] while reading the OpenPGP key pair ('%s',"
449
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
450
fprintf(stderr, "The GnuTLS error is: %s\n",
451
safer_gnutls_strerror(ret));
455
/* GnuTLS server initialization */
456
ret = gnutls_dh_params_init(&mc.dh_params);
457
if(ret != GNUTLS_E_SUCCESS){
458
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
459
" %s\n", safer_gnutls_strerror(ret));
462
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
463
if(ret != GNUTLS_E_SUCCESS){
464
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
465
safer_gnutls_strerror(ret));
469
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
475
gnutls_certificate_free_credentials(mc.cred);
476
gnutls_global_deinit();
477
gnutls_dh_params_deinit(mc.dh_params);
481
static int init_gnutls_session(gnutls_session_t *session){
483
/* GnuTLS session creation */
485
ret = gnutls_init(session, GNUTLS_SERVER);
489
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
490
if(ret != GNUTLS_E_SUCCESS){
491
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
492
safer_gnutls_strerror(ret));
498
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
500
gnutls_deinit(*session);
503
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
504
if(ret != GNUTLS_E_SUCCESS){
505
fprintf(stderr, "Syntax error at: %s\n", err);
506
fprintf(stderr, "GnuTLS error: %s\n",
507
safer_gnutls_strerror(ret));
508
gnutls_deinit(*session);
514
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
517
gnutls_deinit(*session);
520
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
521
if(ret != GNUTLS_E_SUCCESS){
522
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
523
safer_gnutls_strerror(ret));
524
gnutls_deinit(*session);
304
528
/* ignore client certificate if any. */
305
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
529
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
307
gnutls_dh_set_prime_bits (es->session, DH_BITS);
531
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
312
void empty_log(AvahiLogLevel level, const char *txt){}
536
/* Avahi log function callback */
537
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
538
__attribute__((unused)) const char *txt){}
314
int start_mandos_communcation(char *ip, uint16_t port){
316
struct sockaddr_in6 to;
317
struct in6_addr ip_addr;
318
encrypted_session es;
540
/* Called when a Mandos server is found */
541
static int start_mandos_communication(const char *ip, uint16_t port,
542
AvahiIfIndex if_index,
544
int ret, tcp_sd = -1;
547
struct sockaddr_in in;
548
struct sockaddr_in6 in6;
319
550
char *buffer = NULL;
320
char *decrypted_buffer;
551
char *decrypted_buffer = NULL;
321
552
size_t buffer_length = 0;
322
553
size_t buffer_capacity = 0;
323
ssize_t decrypted_buffer_size;
325
const char interface[] = "eth0";
556
gnutls_session_t session;
557
int pf; /* Protocol family */
574
fprintf(stderr, "Bad address family: %d\n", af);
579
ret = init_gnutls_session(&session);
328
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
585
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
331
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
589
tcp_sd = socket(pf, SOCK_STREAM, 0);
333
592
perror("socket");
338
fprintf(stderr, "Binding to interface %s\n", interface);
341
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
343
perror("setsockopt bindtodevice");
347
memset(&to,0,sizeof(to));
348
to.sin6_family = AF_INET6;
349
ret = inet_pton(AF_INET6, ip, &ip_addr);
602
memset(&to, 0, sizeof(to));
604
to.in6.sin6_family = (sa_family_t)af;
605
ret = inet_pton(af, ip, &to.in6.sin6_addr);
607
to.in.sin_family = (sa_family_t)af;
608
ret = inet_pton(af, ip, &to.in.sin_addr);
351
612
perror("inet_pton");
355
618
fprintf(stderr, "Bad address: %s\n", ip);
358
to.sin6_port = htons(port);
359
to.sin6_scope_id = if_nametoindex(interface);
623
to.in6.sin6_port = htons(port); /* Spurious warnings from
625
-Wunreachable-code */
627
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
628
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
630
if(if_index == AVAHI_IF_UNSPEC){
631
fprintf(stderr, "An IPv6 link-local address is incomplete"
632
" without a network interface\n");
636
/* Set the network interface number as scope */
637
to.in6.sin6_scope_id = (uint32_t)if_index;
640
to.in.sin_port = htons(port); /* Spurious warnings from
642
-Wunreachable-code */
362
fprintf(stderr, "Connection to: %s\n", ip);
365
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
651
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
652
char interface[IF_NAMESIZE];
653
if(if_indextoname((unsigned int)if_index, interface) == NULL){
654
perror("if_indextoname");
656
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
657
ip, interface, port);
660
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
663
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
664
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
667
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
670
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
676
if(strcmp(addrstr, ip) != 0){
677
fprintf(stderr, "Canonical address form: %s\n", addrstr);
688
ret = connect(tcp_sd, &to.in6, sizeof(to));
690
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
367
694
perror("connect");
371
ret = initgnutls (&es);
378
gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
381
fprintf(stderr, "Establishing tls session with %s\n", ip);
385
ret = gnutls_handshake (es.session);
387
if (ret != GNUTLS_E_SUCCESS){
388
fprintf(stderr, "\n*** Handshake failed ***\n");
394
//Retrieve gpg packet that contains the wanted password
397
fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
704
const char *out = mandos_protocol_version;
401
if (buffer_length + BUFFER_SIZE > buffer_capacity){
402
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
707
size_t out_size = strlen(out);
708
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
709
out_size - written));
716
written += (size_t)ret;
717
if(written < out_size){
720
if(out == mandos_protocol_version){
407
buffer_capacity += BUFFER_SIZE;
410
ret = gnutls_record_recv
411
(es.session, buffer+buffer_length, BUFFER_SIZE);
735
fprintf(stderr, "Establishing TLS session with %s\n", ip);
743
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
751
ret = gnutls_handshake(session);
756
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
758
if(ret != GNUTLS_E_SUCCESS){
760
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
767
/* Read OpenPGP packet that contains the wanted password */
770
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
781
buffer_capacity = incbuffer(&buffer, buffer_length,
783
if(buffer_capacity == 0){
795
sret = gnutls_record_recv(session, buffer+buffer_length,
417
802
case GNUTLS_E_INTERRUPTED:
418
803
case GNUTLS_E_AGAIN:
420
805
case GNUTLS_E_REHANDSHAKE:
421
ret = gnutls_handshake (es.session);
423
fprintf(stderr, "\n*** Handshake failed ***\n");
807
ret = gnutls_handshake(session);
813
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
815
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
430
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
432
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
436
buffer_length += ret;
440
if (buffer_length > 0){
441
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
442
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
443
free(decrypted_buffer);
822
fprintf(stderr, "Unknown error while reading data from"
823
" encrypted session with Mandos server\n");
824
gnutls_bye(session, GNUTLS_SHUT_RDWR);
829
buffer_length += (size_t) sret;
834
fprintf(stderr, "Closing TLS session\n");
843
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
848
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
850
if(buffer_length > 0){
851
ssize_t decrypted_buffer_size;
852
decrypted_buffer_size = pgp_packet_decrypt(buffer,
855
if(decrypted_buffer_size >= 0){
858
while(written < (size_t) decrypted_buffer_size){
864
ret = (int)fwrite(decrypted_buffer + written, 1,
865
(size_t)decrypted_buffer_size - written,
867
if(ret == 0 and ferror(stdout)){
870
fprintf(stderr, "Error writing encrypted data: %s\n",
876
written += (size_t)ret;
882
/* Shutdown procedure */
887
free(decrypted_buffer);
890
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
898
gnutls_deinit(session);
452
fprintf(stderr, "Closing tls session\n");
456
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
459
gnutls_deinit (es.session);
460
gnutls_certificate_free_credentials (es.cred);
461
gnutls_global_deinit ();
465
static AvahiSimplePoll *simple_poll = NULL;
466
static AvahiServer *server = NULL;
468
static void resolve_callback(
469
AvahiSServiceResolver *r,
470
AVAHI_GCC_UNUSED AvahiIfIndex interface,
471
AVAHI_GCC_UNUSED AvahiProtocol protocol,
472
AvahiResolverEvent event,
476
const char *host_name,
477
const AvahiAddress *address,
479
AvahiStringList *txt,
480
AvahiLookupResultFlags flags,
481
AVAHI_GCC_UNUSED void* userdata) {
485
/* Called whenever a service has been resolved successfully or timed out */
488
case AVAHI_RESOLVER_FAILURE:
489
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)));
492
case AVAHI_RESOLVER_FOUND: {
493
char ip[AVAHI_ADDRESS_STR_MAX];
494
avahi_address_snprint(ip, sizeof(ip), address);
496
fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
498
int ret = start_mandos_communcation(ip, port);
506
avahi_s_service_resolver_free(r);
509
static void browse_callback(
510
AvahiSServiceBrowser *b,
511
AvahiIfIndex interface,
512
AvahiProtocol protocol,
513
AvahiBrowserEvent event,
517
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
520
AvahiServer *s = userdata;
523
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
527
case AVAHI_BROWSER_FAILURE:
529
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
530
avahi_simple_poll_quit(simple_poll);
533
case AVAHI_BROWSER_NEW:
534
/* We ignore the returned resolver object. In the callback
535
function we free it. If the server is terminated before
536
the callback function is called the server will free
537
the resolver for us. */
539
if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
540
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
544
case AVAHI_BROWSER_REMOVE:
547
case AVAHI_BROWSER_ALL_FOR_NOW:
548
case AVAHI_BROWSER_CACHE_EXHAUSTED:
553
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
908
static void resolve_callback(AvahiSServiceResolver *r,
909
AvahiIfIndex interface,
911
AvahiResolverEvent event,
915
const char *host_name,
916
const AvahiAddress *address,
918
AVAHI_GCC_UNUSED AvahiStringList *txt,
919
AVAHI_GCC_UNUSED AvahiLookupResultFlags
921
AVAHI_GCC_UNUSED void* userdata){
924
/* Called whenever a service has been resolved successfully or
933
case AVAHI_RESOLVER_FAILURE:
934
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
935
" of type '%s' in domain '%s': %s\n", name, type, domain,
936
avahi_strerror(avahi_server_errno(mc.server)));
939
case AVAHI_RESOLVER_FOUND:
941
char ip[AVAHI_ADDRESS_STR_MAX];
942
avahi_address_snprint(ip, sizeof(ip), address);
944
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
945
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
946
ip, (intmax_t)interface, port);
948
int ret = start_mandos_communication(ip, port, interface,
949
avahi_proto_to_af(proto));
951
avahi_simple_poll_quit(mc.simple_poll);
955
avahi_s_service_resolver_free(r);
958
static void browse_callback(AvahiSServiceBrowser *b,
959
AvahiIfIndex interface,
960
AvahiProtocol protocol,
961
AvahiBrowserEvent event,
965
AVAHI_GCC_UNUSED AvahiLookupResultFlags
967
AVAHI_GCC_UNUSED void* userdata){
970
/* Called whenever a new services becomes available on the LAN or
971
is removed from the LAN */
979
case AVAHI_BROWSER_FAILURE:
981
fprintf(stderr, "(Avahi browser) %s\n",
982
avahi_strerror(avahi_server_errno(mc.server)));
983
avahi_simple_poll_quit(mc.simple_poll);
986
case AVAHI_BROWSER_NEW:
987
/* We ignore the returned Avahi resolver object. In the callback
988
function we free it. If the Avahi server is terminated before
989
the callback function is called the Avahi server will free the
992
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
993
name, type, domain, protocol, 0,
994
resolve_callback, NULL) == NULL)
995
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
996
name, avahi_strerror(avahi_server_errno(mc.server)));
999
case AVAHI_BROWSER_REMOVE:
1002
case AVAHI_BROWSER_ALL_FOR_NOW:
1003
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1005
fprintf(stderr, "No Mandos server found, still searching...\n");
1011
/* stop main loop after sigterm has been called */
1012
static void handle_sigterm(int sig){
1017
signal_received = sig;
1018
int old_errno = errno;
1019
if(mc.simple_poll != NULL){
1020
avahi_simple_poll_quit(mc.simple_poll);
1026
* This function determines if a directory entry in /sys/class/net
1027
* corresponds to an acceptable network device.
1028
* (This function is passed to scandir(3) as a filter function.)
1030
int good_interface(const struct dirent *if_entry){
1032
char *flagname = NULL;
1033
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1039
if(if_entry->d_name[0] == '.'){
1042
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1047
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1048
/* read line from flags_fd */
1049
ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1050
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1051
flagstring[(size_t)to_read] = '\0';
1052
if(flagstring == NULL){
1058
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1075
tmpmax = strtoimax(flagstring, &tmp, 0);
1076
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1077
and not (isspace(*tmp)))
1078
or tmpmax != (ifreq_flags)tmpmax){
1080
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1081
flagstring, if_entry->d_name);
1087
ifreq_flags flags = (ifreq_flags)tmpmax;
1088
/* Reject the loopback device */
1089
if(flags & IFF_LOOPBACK){
1091
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1096
/* Accept point-to-point devices only if connect_to is specified */
1097
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1099
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1104
/* Otherwise, reject non-broadcast-capable devices */
1105
if(not (flags & IFF_BROADCAST)){
1107
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1112
/* Accept this device */
1114
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1120
int main(int argc, char *argv[]){
1121
AvahiSServiceBrowser *sb = NULL;
1126
int exitcode = EXIT_SUCCESS;
1127
const char *interface = "";
1128
struct ifreq network;
1130
bool take_down_interface = false;
1133
char tempdir[] = "/tmp/mandosXXXXXX";
1134
bool tempdir_created = false;
1135
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1136
const char *seckey = PATHDIR "/" SECKEY;
1137
const char *pubkey = PATHDIR "/" PUBKEY;
1139
bool gnutls_initialized = false;
1140
bool gpgme_initialized = false;
1143
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1144
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1149
/* Lower any group privileges we might have, just to be safe */
1156
/* Lower user privileges (temporarily) */
1168
struct argp_option options[] = {
1169
{ .name = "debug", .key = 128,
1170
.doc = "Debug mode", .group = 3 },
1171
{ .name = "connect", .key = 'c',
1172
.arg = "ADDRESS:PORT",
1173
.doc = "Connect directly to a specific Mandos server",
1175
{ .name = "interface", .key = 'i',
1177
.doc = "Network interface that will be used to search for"
1180
{ .name = "seckey", .key = 's',
1182
.doc = "OpenPGP secret key file base name",
1184
{ .name = "pubkey", .key = 'p',
1186
.doc = "OpenPGP public key file base name",
1188
{ .name = "dh-bits", .key = 129,
1190
.doc = "Bit length of the prime number used in the"
1191
" Diffie-Hellman key exchange",
1193
{ .name = "priority", .key = 130,
1195
.doc = "GnuTLS priority string for the TLS handshake",
1197
{ .name = "delay", .key = 131,
1199
.doc = "Maximum delay to wait for interface startup",
1202
* These reproduce what we would get without ARGP_NO_HELP
1204
{ .name = "help", .key = '?',
1205
.doc = "Give this help list", .group = -1 },
1206
{ .name = "usage", .key = -3,
1207
.doc = "Give a short usage message", .group = -1 },
1208
{ .name = "version", .key = 'V',
1209
.doc = "Print program version", .group = -1 },
1213
error_t parse_opt(int key, char *arg,
1214
struct argp_state *state){
1217
case 128: /* --debug */
1220
case 'c': /* --connect */
1223
case 'i': /* --interface */
1226
case 's': /* --seckey */
1229
case 'p': /* --pubkey */
1232
case 129: /* --dh-bits */
1234
tmpmax = strtoimax(arg, &tmp, 10);
1235
if(errno != 0 or tmp == arg or *tmp != '\0'
1236
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1237
argp_error(state, "Bad number of DH bits");
1239
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1241
case 130: /* --priority */
1244
case 131: /* --delay */
1246
delay = strtof(arg, &tmp);
1247
if(errno != 0 or tmp == arg or *tmp != '\0'){
1248
argp_error(state, "Bad delay");
1252
* These reproduce what we would get without ARGP_NO_HELP
1254
case '?': /* --help */
1255
argp_state_help(state, state->out_stream,
1256
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1257
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1258
case -3: /* --usage */
1259
argp_state_help(state, state->out_stream,
1260
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1261
case 'V': /* --version */
1262
fprintf(state->out_stream, "%s\n", argp_program_version);
1263
exit(argp_err_exit_status);
1266
return ARGP_ERR_UNKNOWN;
1271
struct argp argp = { .options = options, .parser = parse_opt,
1273
.doc = "Mandos client -- Get and decrypt"
1274
" passwords from a Mandos server" };
1275
ret = argp_parse(&argp, argc, argv,
1276
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
1283
perror("argp_parse");
1284
exitcode = EX_OSERR;
1287
exitcode = EX_USAGE;
1293
avahi_set_log_function(empty_log);
1296
if(interface[0] == '\0'){
1297
struct dirent **direntries;
1298
ret = scandir(sys_class_net, &direntries, good_interface,
1301
/* Pick the first good interface */
1302
interface = strdup(direntries[0]->d_name);
1304
fprintf(stderr, "Using interface \"%s\"\n", interface);
1306
if(interface == NULL){
1309
exitcode = EXIT_FAILURE;
1315
fprintf(stderr, "Could not find a network interface\n");
1316
exitcode = EXIT_FAILURE;
1321
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1322
from the signal handler */
1323
/* Initialize the pseudo-RNG for Avahi */
1324
srand((unsigned int) time(NULL));
1325
mc.simple_poll = avahi_simple_poll_new();
1326
if(mc.simple_poll == NULL){
1327
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1328
exitcode = EX_UNAVAILABLE;
1332
sigemptyset(&sigterm_action.sa_mask);
1333
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1335
perror("sigaddset");
1336
exitcode = EX_OSERR;
1339
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1341
perror("sigaddset");
1342
exitcode = EX_OSERR;
1345
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1347
perror("sigaddset");
1348
exitcode = EX_OSERR;
1351
/* Need to check if the handler is SIG_IGN before handling:
1352
| [[info:libc:Initial Signal Actions]] |
1353
| [[info:libc:Basic Signal Handling]] |
1355
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1357
perror("sigaction");
1360
if(old_sigterm_action.sa_handler != SIG_IGN){
1361
ret = sigaction(SIGINT, &sigterm_action, NULL);
1363
perror("sigaction");
1364
exitcode = EX_OSERR;
1368
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1370
perror("sigaction");
1373
if(old_sigterm_action.sa_handler != SIG_IGN){
1374
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1376
perror("sigaction");
1377
exitcode = EX_OSERR;
1381
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1383
perror("sigaction");
1386
if(old_sigterm_action.sa_handler != SIG_IGN){
1387
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1389
perror("sigaction");
1390
exitcode = EX_OSERR;
1395
/* If the interface is down, bring it up */
1396
if(strcmp(interface, "none") != 0){
1397
if_index = (AvahiIfIndex) if_nametoindex(interface);
1399
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1400
exitcode = EX_UNAVAILABLE;
1408
/* Re-raise priviliges */
1416
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1417
messages about the network interface to mess up the prompt */
1418
ret = klogctl(8, NULL, 5);
1419
bool restore_loglevel = true;
1421
restore_loglevel = false;
1424
#endif /* __linux__ */
1426
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1429
exitcode = EX_OSERR;
1431
if(restore_loglevel){
1432
ret = klogctl(7, NULL, 0);
1437
#endif /* __linux__ */
1438
/* Lower privileges */
1446
strcpy(network.ifr_name, interface);
1447
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1449
perror("ioctl SIOCGIFFLAGS");
1451
if(restore_loglevel){
1452
ret = klogctl(7, NULL, 0);
1457
#endif /* __linux__ */
1458
exitcode = EX_OSERR;
1459
/* Lower privileges */
1467
if((network.ifr_flags & IFF_UP) == 0){
1468
network.ifr_flags |= IFF_UP;
1469
take_down_interface = true;
1470
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1472
take_down_interface = false;
1473
perror("ioctl SIOCSIFFLAGS +IFF_UP");
1474
exitcode = EX_OSERR;
1476
if(restore_loglevel){
1477
ret = klogctl(7, NULL, 0);
1482
#endif /* __linux__ */
1483
/* Lower privileges */
1492
/* sleep checking until interface is running */
1493
for(int i=0; i < delay * 4; i++){
1494
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1496
perror("ioctl SIOCGIFFLAGS");
1497
} else if(network.ifr_flags & IFF_RUNNING){
1500
struct timespec sleeptime = { .tv_nsec = 250000000 };
1501
ret = nanosleep(&sleeptime, NULL);
1502
if(ret == -1 and errno != EINTR){
1503
perror("nanosleep");
1506
if(not take_down_interface){
1507
/* We won't need the socket anymore */
1508
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1514
if(restore_loglevel){
1515
/* Restores kernel loglevel to default */
1516
ret = klogctl(7, NULL, 0);
1521
#endif /* __linux__ */
1522
/* Lower privileges */
1524
if(take_down_interface){
1525
/* Lower privileges */
1531
/* Lower privileges permanently */
1543
ret = init_gnutls_global(pubkey, seckey);
1545
fprintf(stderr, "init_gnutls_global failed\n");
1546
exitcode = EX_UNAVAILABLE;
1549
gnutls_initialized = true;
1556
tempdir_created = true;
1557
if(mkdtemp(tempdir) == NULL){
1558
tempdir_created = false;
1567
if(not init_gpgme(pubkey, seckey, tempdir)){
1568
fprintf(stderr, "init_gpgme failed\n");
1569
exitcode = EX_UNAVAILABLE;
1572
gpgme_initialized = true;
1579
if(connect_to != NULL){
1580
/* Connect directly, do not use Zeroconf */
1581
/* (Mainly meant for debugging) */
1582
char *address = strrchr(connect_to, ':');
1583
if(address == NULL){
1584
fprintf(stderr, "No colon in address\n");
1585
exitcode = EX_USAGE;
1595
tmpmax = strtoimax(address+1, &tmp, 10);
1596
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1597
or tmpmax != (uint16_t)tmpmax){
1598
fprintf(stderr, "Bad port number\n");
1599
exitcode = EX_USAGE;
1607
port = (uint16_t)tmpmax;
1609
address = connect_to;
1610
/* Colon in address indicates IPv6 */
1612
if(strchr(address, ':') != NULL){
1622
ret = start_mandos_communication(address, port, if_index, af);
1628
exitcode = EX_NOHOST;
1631
exitcode = EX_USAGE;
1634
exitcode = EX_IOERR;
1637
exitcode = EX_PROTOCOL;
1640
exitcode = EX_OSERR;
1644
exitcode = EXIT_SUCCESS;
554
1654
AvahiServerConfig config;
555
AvahiSServiceBrowser *sb = NULL;
556
const char db[] = "--debug";
559
int returncode = EXIT_SUCCESS;
560
char *basename = rindex(argv[0], '/');
561
if(basename == NULL){
567
char *program_name = malloc(strlen(basename) + sizeof(db));
569
if (program_name == NULL){
574
program_name[0] = '\0';
576
for (int i = 1; i < argc; i++){
577
if (not strncmp(argv[i], db, 5)){
578
strcat(strcat(strcat(program_name, db ), "="), basename);
579
if(not strcmp(argv[i], db) or not strcmp(argv[i], program_name)){
587
avahi_set_log_function(empty_log);
590
/* Initialize the psuedo-RNG */
593
/* Allocate main loop object */
594
if (!(simple_poll = avahi_simple_poll_new())) {
595
fprintf(stderr, "Failed to create simple poll object.\n");
600
/* Do not publish any local records */
1655
/* Do not publish any local Zeroconf records */
601
1656
avahi_server_config_init(&config);
602
1657
config.publish_hinfo = 0;
603
1658
config.publish_addresses = 0;
604
1659
config.publish_workstation = 0;
605
1660
config.publish_domain = 0;
607
1662
/* Allocate a new server */
608
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
610
/* Free the configuration data */
1663
mc.server = avahi_server_new(avahi_simple_poll_get
1664
(mc.simple_poll), &config, NULL,
1667
/* Free the Avahi configuration data */
611
1668
avahi_server_config_free(&config);
613
/* Check if creating the server object succeeded */
615
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
616
returncode = EXIT_FAILURE;
620
/* Create the service browser */
621
if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
622
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
623
returncode = EXIT_FAILURE;
627
/* Run the main loop */
630
fprintf(stderr, "Starting avahi loop search\n");
633
avahi_simple_poll_loop(simple_poll);
638
fprintf(stderr, "%s exiting\n", argv[0]);
643
avahi_s_service_browser_free(sb);
646
avahi_server_free(server);
649
avahi_simple_poll_free(simple_poll);
1671
/* Check if creating the Avahi server object succeeded */
1672
if(mc.server == NULL){
1673
fprintf(stderr, "Failed to create Avahi server: %s\n",
1674
avahi_strerror(error));
1675
exitcode = EX_UNAVAILABLE;
1683
/* Create the Avahi service browser */
1684
sb = avahi_s_service_browser_new(mc.server, if_index,
1685
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1686
NULL, 0, browse_callback, NULL);
1688
fprintf(stderr, "Failed to create service browser: %s\n",
1689
avahi_strerror(avahi_server_errno(mc.server)));
1690
exitcode = EX_UNAVAILABLE;
1698
/* Run the main loop */
1701
fprintf(stderr, "Starting Avahi loop search\n");
1704
avahi_simple_poll_loop(mc.simple_poll);
1709
fprintf(stderr, "%s exiting\n", argv[0]);
1712
/* Cleanup things */
1714
avahi_s_service_browser_free(sb);
1716
if(mc.server != NULL)
1717
avahi_server_free(mc.server);
1719
if(mc.simple_poll != NULL)
1720
avahi_simple_poll_free(mc.simple_poll);
1722
if(gnutls_initialized){
1723
gnutls_certificate_free_credentials(mc.cred);
1724
gnutls_global_deinit();
1725
gnutls_dh_params_deinit(mc.dh_params);
1728
if(gpgme_initialized){
1729
gpgme_release(mc.ctx);
1732
/* Take down the network interface */
1733
if(take_down_interface){
1734
/* Re-raise priviliges */
1741
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1743
perror("ioctl SIOCGIFFLAGS");
1744
} else if(network.ifr_flags & IFF_UP) {
1745
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1746
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1748
perror("ioctl SIOCSIFFLAGS -IFF_UP");
1751
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1755
/* Lower privileges permanently */
1764
/* Removes the temp directory used by GPGME */
1765
if(tempdir_created){
1767
struct dirent *direntry;
1768
d = opendir(tempdir);
1770
if(errno != ENOENT){
1775
direntry = readdir(d);
1776
if(direntry == NULL){
1779
/* Skip "." and ".." */
1780
if(direntry->d_name[0] == '.'
1781
and (direntry->d_name[1] == '\0'
1782
or (direntry->d_name[1] == '.'
1783
and direntry->d_name[2] == '\0'))){
1786
char *fullname = NULL;
1787
ret = asprintf(&fullname, "%s/%s", tempdir,
1793
ret = remove(fullname);
1795
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1802
ret = rmdir(tempdir);
1803
if(ret == -1 and errno != ENOENT){
1809
sigemptyset(&old_sigterm_action.sa_mask);
1810
old_sigterm_action.sa_handler = SIG_DFL;
1811
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1812
&old_sigterm_action,
1815
perror("sigaction");
1818
ret = raise(signal_received);
1819
} while(ret != 0 and errno == EINTR);
1824
TEMP_FAILURE_RETRY(pause());