119
348
/* Create new empty GPGME data buffer for the plaintext */
120
349
rc = gpgme_data_new(&dh_plain);
121
if (rc != GPG_ERR_NO_ERROR){
350
if(rc != GPG_ERR_NO_ERROR){
122
351
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
123
352
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){
353
gpgme_data_release(dh_crypto);
357
/* Decrypt data from the cryptotext data buffer to the plaintext
359
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
360
if(rc != GPG_ERR_NO_ERROR){
138
361
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
139
362
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;
363
plaintext_length = -1;
365
gpgme_decrypt_result_t result;
366
result = gpgme_op_decrypt_result(mc.ctx);
368
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
370
fprintf(stderr, "Unsupported algorithm: %s\n",
371
result->unsupported_algorithm);
372
fprintf(stderr, "Wrong key usage: %u\n",
373
result->wrong_key_usage);
374
if(result->file_name != NULL){
375
fprintf(stderr, "File name: %s\n", result->file_name);
377
gpgme_recipient_t recipient;
378
recipient = result->recipients;
161
379
while(recipient != NULL){
162
380
fprintf(stderr, "Public key algorithm: %s\n",
163
381
gpgme_pubkey_algo_name(recipient->pubkey_algo));
164
382
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
165
383
fprintf(stderr, "Secret key available: %s\n",
166
recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
384
recipient->status == GPG_ERR_NO_SECKEY
167
386
recipient = recipient->next;
173
/* Delete the GPGME FILE pointer cryptotext data buffer */
174
gpgme_data_release(dh_crypto);
394
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
176
397
/* Seek back to the beginning of the GPGME plaintext data buffer */
177
gpgme_data_seek(dh_plain, 0, SEEK_SET);
398
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
399
perror_plus("gpgme_data_seek");
400
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;
406
plaintext_capacity = incbuffer(plaintext,
407
(size_t)plaintext_length,
409
if(plaintext_capacity == 0){
410
perror_plus("incbuffer");
411
plaintext_length = -1;
190
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
415
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
191
417
/* Print the data, if any */
193
/* If password is empty, then a incorrect error will be printed */
197
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"); */
423
perror_plus("gpgme_data_read");
424
plaintext_length = -1;
427
plaintext_length += ret;
431
fprintf(stderr, "Decrypted password is: ");
432
for(ssize_t i = 0; i < plaintext_length; i++){
433
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
435
fprintf(stderr, "\n");
440
/* Delete the GPGME cryptotext data buffer */
441
gpgme_data_release(dh_crypto);
211
443
/* Delete the GPGME plaintext data buffer */
212
444
gpgme_data_release(dh_plain);
213
return new_packet_length;
445
return plaintext_length;
216
static const char * safer_gnutls_strerror (int value) {
217
const char *ret = gnutls_strerror (value);
448
static const char * safer_gnutls_strerror(int value){
449
const char *ret = gnutls_strerror(value); /* Spurious warning from
450
-Wunreachable-code */
219
452
ret = "(unknown)";
223
void debuggnutls(int level, const char* string){
224
fprintf(stderr, "%s", string);
456
/* GnuTLS log function callback */
457
static void debuggnutls(__attribute__((unused)) int level,
459
fprintf(stderr, "GnuTLS: %s", string);
227
int initgnutls(encrypted_session *es){
462
static int init_gnutls_global(const char *pubkeyfilename,
463
const char *seckeyfilename){
232
fprintf(stderr, "Initializing gnutls\n");
467
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));
470
ret = gnutls_global_init();
471
if(ret != GNUTLS_E_SUCCESS){
472
fprintf(stderr, "GnuTLS global_init: %s\n",
473
safer_gnutls_strerror(ret));
478
/* "Use a log level over 10 to enable all debugging options."
243
481
gnutls_global_set_log_level(11);
244
482
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));
485
/* OpenPGP credentials */
486
ret = gnutls_certificate_allocate_credentials(&mc.cred);
487
if(ret != GNUTLS_E_SUCCESS){
488
fprintf(stderr, "GnuTLS memory error: %s\n",
489
safer_gnutls_strerror(ret));
490
gnutls_global_deinit();
256
fprintf(stderr, "Attempting to use openpgp certificate %s"
257
" and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
495
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
496
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
260
500
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));
501
(mc.cred, pubkeyfilename, seckeyfilename,
502
GNUTLS_OPENPGP_FMT_BASE64);
503
if(ret != GNUTLS_E_SUCCESS){
505
"Error[%d] while reading the OpenPGP key pair ('%s',"
506
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
507
fprintf(stderr, "The GnuTLS error is: %s\n",
508
safer_gnutls_strerror(ret));
512
/* GnuTLS server initialization */
513
ret = gnutls_dh_params_init(&mc.dh_params);
514
if(ret != GNUTLS_E_SUCCESS){
515
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
516
" %s\n", safer_gnutls_strerror(ret));
519
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
520
if(ret != GNUTLS_E_SUCCESS){
521
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
522
safer_gnutls_strerror(ret));
526
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
532
gnutls_certificate_free_credentials(mc.cred);
533
gnutls_global_deinit();
534
gnutls_dh_params_deinit(mc.dh_params);
538
static int init_gnutls_session(gnutls_session_t *session){
540
/* GnuTLS session creation */
542
ret = gnutls_init(session, GNUTLS_SERVER);
546
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
547
if(ret != GNUTLS_E_SUCCESS){
548
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
549
safer_gnutls_strerror(ret));
555
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
557
gnutls_deinit(*session);
560
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
561
if(ret != GNUTLS_E_SUCCESS){
562
fprintf(stderr, "Syntax error at: %s\n", err);
563
fprintf(stderr, "GnuTLS error: %s\n",
564
safer_gnutls_strerror(ret));
565
gnutls_deinit(*session);
571
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
574
gnutls_deinit(*session);
577
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
578
if(ret != GNUTLS_E_SUCCESS){
579
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
580
safer_gnutls_strerror(ret));
581
gnutls_deinit(*session);
311
585
/* ignore client certificate if any. */
312
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
586
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
314
gnutls_dh_set_prime_bits (es->session, DH_BITS);
588
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
319
void empty_log(AvahiLogLevel level, const char *txt){}
593
/* Avahi log function callback */
594
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
595
__attribute__((unused)) const char *txt){}
321
int start_mandos_communication(char *ip, uint16_t port){
323
struct sockaddr_in6 to;
324
encrypted_session es;
597
/* Called when a Mandos server is found */
598
static int start_mandos_communication(const char *ip, uint16_t port,
599
AvahiIfIndex if_index,
601
int ret, tcp_sd = -1;
604
struct sockaddr_in in;
605
struct sockaddr_in6 in6;
325
607
char *buffer = NULL;
326
char *decrypted_buffer;
608
char *decrypted_buffer = NULL;
327
609
size_t buffer_length = 0;
328
610
size_t buffer_capacity = 0;
329
ssize_t decrypted_buffer_size;
333
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
336
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
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);
613
gnutls_session_t session;
614
int pf; /* Protocol family */
631
fprintf(stderr, "Bad address family: %d\n", af);
636
ret = init_gnutls_session(&session);
642
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
646
tcp_sd = socket(pf, SOCK_STREAM, 0);
649
perror_plus("socket");
659
memset(&to, 0, sizeof(to));
661
to.in6.sin6_family = (sa_family_t)af;
662
ret = inet_pton(af, ip, &to.in6.sin6_addr);
664
to.in.sin_family = (sa_family_t)af;
665
ret = inet_pton(af, ip, &to.in.sin_addr);
669
perror_plus("inet_pton");
360
675
fprintf(stderr, "Bad address: %s\n", ip);
363
to.sin6_port = htons(port);
364
to.sin6_scope_id = if_nametoindex(interface);
367
fprintf(stderr, "Connection to: %s\n", ip);
370
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
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);
406
if (buffer_length + BUFFER_SIZE > buffer_capacity){
407
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
412
buffer_capacity += BUFFER_SIZE;
415
ret = gnutls_record_recv
416
(es.session, buffer+buffer_length, BUFFER_SIZE);
680
to.in6.sin6_port = htons(port); /* Spurious warnings from
682
-Wunreachable-code */
684
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
685
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
687
if(if_index == AVAHI_IF_UNSPEC){
688
fprintf(stderr, "An IPv6 link-local address is incomplete"
689
" without a network interface\n");
693
/* Set the network interface number as scope */
694
to.in6.sin6_scope_id = (uint32_t)if_index;
697
to.in.sin_port = htons(port); /* Spurious warnings from
699
-Wunreachable-code */
708
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
709
char interface[IF_NAMESIZE];
710
if(if_indextoname((unsigned int)if_index, interface) == NULL){
711
perror_plus("if_indextoname");
713
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
714
ip, interface, port);
717
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
720
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
721
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
724
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
727
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
731
perror_plus("inet_ntop");
733
if(strcmp(addrstr, ip) != 0){
734
fprintf(stderr, "Canonical address form: %s\n", addrstr);
745
ret = connect(tcp_sd, &to.in6, sizeof(to));
747
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
750
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
752
perror_plus("connect");
763
const char *out = mandos_protocol_version;
766
size_t out_size = strlen(out);
767
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
768
out_size - written));
771
perror_plus("write");
775
written += (size_t)ret;
776
if(written < out_size){
779
if(out == mandos_protocol_version){
794
fprintf(stderr, "Establishing TLS session with %s\n", ip);
802
/* Spurious warning from -Wint-to-pointer-cast */
803
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
811
ret = gnutls_handshake(session);
816
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
818
if(ret != GNUTLS_E_SUCCESS){
820
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
827
/* Read OpenPGP packet that contains the wanted password */
830
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
841
buffer_capacity = incbuffer(&buffer, buffer_length,
843
if(buffer_capacity == 0){
845
perror_plus("incbuffer");
855
sret = gnutls_record_recv(session, buffer+buffer_length,
422
862
case GNUTLS_E_INTERRUPTED:
423
863
case GNUTLS_E_AGAIN:
425
865
case GNUTLS_E_REHANDSHAKE:
426
ret = gnutls_handshake (es.session);
428
fprintf(stderr, "\n*** Handshake failed ***\n");
867
ret = gnutls_handshake(session);
873
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
875
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);
441
buffer_length += ret;
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);
882
fprintf(stderr, "Unknown error while reading data from"
883
" encrypted session with Mandos server\n");
884
gnutls_bye(session, GNUTLS_SHUT_RDWR);
889
buffer_length += (size_t) sret;
894
fprintf(stderr, "Closing TLS session\n");
903
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
908
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
910
if(buffer_length > 0){
911
ssize_t decrypted_buffer_size;
912
decrypted_buffer_size = pgp_packet_decrypt(buffer,
915
if(decrypted_buffer_size >= 0){
918
while(written < (size_t) decrypted_buffer_size){
924
ret = (int)fwrite(decrypted_buffer + written, 1,
925
(size_t)decrypted_buffer_size - written,
927
if(ret == 0 and ferror(stdout)){
930
fprintf(stderr, "Error writing encrypted data: %s\n",
936
written += (size_t)ret;
942
/* Shutdown procedure */
947
free(decrypted_buffer);
950
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
956
perror_plus("close");
958
gnutls_deinit(session);
457
fprintf(stderr, "Closing tls session\n");
461
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
464
gnutls_deinit (es.session);
465
gnutls_certificate_free_credentials (es.cred);
466
gnutls_global_deinit ();
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[]) {
968
static void resolve_callback(AvahiSServiceResolver *r,
969
AvahiIfIndex interface,
971
AvahiResolverEvent event,
975
const char *host_name,
976
const AvahiAddress *address,
978
AVAHI_GCC_UNUSED AvahiStringList *txt,
979
AVAHI_GCC_UNUSED AvahiLookupResultFlags
981
AVAHI_GCC_UNUSED void* userdata){
984
/* Called whenever a service has been resolved successfully or
993
case AVAHI_RESOLVER_FAILURE:
994
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
995
" of type '%s' in domain '%s': %s\n", name, type, domain,
996
avahi_strerror(avahi_server_errno(mc.server)));
999
case AVAHI_RESOLVER_FOUND:
1001
char ip[AVAHI_ADDRESS_STR_MAX];
1002
avahi_address_snprint(ip, sizeof(ip), address);
1004
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
1005
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
1006
ip, (intmax_t)interface, port);
1008
int ret = start_mandos_communication(ip, port, interface,
1009
avahi_proto_to_af(proto));
1011
avahi_simple_poll_quit(mc.simple_poll);
1013
ret = add_server(ip, port, interface,
1014
avahi_proto_to_af(proto));
1018
avahi_s_service_resolver_free(r);
1021
static void browse_callback(AvahiSServiceBrowser *b,
1022
AvahiIfIndex interface,
1023
AvahiProtocol protocol,
1024
AvahiBrowserEvent event,
1028
AVAHI_GCC_UNUSED AvahiLookupResultFlags
1030
AVAHI_GCC_UNUSED void* userdata){
1033
/* Called whenever a new services becomes available on the LAN or
1034
is removed from the LAN */
1042
case AVAHI_BROWSER_FAILURE:
1044
fprintf(stderr, "(Avahi browser) %s\n",
1045
avahi_strerror(avahi_server_errno(mc.server)));
1046
avahi_simple_poll_quit(mc.simple_poll);
1049
case AVAHI_BROWSER_NEW:
1050
/* We ignore the returned Avahi resolver object. In the callback
1051
function we free it. If the Avahi server is terminated before
1052
the callback function is called the Avahi server will free the
1055
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
1056
name, type, domain, protocol, 0,
1057
resolve_callback, NULL) == NULL)
1058
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
1059
name, avahi_strerror(avahi_server_errno(mc.server)));
1062
case AVAHI_BROWSER_REMOVE:
1065
case AVAHI_BROWSER_ALL_FOR_NOW:
1066
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1068
fprintf(stderr, "No Mandos server found, still searching...\n");
1074
/* Signal handler that stops main loop after SIGTERM */
1075
static void handle_sigterm(int sig){
1080
signal_received = sig;
1081
int old_errno = errno;
1082
/* set main loop to exit */
1083
if(mc.simple_poll != NULL){
1084
avahi_simple_poll_quit(mc.simple_poll);
1089
bool get_flags(const char *ifname, struct ifreq *ifr){
1092
int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1094
perror_plus("socket");
1097
strcpy(ifr->ifr_name, ifname);
1098
ret = ioctl(s, SIOCGIFFLAGS, ifr);
1101
perror_plus("ioctl SIOCGIFFLAGS");
1108
bool good_flags(const char *ifname, const struct ifreq *ifr){
1110
/* Reject the loopback device */
1111
if(ifr->ifr_flags & IFF_LOOPBACK){
1113
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1118
/* Accept point-to-point devices only if connect_to is specified */
1119
if(connect_to != NULL and (ifr->ifr_flags & IFF_POINTOPOINT)){
1121
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1126
/* Otherwise, reject non-broadcast-capable devices */
1127
if(not (ifr->ifr_flags & IFF_BROADCAST)){
1129
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1134
/* Reject non-ARP interfaces (including dummy interfaces) */
1135
if(ifr->ifr_flags & IFF_NOARP){
1137
fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n", ifname);
1142
/* Accept this device */
1144
fprintf(stderr, "Interface \"%s\" is good\n", ifname);
1150
* This function determines if a directory entry in /sys/class/net
1151
* corresponds to an acceptable network device.
1152
* (This function is passed to scandir(3) as a filter function.)
1154
int good_interface(const struct dirent *if_entry){
1156
if(if_entry->d_name[0] == '.'){
1161
if(not get_flags(if_entry->d_name, &ifr)){
1165
if(not good_flags(if_entry->d_name, &ifr)){
1172
* This function determines if a directory entry in /sys/class/net
1173
* corresponds to an acceptable network device which is up.
1174
* (This function is passed to scandir(3) as a filter function.)
1176
int up_interface(const struct dirent *if_entry){
1178
char *flagname = NULL;
1179
if(if_entry->d_name[0] == '.'){
1182
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1185
perror_plus("asprintf");
1188
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1190
perror_plus("open");
1195
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1196
/* read line from flags_fd */
1197
ssize_t to_read = 2+(sizeof(ifreq_flags)*2)+1; /* "0x1003\n" */
1198
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1199
flagstring[(size_t)to_read] = '\0';
1200
if(flagstring == NULL){
1201
perror_plus("malloc");
1206
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1209
perror_plus("read");
1223
tmpmax = strtoimax(flagstring, &tmp, 0);
1224
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1225
and not (isspace(*tmp)))
1226
or tmpmax != (ifreq_flags)tmpmax){
1228
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1229
flagstring, if_entry->d_name);
1235
ifreq_flags flags = (ifreq_flags)tmpmax;
1236
/* Reject the loopback device */
1237
if(flags & IFF_LOOPBACK){
1239
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1245
/* Reject down interfaces */
1246
if(not (flags & IFF_UP)){
1250
/* Accept point-to-point devices only if connect_to is specified */
1251
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1253
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1258
/* Otherwise, reject non-broadcast-capable devices */
1259
if(not (flags & IFF_BROADCAST)){
1261
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1266
/* Reject non-ARP interfaces (including dummy interfaces) */
1267
if(flags & IFF_NOARP){
1269
fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n",
1274
/* Accept this device */
1276
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1282
int notdotentries(const struct dirent *direntry){
1283
/* Skip "." and ".." */
1284
if(direntry->d_name[0] == '.'
1285
and (direntry->d_name[1] == '\0'
1286
or (direntry->d_name[1] == '.'
1287
and direntry->d_name[2] == '\0'))){
1293
/* Is this directory entry a runnable program? */
1294
int runnable_hook(const struct dirent *direntry){
1298
if((direntry->d_name)[0] == '\0'){
1303
/* Save pointer to last character */
1304
char *end = strchr(direntry->d_name, '\0')-1;
1311
if(((direntry->d_name)[0] == '#')
1313
/* Temporary #name# */
1317
/* XXX more rules here */
1319
ret = stat(direntry->d_name, &st);
1322
perror_plus("Could not stat plugin");
1326
if(not (st.st_mode & S_ISREG)){
1327
/* Not a regular file */
1330
if(not (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))){
1331
/* Not executable */
1337
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval){
1339
struct timespec now;
1340
struct timespec waited_time;
1341
intmax_t block_time;
1344
if(mc.current_server == NULL){
1347
"Wait until first server is found. No timeout!\n");
1349
ret = avahi_simple_poll_iterate(s, -1);
1352
fprintf(stderr, "Check current_server if we should run it,"
1355
/* the current time */
1356
ret = clock_gettime(CLOCK_MONOTONIC, &now);
1358
perror_plus("clock_gettime");
1361
/* Calculating in ms how long time between now and server
1362
who we visted longest time ago. Now - last seen. */
1363
waited_time.tv_sec = (now.tv_sec
1364
- mc.current_server->last_seen.tv_sec);
1365
waited_time.tv_nsec = (now.tv_nsec
1366
- mc.current_server->last_seen.tv_nsec);
1367
/* total time is 10s/10,000ms.
1368
Converting to s from ms by dividing by 1,000,
1369
and ns to ms by dividing by 1,000,000. */
1370
block_time = ((retry_interval
1371
- ((intmax_t)waited_time.tv_sec * 1000))
1372
- ((intmax_t)waited_time.tv_nsec / 1000000));
1375
fprintf(stderr, "Blocking for %" PRIdMAX " ms\n", block_time);
1378
if(block_time <= 0){
1379
ret = start_mandos_communication(mc.current_server->ip,
1380
mc.current_server->port,
1381
mc.current_server->if_index,
1382
mc.current_server->af);
1384
avahi_simple_poll_quit(mc.simple_poll);
1387
ret = clock_gettime(CLOCK_MONOTONIC,
1388
&mc.current_server->last_seen);
1390
perror_plus("clock_gettime");
1393
mc.current_server = mc.current_server->next;
1394
block_time = 0; /* Call avahi to find new Mandos
1395
servers, but don't block */
1398
ret = avahi_simple_poll_iterate(s, (int)block_time);
1401
if (ret > 0 or errno != EINTR) {
1402
return (ret != 1) ? ret : 0;
1408
int main(int argc, char *argv[]){
1409
AvahiSServiceBrowser *sb = NULL;
1414
int exitcode = EXIT_SUCCESS;
1415
const char *interface = "";
1416
struct ifreq network;
1418
bool take_down_interface = false;
1421
char tempdir[] = "/tmp/mandosXXXXXX";
1422
bool tempdir_created = false;
1423
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1424
const char *seckey = PATHDIR "/" SECKEY;
1425
const char *pubkey = PATHDIR "/" PUBKEY;
1427
bool gnutls_initialized = false;
1428
bool gpgme_initialized = false;
1430
double retry_interval = 10; /* 10s between trying a server and
1431
retrying the same server again */
1433
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1434
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1439
/* Lower any group privileges we might have, just to be safe */
1443
perror_plus("setgid");
1446
/* Lower user privileges (temporarily) */
1450
perror_plus("seteuid");
1458
struct argp_option options[] = {
1459
{ .name = "debug", .key = 128,
1460
.doc = "Debug mode", .group = 3 },
1461
{ .name = "connect", .key = 'c',
1462
.arg = "ADDRESS:PORT",
1463
.doc = "Connect directly to a specific Mandos server",
1465
{ .name = "interface", .key = 'i',
1467
.doc = "Network interface that will be used to search for"
1470
{ .name = "seckey", .key = 's',
1472
.doc = "OpenPGP secret key file base name",
1474
{ .name = "pubkey", .key = 'p',
1476
.doc = "OpenPGP public key file base name",
1478
{ .name = "dh-bits", .key = 129,
1480
.doc = "Bit length of the prime number used in the"
1481
" Diffie-Hellman key exchange",
1483
{ .name = "priority", .key = 130,
1485
.doc = "GnuTLS priority string for the TLS handshake",
1487
{ .name = "delay", .key = 131,
1489
.doc = "Maximum delay to wait for interface startup",
1491
{ .name = "retry", .key = 132,
1493
.doc = "Retry interval used when denied by the mandos server",
1496
* These reproduce what we would get without ARGP_NO_HELP
1498
{ .name = "help", .key = '?',
1499
.doc = "Give this help list", .group = -1 },
1500
{ .name = "usage", .key = -3,
1501
.doc = "Give a short usage message", .group = -1 },
1502
{ .name = "version", .key = 'V',
1503
.doc = "Print program version", .group = -1 },
1507
error_t parse_opt(int key, char *arg,
1508
struct argp_state *state){
1511
case 128: /* --debug */
1514
case 'c': /* --connect */
1517
case 'i': /* --interface */
1520
case 's': /* --seckey */
1523
case 'p': /* --pubkey */
1526
case 129: /* --dh-bits */
1528
tmpmax = strtoimax(arg, &tmp, 10);
1529
if(errno != 0 or tmp == arg or *tmp != '\0'
1530
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1531
argp_error(state, "Bad number of DH bits");
1533
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1535
case 130: /* --priority */
1538
case 131: /* --delay */
1540
delay = strtof(arg, &tmp);
1541
if(errno != 0 or tmp == arg or *tmp != '\0'){
1542
argp_error(state, "Bad delay");
1544
case 132: /* --retry */
1546
retry_interval = strtod(arg, &tmp);
1547
if(errno != 0 or tmp == arg or *tmp != '\0'
1548
or (retry_interval * 1000) > INT_MAX
1549
or retry_interval < 0){
1550
argp_error(state, "Bad retry interval");
1554
* These reproduce what we would get without ARGP_NO_HELP
1556
case '?': /* --help */
1557
argp_state_help(state, state->out_stream,
1558
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1559
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1560
case -3: /* --usage */
1561
argp_state_help(state, state->out_stream,
1562
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1563
case 'V': /* --version */
1564
fprintf(state->out_stream, "%s\n", argp_program_version);
1565
exit(argp_err_exit_status);
1568
return ARGP_ERR_UNKNOWN;
1573
struct argp argp = { .options = options, .parser = parse_opt,
1575
.doc = "Mandos client -- Get and decrypt"
1576
" passwords from a Mandos server" };
1577
ret = argp_parse(&argp, argc, argv,
1578
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
1585
perror_plus("argp_parse");
1586
exitcode = EX_OSERR;
1589
exitcode = EX_USAGE;
1595
/* Work around Debian bug #633582:
1596
<http://bugs.debian.org/633582> */
1599
/* Re-raise priviliges */
1603
perror_plus("seteuid");
1606
if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
1607
int seckey_fd = open(seckey, O_RDONLY);
1608
if(seckey_fd == -1){
1609
perror_plus("open");
1611
ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
1613
perror_plus("fstat");
1615
if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
1616
ret = fchown(seckey_fd, uid, gid);
1618
perror_plus("fchown");
1622
TEMP_FAILURE_RETRY(close(seckey_fd));
1626
if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){
1627
int pubkey_fd = open(pubkey, O_RDONLY);
1628
if(pubkey_fd == -1){
1629
perror_plus("open");
1631
ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
1633
perror_plus("fstat");
1635
if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
1636
ret = fchown(pubkey_fd, uid, gid);
1638
perror_plus("fchown");
1642
TEMP_FAILURE_RETRY(close(pubkey_fd));
1646
/* Lower privileges */
1650
perror_plus("seteuid");
1654
/* Find network hooks and run them */
1656
struct dirent **direntries;
1657
struct dirent *direntry;
1658
int numhooks = scandir(HOOKDIR, &direntries, runnable_hook,
1660
int devnull = open("/dev/null", O_RDONLY);
1661
for(int i = 0; i < numhooks; i++){
1662
direntry = direntries[0];
1663
char *fullname = NULL;
1664
ret = asprintf(&fullname, "%s/%s", tempdir,
1667
perror_plus("asprintf");
1670
pid_t hook_pid = fork();
1673
dup2(devnull, STDIN_FILENO);
1675
dup2(STDERR_FILENO, STDOUT_FILENO);
1676
setenv("DEVICE", interface, 1);
1677
setenv("VERBOSE", debug ? "1" : "0", 1);
1678
setenv("MODE", "start", 1);
1679
/* setenv( XXX more here */
1680
ret = execl(fullname, direntry->d_name, "start");
1681
perror_plus("execl");
1692
avahi_set_log_function(empty_log);
1695
if(interface[0] == '\0'){
1696
struct dirent **direntries;
1697
ret = scandir(sys_class_net, &direntries, good_interface,
1700
/* Pick the first good interface */
1701
interface = strdup(direntries[0]->d_name);
1703
fprintf(stderr, "Using interface \"%s\"\n", interface);
1705
if(interface == NULL){
1706
perror_plus("malloc");
1708
exitcode = EXIT_FAILURE;
1714
fprintf(stderr, "Could not find a network interface\n");
1715
exitcode = EXIT_FAILURE;
1720
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1721
from the signal handler */
1722
/* Initialize the pseudo-RNG for Avahi */
1723
srand((unsigned int) time(NULL));
1724
mc.simple_poll = avahi_simple_poll_new();
1725
if(mc.simple_poll == NULL){
1726
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1727
exitcode = EX_UNAVAILABLE;
1731
sigemptyset(&sigterm_action.sa_mask);
1732
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1734
perror_plus("sigaddset");
1735
exitcode = EX_OSERR;
1738
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1740
perror_plus("sigaddset");
1741
exitcode = EX_OSERR;
1744
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1746
perror_plus("sigaddset");
1747
exitcode = EX_OSERR;
1750
/* Need to check if the handler is SIG_IGN before handling:
1751
| [[info:libc:Initial Signal Actions]] |
1752
| [[info:libc:Basic Signal Handling]] |
1754
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1756
perror_plus("sigaction");
1759
if(old_sigterm_action.sa_handler != SIG_IGN){
1760
ret = sigaction(SIGINT, &sigterm_action, NULL);
1762
perror_plus("sigaction");
1763
exitcode = EX_OSERR;
1767
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1769
perror_plus("sigaction");
1772
if(old_sigterm_action.sa_handler != SIG_IGN){
1773
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1775
perror_plus("sigaction");
1776
exitcode = EX_OSERR;
1780
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1782
perror_plus("sigaction");
1785
if(old_sigterm_action.sa_handler != SIG_IGN){
1786
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1788
perror_plus("sigaction");
1789
exitcode = EX_OSERR;
1794
/* If the interface is down, bring it up */
1795
if(strcmp(interface, "none") != 0){
1796
if_index = (AvahiIfIndex) if_nametoindex(interface);
1798
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1799
exitcode = EX_UNAVAILABLE;
1807
/* Re-raise priviliges */
1811
perror_plus("seteuid");
1815
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1816
messages about the network interface to mess up the prompt */
1817
ret = klogctl(8, NULL, 5);
1818
bool restore_loglevel = true;
1820
restore_loglevel = false;
1821
perror_plus("klogctl");
1823
#endif /* __linux__ */
1825
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1827
perror_plus("socket");
1828
exitcode = EX_OSERR;
1830
if(restore_loglevel){
1831
ret = klogctl(7, NULL, 0);
1833
perror_plus("klogctl");
1836
#endif /* __linux__ */
1837
/* Lower privileges */
1841
perror_plus("seteuid");
1845
strcpy(network.ifr_name, interface);
1846
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1848
perror_plus("ioctl SIOCGIFFLAGS");
1850
if(restore_loglevel){
1851
ret = klogctl(7, NULL, 0);
1853
perror_plus("klogctl");
1856
#endif /* __linux__ */
1857
exitcode = EX_OSERR;
1858
/* Lower privileges */
1862
perror_plus("seteuid");
1866
if((network.ifr_flags & IFF_UP) == 0){
1867
network.ifr_flags |= IFF_UP;
1868
take_down_interface = true;
1869
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1871
take_down_interface = false;
1872
perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1873
exitcode = EX_OSERR;
1875
if(restore_loglevel){
1876
ret = klogctl(7, NULL, 0);
1878
perror_plus("klogctl");
1881
#endif /* __linux__ */
1882
/* Lower privileges */
1886
perror_plus("seteuid");
1891
/* Sleep checking until interface is running.
1892
Check every 0.25s, up to total time of delay */
1893
for(int i=0; i < delay * 4; i++){
1894
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1896
perror_plus("ioctl SIOCGIFFLAGS");
1897
} else if(network.ifr_flags & IFF_RUNNING){
1900
struct timespec sleeptime = { .tv_nsec = 250000000 };
1901
ret = nanosleep(&sleeptime, NULL);
1902
if(ret == -1 and errno != EINTR){
1903
perror_plus("nanosleep");
1906
if(not take_down_interface){
1907
/* We won't need the socket anymore */
1908
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1910
perror_plus("close");
1914
if(restore_loglevel){
1915
/* Restores kernel loglevel to default */
1916
ret = klogctl(7, NULL, 0);
1918
perror_plus("klogctl");
1921
#endif /* __linux__ */
1922
/* Lower privileges */
1924
if(take_down_interface){
1925
/* Lower privileges */
1928
perror_plus("seteuid");
1931
/* Lower privileges permanently */
1934
perror_plus("setuid");
1943
ret = init_gnutls_global(pubkey, seckey);
1945
fprintf(stderr, "init_gnutls_global failed\n");
1946
exitcode = EX_UNAVAILABLE;
1949
gnutls_initialized = true;
1956
if(mkdtemp(tempdir) == NULL){
1957
perror_plus("mkdtemp");
1960
tempdir_created = true;
1966
if(not init_gpgme(pubkey, seckey, tempdir)){
1967
fprintf(stderr, "init_gpgme failed\n");
1968
exitcode = EX_UNAVAILABLE;
1971
gpgme_initialized = true;
1978
if(connect_to != NULL){
1979
/* Connect directly, do not use Zeroconf */
1980
/* (Mainly meant for debugging) */
1981
char *address = strrchr(connect_to, ':');
1982
if(address == NULL){
1983
fprintf(stderr, "No colon in address\n");
1984
exitcode = EX_USAGE;
1994
tmpmax = strtoimax(address+1, &tmp, 10);
1995
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1996
or tmpmax != (uint16_t)tmpmax){
1997
fprintf(stderr, "Bad port number\n");
1998
exitcode = EX_USAGE;
2006
port = (uint16_t)tmpmax;
2008
/* Colon in address indicates IPv6 */
2010
if(strchr(connect_to, ':') != NULL){
2012
/* Accept [] around IPv6 address - see RFC 5952 */
2013
if(connect_to[0] == '[' and address[-1] == ']')
2021
address = connect_to;
2027
while(not quit_now){
2028
ret = start_mandos_communication(address, port, if_index, af);
2029
if(quit_now or ret == 0){
2033
fprintf(stderr, "Retrying in %d seconds\n",
2034
(int)retry_interval);
2036
sleep((int)retry_interval);
2040
exitcode = EXIT_SUCCESS;
559
2051
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 */
2052
/* Do not publish any local Zeroconf records */
604
2053
avahi_server_config_init(&config);
605
2054
config.publish_hinfo = 0;
606
2055
config.publish_addresses = 0;
607
2056
config.publish_workstation = 0;
608
2057
config.publish_domain = 0;
610
2059
/* Allocate a new server */
611
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
613
/* Free the configuration data */
2060
mc.server = avahi_server_new(avahi_simple_poll_get
2061
(mc.simple_poll), &config, NULL,
2064
/* Free the Avahi configuration data */
614
2065
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);
2068
/* Check if creating the Avahi server object succeeded */
2069
if(mc.server == NULL){
2070
fprintf(stderr, "Failed to create Avahi server: %s\n",
2071
avahi_strerror(error));
2072
exitcode = EX_UNAVAILABLE;
2080
/* Create the Avahi service browser */
2081
sb = avahi_s_service_browser_new(mc.server, if_index,
2082
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
2083
NULL, 0, browse_callback, NULL);
2085
fprintf(stderr, "Failed to create service browser: %s\n",
2086
avahi_strerror(avahi_server_errno(mc.server)));
2087
exitcode = EX_UNAVAILABLE;
2095
/* Run the main loop */
2098
fprintf(stderr, "Starting Avahi loop search\n");
2101
ret = avahi_loop_with_timeout(mc.simple_poll,
2102
(int)(retry_interval * 1000));
2104
fprintf(stderr, "avahi_loop_with_timeout exited %s\n",
2105
(ret == 0) ? "successfully" : "with error");
2111
fprintf(stderr, "%s exiting\n", argv[0]);
2114
/* Cleanup things */
2116
avahi_s_service_browser_free(sb);
2118
if(mc.server != NULL)
2119
avahi_server_free(mc.server);
2121
if(mc.simple_poll != NULL)
2122
avahi_simple_poll_free(mc.simple_poll);
2124
if(gnutls_initialized){
2125
gnutls_certificate_free_credentials(mc.cred);
2126
gnutls_global_deinit();
2127
gnutls_dh_params_deinit(mc.dh_params);
2130
if(gpgme_initialized){
2131
gpgme_release(mc.ctx);
2134
/* Cleans up the circular linked list of Mandos servers the client
2136
if(mc.current_server != NULL){
2137
mc.current_server->prev->next = NULL;
2138
while(mc.current_server != NULL){
2139
server *next = mc.current_server->next;
2140
free(mc.current_server);
2141
mc.current_server = next;
2145
/* XXX run network hooks "stop" here */
2147
/* Take down the network interface */
2148
if(take_down_interface){
2149
/* Re-raise priviliges */
2153
perror_plus("seteuid");
2156
ret = ioctl(sd, SIOCGIFFLAGS, &network);
2158
perror_plus("ioctl SIOCGIFFLAGS");
2159
} else if(network.ifr_flags & IFF_UP) {
2160
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
2161
ret = ioctl(sd, SIOCSIFFLAGS, &network);
2163
perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
2166
ret = (int)TEMP_FAILURE_RETRY(close(sd));
2168
perror_plus("close");
2170
/* Lower privileges permanently */
2174
perror_plus("setuid");
2179
/* Removes the GPGME temp directory and all files inside */
2180
if(tempdir_created){
2181
struct dirent **direntries = NULL;
2182
struct dirent *direntry = NULL;
2183
int numentries = scandir(tempdir, &direntries, notdotentries,
2185
if (numentries > 0){
2186
for(int i = 0; i < numentries; i++){
2187
direntry = direntries[i];
2188
char *fullname = NULL;
2189
ret = asprintf(&fullname, "%s/%s", tempdir,
2192
perror_plus("asprintf");
2195
ret = remove(fullname);
2197
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
2204
/* need to clean even if 0 because man page doesn't specify */
2206
if (numentries == -1){
2207
perror_plus("scandir");
2209
ret = rmdir(tempdir);
2210
if(ret == -1 and errno != ENOENT){
2211
perror_plus("rmdir");
2216
sigemptyset(&old_sigterm_action.sa_mask);
2217
old_sigterm_action.sa_handler = SIG_DFL;
2218
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
2219
&old_sigterm_action,
2222
perror_plus("sigaction");
2225
ret = raise(signal_received);
2226
} while(ret != 0 and errno == EINTR);
2228
perror_plus("raise");
2231
TEMP_FAILURE_RETRY(pause());