123
346
/* Create new empty GPGME data buffer for the plaintext */
124
347
rc = gpgme_data_new(&dh_plain);
125
if (rc != GPG_ERR_NO_ERROR){
348
if(rc != GPG_ERR_NO_ERROR){
126
349
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
127
350
gpgme_strsource(rc), gpgme_strerror(rc));
131
/* Create new GPGME "context" */
132
rc = gpgme_new(&ctx);
133
if (rc != GPG_ERR_NO_ERROR){
134
fprintf(stderr, "bad gpgme_new: %s: %s\n",
135
gpgme_strsource(rc), gpgme_strerror(rc));
139
/* Decrypt data from the FILE pointer to the plaintext data buffer */
140
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
141
if (rc != GPG_ERR_NO_ERROR){
351
gpgme_data_release(dh_crypto);
355
/* Decrypt data from the cryptotext data buffer to the plaintext
357
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
358
if(rc != GPG_ERR_NO_ERROR){
142
359
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
143
360
gpgme_strsource(rc), gpgme_strerror(rc));
361
plaintext_length = -1;
363
gpgme_decrypt_result_t result;
364
result = gpgme_op_decrypt_result(mc.ctx);
366
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
368
fprintf(stderr, "Unsupported algorithm: %s\n",
369
result->unsupported_algorithm);
370
fprintf(stderr, "Wrong key usage: %u\n",
371
result->wrong_key_usage);
372
if(result->file_name != NULL){
373
fprintf(stderr, "File name: %s\n", result->file_name);
375
gpgme_recipient_t recipient;
376
recipient = result->recipients;
377
while(recipient != NULL){
378
fprintf(stderr, "Public key algorithm: %s\n",
379
gpgme_pubkey_algo_name(recipient->pubkey_algo));
380
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
381
fprintf(stderr, "Secret key available: %s\n",
382
recipient->status == GPG_ERR_NO_SECKEY
384
recipient = recipient->next;
147
/* gpgme_decrypt_result_t result; */
148
/* result = gpgme_op_decrypt_result(ctx); */
149
/* fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm); */
150
/* fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage); */
151
/* if(result->file_name != NULL){ */
152
/* fprintf(stderr, "File name: %s\n", result->file_name); */
154
/* gpgme_recipient_t recipient; */
155
/* recipient = result->recipients; */
157
/* while(recipient != NULL){ */
158
/* fprintf(stderr, "Public key algorithm: %s\n", */
159
/* gpgme_pubkey_algo_name(recipient->pubkey_algo)); */
160
/* fprintf(stderr, "Key ID: %s\n", recipient->keyid); */
161
/* fprintf(stderr, "Secret key available: %s\n", */
162
/* recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes"); */
163
/* recipient = recipient->next; */
167
/* Delete the GPGME FILE pointer cryptotext data buffer */
168
gpgme_data_release(dh_crypto);
392
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
170
395
/* Seek back to the beginning of the GPGME plaintext data buffer */
171
gpgme_data_seek(dh_plain, 0, SEEK_SET);
396
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
397
perror_plus("gpgme_data_seek");
398
plaintext_length = -1;
175
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
176
*new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
177
if (*new_packet == NULL){
181
new_packet_capacity += BUFFER_SIZE;
404
plaintext_capacity = incbuffer(plaintext,
405
(size_t)plaintext_length,
407
if(plaintext_capacity == 0){
408
perror_plus("incbuffer");
409
plaintext_length = -1;
184
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
413
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
185
415
/* Print the data, if any */
187
/* If password is empty, then a incorrect error will be printed */
191
perror("gpgme_data_read");
194
new_packet_length += ret;
197
/* Delete the GPGME plaintext data buffer */
421
perror_plus("gpgme_data_read");
422
plaintext_length = -1;
425
plaintext_length += ret;
429
fprintf(stderr, "Decrypted password is: ");
430
for(ssize_t i = 0; i < plaintext_length; i++){
431
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
433
fprintf(stderr, "\n");
438
/* Delete the GPGME cryptotext data buffer */
439
gpgme_data_release(dh_crypto);
441
/* Delete the GPGME plaintext data buffer */
198
442
gpgme_data_release(dh_plain);
199
return new_packet_length;
443
return plaintext_length;
202
static const char * safer_gnutls_strerror (int value) {
203
const char *ret = gnutls_strerror (value);
446
static const char * safer_gnutls_strerror(int value){
447
const char *ret = gnutls_strerror(value); /* Spurious warning from
448
-Wunreachable-code */
205
450
ret = "(unknown)";
209
void debuggnutls(int level, const char* string){
210
fprintf(stderr, "%s", string);
454
/* GnuTLS log function callback */
455
static void debuggnutls(__attribute__((unused)) int level,
457
fprintf(stderr, "GnuTLS: %s", string);
213
int initgnutls(encrypted_session *es){
460
static int init_gnutls_global(const char *pubkeyfilename,
461
const char *seckeyfilename){
217
if ((ret = gnutls_global_init ())
218
!= GNUTLS_E_SUCCESS) {
219
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
223
/* Uncomment to enable full debuggin on the gnutls library */
224
/* gnutls_global_set_log_level(11); */
225
/* gnutls_global_set_log_function(debuggnutls); */
228
/* openpgp credentials */
229
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
230
!= GNUTLS_E_SUCCESS) {
231
fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
465
fprintf(stderr, "Initializing GnuTLS\n");
468
ret = gnutls_global_init();
469
if(ret != GNUTLS_E_SUCCESS){
470
fprintf(stderr, "GnuTLS global_init: %s\n",
471
safer_gnutls_strerror(ret));
476
/* "Use a log level over 10 to enable all debugging options."
479
gnutls_global_set_log_level(11);
480
gnutls_global_set_log_function(debuggnutls);
483
/* OpenPGP credentials */
484
ret = gnutls_certificate_allocate_credentials(&mc.cred);
485
if(ret != GNUTLS_E_SUCCESS){
486
fprintf(stderr, "GnuTLS memory error: %s\n",
487
safer_gnutls_strerror(ret));
488
gnutls_global_deinit();
493
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
494
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
235
498
ret = gnutls_certificate_set_openpgp_key_file
236
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
237
if (ret != GNUTLS_E_SUCCESS) {
239
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
240
ret, CERTFILE, KEYFILE);
241
fprintf(stdout, "The Error is: %s\n",
242
safer_gnutls_strerror(ret));
246
//Gnutls server initialization
247
if ((ret = gnutls_dh_params_init (&es->dh_params))
248
!= GNUTLS_E_SUCCESS) {
249
fprintf (stderr, "Error in dh parameter initialization: %s\n",
250
safer_gnutls_strerror(ret));
254
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
255
!= GNUTLS_E_SUCCESS) {
256
fprintf (stderr, "Error in prime generation: %s\n",
257
safer_gnutls_strerror(ret));
261
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
263
// Gnutls session creation
264
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
265
!= GNUTLS_E_SUCCESS){
266
fprintf(stderr, "Error in gnutls session initialization: %s\n",
267
safer_gnutls_strerror(ret));
270
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
271
!= GNUTLS_E_SUCCESS) {
272
fprintf(stderr, "Syntax error at: %s\n", err);
273
fprintf(stderr, "Gnutls error: %s\n",
274
safer_gnutls_strerror(ret));
278
if ((ret = gnutls_credentials_set
279
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
280
!= GNUTLS_E_SUCCESS) {
281
fprintf(stderr, "Error setting a credentials set: %s\n",
282
safer_gnutls_strerror(ret));
499
(mc.cred, pubkeyfilename, seckeyfilename,
500
GNUTLS_OPENPGP_FMT_BASE64);
501
if(ret != GNUTLS_E_SUCCESS){
503
"Error[%d] while reading the OpenPGP key pair ('%s',"
504
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
505
fprintf(stderr, "The GnuTLS error is: %s\n",
506
safer_gnutls_strerror(ret));
510
/* GnuTLS server initialization */
511
ret = gnutls_dh_params_init(&mc.dh_params);
512
if(ret != GNUTLS_E_SUCCESS){
513
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
514
" %s\n", safer_gnutls_strerror(ret));
517
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
518
if(ret != GNUTLS_E_SUCCESS){
519
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
520
safer_gnutls_strerror(ret));
524
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
530
gnutls_certificate_free_credentials(mc.cred);
531
gnutls_global_deinit();
532
gnutls_dh_params_deinit(mc.dh_params);
536
static int init_gnutls_session(gnutls_session_t *session){
538
/* GnuTLS session creation */
540
ret = gnutls_init(session, GNUTLS_SERVER);
544
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
545
if(ret != GNUTLS_E_SUCCESS){
546
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
547
safer_gnutls_strerror(ret));
553
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
555
gnutls_deinit(*session);
558
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
559
if(ret != GNUTLS_E_SUCCESS){
560
fprintf(stderr, "Syntax error at: %s\n", err);
561
fprintf(stderr, "GnuTLS error: %s\n",
562
safer_gnutls_strerror(ret));
563
gnutls_deinit(*session);
569
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
572
gnutls_deinit(*session);
575
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
576
if(ret != GNUTLS_E_SUCCESS){
577
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
578
safer_gnutls_strerror(ret));
579
gnutls_deinit(*session);
286
583
/* ignore client certificate if any. */
287
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
584
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
289
gnutls_dh_set_prime_bits (es->session, DH_BITS);
586
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
294
void empty_log(AvahiLogLevel level, const char *txt){}
591
/* Avahi log function callback */
592
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
593
__attribute__((unused)) const char *txt){}
296
int start_mandos_communcation(char *ip, uint16_t port){
298
struct sockaddr_in6 to;
299
struct in6_addr ip_addr;
300
encrypted_session es;
595
/* Called when a Mandos server is found */
596
static int start_mandos_communication(const char *ip, uint16_t port,
597
AvahiIfIndex if_index,
599
int ret, tcp_sd = -1;
602
struct sockaddr_in in;
603
struct sockaddr_in6 in6;
301
605
char *buffer = NULL;
302
char *decrypted_buffer;
606
char *decrypted_buffer = NULL;
303
607
size_t buffer_length = 0;
304
608
size_t buffer_capacity = 0;
305
ssize_t decrypted_buffer_size;
309
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
315
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
317
perror("setsockopt bindtodevice");
321
memset(&to,0,sizeof(to));
322
to.sin6_family = AF_INET6;
323
ret = inet_pton(AF_INET6, ip, &ip_addr);
611
gnutls_session_t session;
612
int pf; /* Protocol family */
629
fprintf(stderr, "Bad address family: %d\n", af);
634
ret = init_gnutls_session(&session);
640
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
644
tcp_sd = socket(pf, SOCK_STREAM, 0);
647
perror_plus("socket");
657
memset(&to, 0, sizeof(to));
659
to.in6.sin6_family = (sa_family_t)af;
660
ret = inet_pton(af, ip, &to.in6.sin6_addr);
662
to.in.sin_family = (sa_family_t)af;
663
ret = inet_pton(af, ip, &to.in.sin_addr);
667
perror_plus("inet_pton");
329
673
fprintf(stderr, "Bad address: %s\n", ip);
332
to.sin6_port = htons(port);
333
to.sin6_scope_id = if_nametoindex("eth0");
335
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
341
ret = initgnutls (&es);
348
gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
350
ret = gnutls_handshake (es.session);
352
if (ret != GNUTLS_E_SUCCESS){
353
fprintf(stderr, "\n*** Handshake failed ***\n");
361
if (buffer_length + BUFFER_SIZE > buffer_capacity){
362
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
367
buffer_capacity += BUFFER_SIZE;
370
ret = gnutls_record_recv
371
(es.session, buffer+buffer_length, BUFFER_SIZE);
678
to.in6.sin6_port = htons(port); /* Spurious warnings from
680
-Wunreachable-code */
682
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
683
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
685
if(if_index == AVAHI_IF_UNSPEC){
686
fprintf(stderr, "An IPv6 link-local address is incomplete"
687
" without a network interface\n");
691
/* Set the network interface number as scope */
692
to.in6.sin6_scope_id = (uint32_t)if_index;
695
to.in.sin_port = htons(port); /* Spurious warnings from
697
-Wunreachable-code */
706
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
707
char interface[IF_NAMESIZE];
708
if(if_indextoname((unsigned int)if_index, interface) == NULL){
709
perror_plus("if_indextoname");
711
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
712
ip, interface, port);
715
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
718
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
719
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
722
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
725
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
729
perror_plus("inet_ntop");
731
if(strcmp(addrstr, ip) != 0){
732
fprintf(stderr, "Canonical address form: %s\n", addrstr);
743
ret = connect(tcp_sd, &to.in6, sizeof(to));
745
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
748
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
750
perror_plus("connect");
761
const char *out = mandos_protocol_version;
764
size_t out_size = strlen(out);
765
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
766
out_size - written));
769
perror_plus("write");
773
written += (size_t)ret;
774
if(written < out_size){
777
if(out == mandos_protocol_version){
792
fprintf(stderr, "Establishing TLS session with %s\n", ip);
800
/* Spurious warning from -Wint-to-pointer-cast */
801
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
809
ret = gnutls_handshake(session);
814
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
816
if(ret != GNUTLS_E_SUCCESS){
818
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
825
/* Read OpenPGP packet that contains the wanted password */
828
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
839
buffer_capacity = incbuffer(&buffer, buffer_length,
841
if(buffer_capacity == 0){
843
perror_plus("incbuffer");
853
sret = gnutls_record_recv(session, buffer+buffer_length,
377
860
case GNUTLS_E_INTERRUPTED:
378
861
case GNUTLS_E_AGAIN:
380
863
case GNUTLS_E_REHANDSHAKE:
381
ret = gnutls_handshake (es.session);
383
fprintf(stderr, "\n*** Handshake failed ***\n");
865
ret = gnutls_handshake(session);
871
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
873
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
390
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
392
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
880
fprintf(stderr, "Unknown error while reading data from"
881
" encrypted session with Mandos server\n");
882
gnutls_bye(session, GNUTLS_SHUT_RDWR);
396
buffer_length += ret;
400
if (buffer_length > 0){
401
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
887
buffer_length += (size_t) sret;
892
fprintf(stderr, "Closing TLS session\n");
901
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
906
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
908
if(buffer_length > 0){
909
ssize_t decrypted_buffer_size;
910
decrypted_buffer_size = pgp_packet_decrypt(buffer,
913
if(decrypted_buffer_size >= 0){
916
while(written < (size_t) decrypted_buffer_size){
922
ret = (int)fwrite(decrypted_buffer + written, 1,
923
(size_t)decrypted_buffer_size - written,
925
if(ret == 0 and ferror(stdout)){
928
fprintf(stderr, "Error writing encrypted data: %s\n",
934
written += (size_t)ret;
940
/* Shutdown procedure */
945
free(decrypted_buffer);
948
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
954
perror_plus("close");
956
gnutls_deinit(session);
404
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
405
free(decrypted_buffer);
412
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
415
gnutls_deinit (es.session);
416
gnutls_certificate_free_credentials (es.cred);
417
gnutls_global_deinit ();
421
static AvahiSimplePoll *simple_poll = NULL;
422
static AvahiServer *server = NULL;
424
static void resolve_callback(
425
AvahiSServiceResolver *r,
426
AVAHI_GCC_UNUSED AvahiIfIndex interface,
427
AVAHI_GCC_UNUSED AvahiProtocol protocol,
428
AvahiResolverEvent event,
432
const char *host_name,
433
const AvahiAddress *address,
435
AvahiStringList *txt,
436
AvahiLookupResultFlags flags,
437
AVAHI_GCC_UNUSED void* userdata) {
441
/* Called whenever a service has been resolved successfully or timed out */
444
case AVAHI_RESOLVER_FAILURE:
445
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)));
448
case AVAHI_RESOLVER_FOUND: {
449
char ip[AVAHI_ADDRESS_STR_MAX];
450
avahi_address_snprint(ip, sizeof(ip), address);
451
int ret = start_mandos_communcation(ip, port);
459
avahi_s_service_resolver_free(r);
462
static void browse_callback(
463
AvahiSServiceBrowser *b,
464
AvahiIfIndex interface,
465
AvahiProtocol protocol,
466
AvahiBrowserEvent event,
470
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
473
AvahiServer *s = userdata;
476
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
480
case AVAHI_BROWSER_FAILURE:
482
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
483
avahi_simple_poll_quit(simple_poll);
486
case AVAHI_BROWSER_NEW:
487
/* We ignore the returned resolver object. In the callback
488
function we free it. If the server is terminated before
489
the callback function is called the server will free
490
the resolver for us. */
492
if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
493
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
497
case AVAHI_BROWSER_REMOVE:
500
case AVAHI_BROWSER_ALL_FOR_NOW:
501
case AVAHI_BROWSER_CACHE_EXHAUSTED:
506
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
966
static void resolve_callback(AvahiSServiceResolver *r,
967
AvahiIfIndex interface,
969
AvahiResolverEvent event,
973
const char *host_name,
974
const AvahiAddress *address,
976
AVAHI_GCC_UNUSED AvahiStringList *txt,
977
AVAHI_GCC_UNUSED AvahiLookupResultFlags
979
AVAHI_GCC_UNUSED void* userdata){
982
/* Called whenever a service has been resolved successfully or
991
case AVAHI_RESOLVER_FAILURE:
992
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
993
" of type '%s' in domain '%s': %s\n", name, type, domain,
994
avahi_strerror(avahi_server_errno(mc.server)));
997
case AVAHI_RESOLVER_FOUND:
999
char ip[AVAHI_ADDRESS_STR_MAX];
1000
avahi_address_snprint(ip, sizeof(ip), address);
1002
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
1003
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
1004
ip, (intmax_t)interface, port);
1006
int ret = start_mandos_communication(ip, port, interface,
1007
avahi_proto_to_af(proto));
1009
avahi_simple_poll_quit(mc.simple_poll);
1011
ret = add_server(ip, port, interface,
1012
avahi_proto_to_af(proto));
1016
avahi_s_service_resolver_free(r);
1019
static void browse_callback(AvahiSServiceBrowser *b,
1020
AvahiIfIndex interface,
1021
AvahiProtocol protocol,
1022
AvahiBrowserEvent event,
1026
AVAHI_GCC_UNUSED AvahiLookupResultFlags
1028
AVAHI_GCC_UNUSED void* userdata){
1031
/* Called whenever a new services becomes available on the LAN or
1032
is removed from the LAN */
1040
case AVAHI_BROWSER_FAILURE:
1042
fprintf(stderr, "(Avahi browser) %s\n",
1043
avahi_strerror(avahi_server_errno(mc.server)));
1044
avahi_simple_poll_quit(mc.simple_poll);
1047
case AVAHI_BROWSER_NEW:
1048
/* We ignore the returned Avahi resolver object. In the callback
1049
function we free it. If the Avahi server is terminated before
1050
the callback function is called the Avahi server will free the
1053
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
1054
name, type, domain, protocol, 0,
1055
resolve_callback, NULL) == NULL)
1056
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
1057
name, avahi_strerror(avahi_server_errno(mc.server)));
1060
case AVAHI_BROWSER_REMOVE:
1063
case AVAHI_BROWSER_ALL_FOR_NOW:
1064
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1066
fprintf(stderr, "No Mandos server found, still searching...\n");
1072
/* Signal handler that stops main loop after SIGTERM */
1073
static void handle_sigterm(int sig){
1078
signal_received = sig;
1079
int old_errno = errno;
1080
/* set main loop to exit */
1081
if(mc.simple_poll != NULL){
1082
avahi_simple_poll_quit(mc.simple_poll);
1088
* This function determines if a directory entry in /sys/class/net
1089
* corresponds to an acceptable network device.
1090
* (This function is passed to scandir(3) as a filter function.)
1092
int good_interface(const struct dirent *if_entry){
1094
char *flagname = NULL;
1095
if(if_entry->d_name[0] == '.'){
1098
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1101
perror_plus("asprintf");
1104
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1106
perror_plus("open");
1111
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1112
/* read line from flags_fd */
1113
ssize_t to_read = 2+(sizeof(ifreq_flags)*2)+1; /* "0x1003\n" */
1114
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1115
flagstring[(size_t)to_read] = '\0';
1116
if(flagstring == NULL){
1117
perror_plus("malloc");
1122
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1125
perror_plus("read");
1139
tmpmax = strtoimax(flagstring, &tmp, 0);
1140
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1141
and not (isspace(*tmp)))
1142
or tmpmax != (ifreq_flags)tmpmax){
1144
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1145
flagstring, if_entry->d_name);
1151
ifreq_flags flags = (ifreq_flags)tmpmax;
1152
/* Reject the loopback device */
1153
if(flags & IFF_LOOPBACK){
1155
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1160
/* Accept point-to-point devices only if connect_to is specified */
1161
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1163
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1168
/* Otherwise, reject non-broadcast-capable devices */
1169
if(not (flags & IFF_BROADCAST)){
1171
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1176
/* Reject non-ARP interfaces (including dummy interfaces) */
1177
if(flags & IFF_NOARP){
1179
fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n",
1184
/* Accept this device */
1186
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1192
int notdotentries(const struct dirent *direntry){
1193
/* Skip "." and ".." */
1194
if(direntry->d_name[0] == '.'
1195
and (direntry->d_name[1] == '\0'
1196
or (direntry->d_name[1] == '.'
1197
and direntry->d_name[2] == '\0'))){
1203
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval){
1205
struct timespec now;
1206
struct timespec waited_time;
1207
intmax_t block_time;
1210
if(mc.current_server == NULL){
1213
"Wait until first server is found. No timeout!\n");
1215
ret = avahi_simple_poll_iterate(s, -1);
1218
fprintf(stderr, "Check current_server if we should run it,"
1221
/* the current time */
1222
ret = clock_gettime(CLOCK_MONOTONIC, &now);
1224
perror_plus("clock_gettime");
1227
/* Calculating in ms how long time between now and server
1228
who we visted longest time ago. Now - last seen. */
1229
waited_time.tv_sec = (now.tv_sec
1230
- mc.current_server->last_seen.tv_sec);
1231
waited_time.tv_nsec = (now.tv_nsec
1232
- mc.current_server->last_seen.tv_nsec);
1233
/* total time is 10s/10,000ms.
1234
Converting to s from ms by dividing by 1,000,
1235
and ns to ms by dividing by 1,000,000. */
1236
block_time = ((retry_interval
1237
- ((intmax_t)waited_time.tv_sec * 1000))
1238
- ((intmax_t)waited_time.tv_nsec / 1000000));
1241
fprintf(stderr, "Blocking for %ld ms\n", block_time);
1244
if(block_time <= 0){
1245
ret = start_mandos_communication(mc.current_server->ip,
1246
mc.current_server->port,
1247
mc.current_server->if_index,
1248
mc.current_server->af);
1250
avahi_simple_poll_quit(mc.simple_poll);
1253
ret = clock_gettime(CLOCK_MONOTONIC,
1254
&mc.current_server->last_seen);
1256
perror_plus("clock_gettime");
1259
mc.current_server = mc.current_server->next;
1260
block_time = 0; /* Call avahi to find new Mandos
1261
servers, but don't block */
1264
ret = avahi_simple_poll_iterate(s, (int)block_time);
1267
if (ret > 0 or errno != EINTR) {
1268
return (ret != 1) ? ret : 0;
1274
int main(int argc, char *argv[]){
1275
AvahiSServiceBrowser *sb = NULL;
1280
int exitcode = EXIT_SUCCESS;
1281
const char *interface = "";
1282
struct ifreq network;
1284
bool take_down_interface = false;
1287
char tempdir[] = "/tmp/mandosXXXXXX";
1288
bool tempdir_created = false;
1289
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1290
const char *seckey = PATHDIR "/" SECKEY;
1291
const char *pubkey = PATHDIR "/" PUBKEY;
1293
bool gnutls_initialized = false;
1294
bool gpgme_initialized = false;
1296
double retry_interval = 10; /* 10s between trying a server and
1297
retrying the same server again */
1299
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1300
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1305
/* Lower any group privileges we might have, just to be safe */
1309
perror_plus("setgid");
1312
/* Lower user privileges (temporarily) */
1316
perror_plus("seteuid");
1324
struct argp_option options[] = {
1325
{ .name = "debug", .key = 128,
1326
.doc = "Debug mode", .group = 3 },
1327
{ .name = "connect", .key = 'c',
1328
.arg = "ADDRESS:PORT",
1329
.doc = "Connect directly to a specific Mandos server",
1331
{ .name = "interface", .key = 'i',
1333
.doc = "Network interface that will be used to search for"
1336
{ .name = "seckey", .key = 's',
1338
.doc = "OpenPGP secret key file base name",
1340
{ .name = "pubkey", .key = 'p',
1342
.doc = "OpenPGP public key file base name",
1344
{ .name = "dh-bits", .key = 129,
1346
.doc = "Bit length of the prime number used in the"
1347
" Diffie-Hellman key exchange",
1349
{ .name = "priority", .key = 130,
1351
.doc = "GnuTLS priority string for the TLS handshake",
1353
{ .name = "delay", .key = 131,
1355
.doc = "Maximum delay to wait for interface startup",
1357
{ .name = "retry", .key = 132,
1359
.doc = "Retry interval used when denied by the mandos server",
1362
* These reproduce what we would get without ARGP_NO_HELP
1364
{ .name = "help", .key = '?',
1365
.doc = "Give this help list", .group = -1 },
1366
{ .name = "usage", .key = -3,
1367
.doc = "Give a short usage message", .group = -1 },
1368
{ .name = "version", .key = 'V',
1369
.doc = "Print program version", .group = -1 },
1373
error_t parse_opt(int key, char *arg,
1374
struct argp_state *state){
1377
case 128: /* --debug */
1380
case 'c': /* --connect */
1383
case 'i': /* --interface */
1386
case 's': /* --seckey */
1389
case 'p': /* --pubkey */
1392
case 129: /* --dh-bits */
1394
tmpmax = strtoimax(arg, &tmp, 10);
1395
if(errno != 0 or tmp == arg or *tmp != '\0'
1396
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1397
argp_error(state, "Bad number of DH bits");
1399
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1401
case 130: /* --priority */
1404
case 131: /* --delay */
1406
delay = strtof(arg, &tmp);
1407
if(errno != 0 or tmp == arg or *tmp != '\0'){
1408
argp_error(state, "Bad delay");
1410
case 132: /* --retry */
1412
retry_interval = strtod(arg, &tmp);
1413
if(errno != 0 or tmp == arg or *tmp != '\0'
1414
or (retry_interval * 1000) > INT_MAX){
1415
argp_error(state, "Bad retry interval");
1419
* These reproduce what we would get without ARGP_NO_HELP
1421
case '?': /* --help */
1422
argp_state_help(state, state->out_stream,
1423
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1424
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1425
case -3: /* --usage */
1426
argp_state_help(state, state->out_stream,
1427
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1428
case 'V': /* --version */
1429
fprintf(state->out_stream, "%s\n", argp_program_version);
1430
exit(argp_err_exit_status);
1433
return ARGP_ERR_UNKNOWN;
1438
struct argp argp = { .options = options, .parser = parse_opt,
1440
.doc = "Mandos client -- Get and decrypt"
1441
" passwords from a Mandos server" };
1442
ret = argp_parse(&argp, argc, argv,
1443
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
1450
perror_plus("argp_parse");
1451
exitcode = EX_OSERR;
1454
exitcode = EX_USAGE;
1460
/* Work around Debian bug #633582:
1461
<http://bugs.debian.org/633582> */
1464
/* Re-raise priviliges */
1468
perror_plus("seteuid");
1471
int seckey_fd = open(PATHDIR "/" SECKEY, O_RDONLY);
1472
if(seckey_fd == -1){
1473
perror_plus("open");
1475
ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
1477
perror_plus("fstat");
1479
if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
1480
ret = fchown(seckey_fd, uid, gid);
1482
perror_plus("fchown");
1486
TEMP_FAILURE_RETRY(close(seckey_fd));
1489
int pubkey_fd = open(PATHDIR "/" PUBKEY, O_RDONLY);
1490
if(pubkey_fd == -1){
1491
perror_plus("open");
1493
ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
1495
perror_plus("fstat");
1497
if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
1498
ret = fchown(pubkey_fd, uid, gid);
1500
perror_plus("fchown");
1504
TEMP_FAILURE_RETRY(close(pubkey_fd));
1507
/* Lower privileges */
1511
perror_plus("seteuid");
1516
avahi_set_log_function(empty_log);
1519
if(interface[0] == '\0'){
1520
struct dirent **direntries;
1521
ret = scandir(sys_class_net, &direntries, good_interface,
1524
/* Pick the first good interface */
1525
interface = strdup(direntries[0]->d_name);
1527
fprintf(stderr, "Using interface \"%s\"\n", interface);
1529
if(interface == NULL){
1530
perror_plus("malloc");
1532
exitcode = EXIT_FAILURE;
1538
fprintf(stderr, "Could not find a network interface\n");
1539
exitcode = EXIT_FAILURE;
1544
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1545
from the signal handler */
1546
/* Initialize the pseudo-RNG for Avahi */
1547
srand((unsigned int) time(NULL));
1548
mc.simple_poll = avahi_simple_poll_new();
1549
if(mc.simple_poll == NULL){
1550
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1551
exitcode = EX_UNAVAILABLE;
1555
sigemptyset(&sigterm_action.sa_mask);
1556
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1558
perror_plus("sigaddset");
1559
exitcode = EX_OSERR;
1562
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1564
perror_plus("sigaddset");
1565
exitcode = EX_OSERR;
1568
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1570
perror_plus("sigaddset");
1571
exitcode = EX_OSERR;
1574
/* Need to check if the handler is SIG_IGN before handling:
1575
| [[info:libc:Initial Signal Actions]] |
1576
| [[info:libc:Basic Signal Handling]] |
1578
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1580
perror_plus("sigaction");
1583
if(old_sigterm_action.sa_handler != SIG_IGN){
1584
ret = sigaction(SIGINT, &sigterm_action, NULL);
1586
perror_plus("sigaction");
1587
exitcode = EX_OSERR;
1591
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1593
perror_plus("sigaction");
1596
if(old_sigterm_action.sa_handler != SIG_IGN){
1597
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1599
perror_plus("sigaction");
1600
exitcode = EX_OSERR;
1604
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1606
perror_plus("sigaction");
1609
if(old_sigterm_action.sa_handler != SIG_IGN){
1610
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1612
perror_plus("sigaction");
1613
exitcode = EX_OSERR;
1618
/* If the interface is down, bring it up */
1619
if(strcmp(interface, "none") != 0){
1620
if_index = (AvahiIfIndex) if_nametoindex(interface);
1622
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1623
exitcode = EX_UNAVAILABLE;
1631
/* Re-raise priviliges */
1635
perror_plus("seteuid");
1639
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1640
messages about the network interface to mess up the prompt */
1641
ret = klogctl(8, NULL, 5);
1642
bool restore_loglevel = true;
1644
restore_loglevel = false;
1645
perror_plus("klogctl");
1647
#endif /* __linux__ */
1649
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1651
perror_plus("socket");
1652
exitcode = EX_OSERR;
1654
if(restore_loglevel){
1655
ret = klogctl(7, NULL, 0);
1657
perror_plus("klogctl");
1660
#endif /* __linux__ */
1661
/* Lower privileges */
1665
perror_plus("seteuid");
1669
strcpy(network.ifr_name, interface);
1670
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1672
perror_plus("ioctl SIOCGIFFLAGS");
1674
if(restore_loglevel){
1675
ret = klogctl(7, NULL, 0);
1677
perror_plus("klogctl");
1680
#endif /* __linux__ */
1681
exitcode = EX_OSERR;
1682
/* Lower privileges */
1686
perror_plus("seteuid");
1690
if((network.ifr_flags & IFF_UP) == 0){
1691
network.ifr_flags |= IFF_UP;
1692
take_down_interface = true;
1693
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1695
take_down_interface = false;
1696
perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1697
exitcode = EX_OSERR;
1699
if(restore_loglevel){
1700
ret = klogctl(7, NULL, 0);
1702
perror_plus("klogctl");
1705
#endif /* __linux__ */
1706
/* Lower privileges */
1710
perror_plus("seteuid");
1715
/* Sleep checking until interface is running.
1716
Check every 0.25s, up to total time of delay */
1717
for(int i=0; i < delay * 4; i++){
1718
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1720
perror_plus("ioctl SIOCGIFFLAGS");
1721
} else if(network.ifr_flags & IFF_RUNNING){
1724
struct timespec sleeptime = { .tv_nsec = 250000000 };
1725
ret = nanosleep(&sleeptime, NULL);
1726
if(ret == -1 and errno != EINTR){
1727
perror_plus("nanosleep");
1730
if(not take_down_interface){
1731
/* We won't need the socket anymore */
1732
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1734
perror_plus("close");
1738
if(restore_loglevel){
1739
/* Restores kernel loglevel to default */
1740
ret = klogctl(7, NULL, 0);
1742
perror_plus("klogctl");
1745
#endif /* __linux__ */
1746
/* Lower privileges */
1748
if(take_down_interface){
1749
/* Lower privileges */
1752
perror_plus("seteuid");
1755
/* Lower privileges permanently */
1758
perror_plus("setuid");
1767
ret = init_gnutls_global(pubkey, seckey);
1769
fprintf(stderr, "init_gnutls_global failed\n");
1770
exitcode = EX_UNAVAILABLE;
1773
gnutls_initialized = true;
1780
if(mkdtemp(tempdir) == NULL){
1781
perror_plus("mkdtemp");
1784
tempdir_created = true;
1790
if(not init_gpgme(pubkey, seckey, tempdir)){
1791
fprintf(stderr, "init_gpgme failed\n");
1792
exitcode = EX_UNAVAILABLE;
1795
gpgme_initialized = true;
1802
if(connect_to != NULL){
1803
/* Connect directly, do not use Zeroconf */
1804
/* (Mainly meant for debugging) */
1805
char *address = strrchr(connect_to, ':');
1806
if(address == NULL){
1807
fprintf(stderr, "No colon in address\n");
1808
exitcode = EX_USAGE;
1818
tmpmax = strtoimax(address+1, &tmp, 10);
1819
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1820
or tmpmax != (uint16_t)tmpmax){
1821
fprintf(stderr, "Bad port number\n");
1822
exitcode = EX_USAGE;
1830
port = (uint16_t)tmpmax;
1832
address = connect_to;
1833
/* Colon in address indicates IPv6 */
1835
if(strchr(address, ':') != NULL){
1845
while(not quit_now){
1846
ret = start_mandos_communication(address, port, if_index, af);
1847
if(quit_now or ret == 0){
1850
sleep((int)retry_interval or 1);
1854
exitcode = EXIT_SUCCESS;
507
1865
AvahiServerConfig config;
508
AvahiSServiceBrowser *sb = NULL;
512
avahi_set_log_function(empty_log);
514
/* Initialize the psuedo-RNG */
517
/* Allocate main loop object */
518
if (!(simple_poll = avahi_simple_poll_new())) {
519
fprintf(stderr, "Failed to create simple poll object.\n");
523
/* Do not publish any local records */
1866
/* Do not publish any local Zeroconf records */
524
1867
avahi_server_config_init(&config);
525
1868
config.publish_hinfo = 0;
526
1869
config.publish_addresses = 0;
527
1870
config.publish_workstation = 0;
528
1871
config.publish_domain = 0;
530
/* /\* Set a unicast DNS server for wide area DNS-SD *\/ */
531
/* avahi_address_parse("193.11.177.11", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]); */
532
/* config.n_wide_area_servers = 1; */
533
/* config.enable_wide_area = 1; */
535
1873
/* Allocate a new server */
536
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
538
/* Free the configuration data */
1874
mc.server = avahi_server_new(avahi_simple_poll_get
1875
(mc.simple_poll), &config, NULL,
1878
/* Free the Avahi configuration data */
539
1879
avahi_server_config_free(&config);
541
/* Check wether creating the server object succeeded */
543
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
547
/* Create the service browser */
548
if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
549
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
553
/* Run the main loop */
554
avahi_simple_poll_loop(simple_poll);
562
avahi_s_service_browser_free(sb);
565
avahi_server_free(server);
568
avahi_simple_poll_free(simple_poll);
1882
/* Check if creating the Avahi server object succeeded */
1883
if(mc.server == NULL){
1884
fprintf(stderr, "Failed to create Avahi server: %s\n",
1885
avahi_strerror(error));
1886
exitcode = EX_UNAVAILABLE;
1894
/* Create the Avahi service browser */
1895
sb = avahi_s_service_browser_new(mc.server, if_index,
1896
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1897
NULL, 0, browse_callback, NULL);
1899
fprintf(stderr, "Failed to create service browser: %s\n",
1900
avahi_strerror(avahi_server_errno(mc.server)));
1901
exitcode = EX_UNAVAILABLE;
1909
/* Run the main loop */
1912
fprintf(stderr, "Starting Avahi loop search\n");
1915
ret = avahi_loop_with_timeout(mc.simple_poll,
1916
(int)(retry_interval * 1000));
1918
fprintf(stderr, "avahi_loop_with_timeout exited %s\n",
1919
(ret == 0) ? "successfully" : "with error");
1925
fprintf(stderr, "%s exiting\n", argv[0]);
1928
/* Cleanup things */
1930
avahi_s_service_browser_free(sb);
1932
if(mc.server != NULL)
1933
avahi_server_free(mc.server);
1935
if(mc.simple_poll != NULL)
1936
avahi_simple_poll_free(mc.simple_poll);
1938
if(gnutls_initialized){
1939
gnutls_certificate_free_credentials(mc.cred);
1940
gnutls_global_deinit();
1941
gnutls_dh_params_deinit(mc.dh_params);
1944
if(gpgme_initialized){
1945
gpgme_release(mc.ctx);
1948
/* Cleans up the circular linked list of Mandos servers the client
1950
if(mc.current_server != NULL){
1951
mc.current_server->prev->next = NULL;
1952
while(mc.current_server != NULL){
1953
server *next = mc.current_server->next;
1954
free(mc.current_server);
1955
mc.current_server = next;
1959
/* Take down the network interface */
1960
if(take_down_interface){
1961
/* Re-raise priviliges */
1965
perror_plus("seteuid");
1968
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1970
perror_plus("ioctl SIOCGIFFLAGS");
1971
} else if(network.ifr_flags & IFF_UP) {
1972
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1973
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1975
perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
1978
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1980
perror_plus("close");
1982
/* Lower privileges permanently */
1986
perror_plus("setuid");
1991
/* Removes the GPGME temp directory and all files inside */
1992
if(tempdir_created){
1993
struct dirent **direntries = NULL;
1994
struct dirent *direntry = NULL;
1995
ret = scandir(tempdir, &direntries, notdotentries, alphasort);
1997
for(int i = 0; i < ret; i++){
1998
direntry = direntries[i];
1999
char *fullname = NULL;
2000
ret = asprintf(&fullname, "%s/%s", tempdir,
2003
perror_plus("asprintf");
2006
ret = remove(fullname);
2008
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
2015
/* need to be cleaned even if ret == 0 because man page doesn't
2019
perror_plus("scandir");
2021
ret = rmdir(tempdir);
2022
if(ret == -1 and errno != ENOENT){
2023
perror_plus("rmdir");
2028
sigemptyset(&old_sigterm_action.sa_mask);
2029
old_sigterm_action.sa_handler = SIG_DFL;
2030
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
2031
&old_sigterm_action,
2034
perror_plus("sigaction");
2037
ret = raise(signal_received);
2038
} while(ret != 0 and errno == EINTR);
2040
perror_plus("raise");
2043
TEMP_FAILURE_RETRY(pause());