46
100
#include <avahi-common/malloc.h>
47
101
#include <avahi-common/error.h>
50
#include <sys/types.h> /* socket(), inet_pton() */
51
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
52
struct in6_addr, inet_pton() */
53
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
54
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
56
#include <unistd.h> /* close() */
57
#include <netinet/in.h>
58
#include <stdbool.h> /* true */
59
#include <string.h> /* memset */
60
#include <arpa/inet.h> /* inet_pton() */
61
#include <iso646.h> /* not */
64
#include <errno.h> /* perror() */
71
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
73
#define CERTFILE CERT_ROOT "openpgp-client.txt"
74
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
104
#include <gnutls/gnutls.h> /* All GnuTLS types, constants and
107
init_gnutls_session(),
109
#include <gnutls/openpgp.h>
110
/* gnutls_certificate_set_openpgp_key_file(),
111
GNUTLS_OPENPGP_FMT_BASE64 */
114
#include <gpgme.h> /* All GPGME types, constants and
117
GPGME_PROTOCOL_OpenPGP,
75
120
#define BUFFER_SIZE 256
122
#define PATHDIR "/conf/conf.d/mandos"
123
#define SECKEY "seckey.txt"
124
#define PUBKEY "pubkey.txt"
78
126
bool debug = false;
127
static const char mandos_protocol_version[] = "1";
128
const char *argp_program_version = "mandos-client " VERSION;
129
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
130
static const char sys_class_net[] = "/sys/class/net";
131
char *connect_to = NULL;
133
/* Used for passing in values through the Avahi callback functions */
81
gnutls_session_t session;
135
AvahiSimplePoll *simple_poll;
82
137
gnutls_certificate_credentials_t cred;
138
unsigned int dh_bits;
83
139
gnutls_dh_params_t dh_params;
87
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
char **new_packet, const char *homedir){
89
gpgme_data_t dh_crypto, dh_plain;
140
const char *priority;
144
/* global context so signal handler can reach it*/
145
mandos_context mc = { .simple_poll = NULL, .server = NULL,
146
.dh_bits = 1024, .priority = "SECURE256"
147
":!CTYPE-X.509:+CTYPE-OPENPGP" };
149
sig_atomic_t quit_now = 0;
150
int signal_received = 0;
153
* Make additional room in "buffer" for at least BUFFER_SIZE more
154
* bytes. "buffer_capacity" is how much is currently allocated,
155
* "buffer_length" is how much is already used.
157
size_t incbuffer(char **buffer, size_t buffer_length,
158
size_t buffer_capacity){
159
if(buffer_length + BUFFER_SIZE > buffer_capacity){
160
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
164
buffer_capacity += BUFFER_SIZE;
166
return buffer_capacity;
172
static bool init_gpgme(const char *seckey,
173
const char *pubkey, const char *tempdir){
93
ssize_t new_packet_capacity = 0;
94
ssize_t new_packet_length = 0;
95
175
gpgme_engine_info_t engine_info;
98
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
179
* Helper function to insert pub and seckey to the engine keyring.
181
bool import_key(const char *filename){
184
gpgme_data_t pgp_data;
186
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
192
rc = gpgme_data_new_from_fd(&pgp_data, fd);
193
if(rc != GPG_ERR_NO_ERROR){
194
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
195
gpgme_strsource(rc), gpgme_strerror(rc));
199
rc = gpgme_op_import(mc.ctx, pgp_data);
200
if(rc != GPG_ERR_NO_ERROR){
201
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
202
gpgme_strsource(rc), gpgme_strerror(rc));
206
ret = (int)TEMP_FAILURE_RETRY(close(fd));
210
gpgme_data_release(pgp_data);
215
fprintf(stderr, "Initializing GPGME\n");
102
219
gpgme_check_version(NULL);
103
gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
220
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
221
if(rc != GPG_ERR_NO_ERROR){
222
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
223
gpgme_strsource(rc), gpgme_strerror(rc));
105
/* Set GPGME home directory */
106
rc = gpgme_get_engine_info (&engine_info);
107
if (rc != GPG_ERR_NO_ERROR){
227
/* Set GPGME home directory for the OpenPGP engine only */
228
rc = gpgme_get_engine_info(&engine_info);
229
if(rc != GPG_ERR_NO_ERROR){
108
230
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
109
231
gpgme_strsource(rc), gpgme_strerror(rc));
112
234
while(engine_info != NULL){
113
235
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
114
236
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
115
engine_info->file_name, homedir);
237
engine_info->file_name, tempdir);
118
240
engine_info = engine_info->next;
120
242
if(engine_info == NULL){
121
fprintf(stderr, "Could not set home dir to %s\n", homedir);
125
/* Create new GPGME data buffer from packet buffer */
126
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
127
if (rc != GPG_ERR_NO_ERROR){
243
fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
247
/* Create new GPGME "context" */
248
rc = gpgme_new(&(mc.ctx));
249
if(rc != GPG_ERR_NO_ERROR){
250
fprintf(stderr, "bad gpgme_new: %s: %s\n",
251
gpgme_strsource(rc), gpgme_strerror(rc));
255
if(not import_key(pubkey) or not import_key(seckey)){
263
* Decrypt OpenPGP data.
264
* Returns -1 on error
266
static ssize_t pgp_packet_decrypt(const char *cryptotext,
269
gpgme_data_t dh_crypto, dh_plain;
272
size_t plaintext_capacity = 0;
273
ssize_t plaintext_length = 0;
276
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
279
/* Create new GPGME data buffer from memory cryptotext */
280
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
282
if(rc != GPG_ERR_NO_ERROR){
128
283
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
129
284
gpgme_strsource(rc), gpgme_strerror(rc));
191
/* Delete the GPGME FILE pointer cryptotext data buffer */
192
gpgme_data_release(dh_crypto);
334
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
194
337
/* Seek back to the beginning of the GPGME plaintext data buffer */
195
gpgme_data_seek(dh_plain, (off_t) 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;
199
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
200
*new_packet = realloc(*new_packet,
201
(unsigned int)new_packet_capacity
203
if (*new_packet == NULL){
207
new_packet_capacity += BUFFER_SIZE;
346
plaintext_capacity = incbuffer(plaintext,
347
(size_t)plaintext_length,
349
if(plaintext_capacity == 0){
351
plaintext_length = -1;
210
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
355
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
212
357
/* Print the data, if any */
217
363
perror("gpgme_data_read");
220
new_packet_length += ret;
223
/* FIXME: check characters before printing to screen so to not print
224
terminal control characters */
226
/* fprintf(stderr, "decrypted password is: "); */
227
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
228
/* fprintf(stderr, "\n"); */
364
plaintext_length = -1;
367
plaintext_length += ret;
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");
380
/* Delete the GPGME cryptotext data buffer */
381
gpgme_data_release(dh_crypto);
231
383
/* Delete the GPGME plaintext data buffer */
232
384
gpgme_data_release(dh_plain);
233
return new_packet_length;
385
return plaintext_length;
236
static const char * safer_gnutls_strerror (int value) {
237
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 */
239
392
ret = "(unknown)";
243
void debuggnutls(__attribute__((unused)) int level,
245
fprintf(stderr, "%s", string);
396
/* GnuTLS log function callback */
397
static void debuggnutls(__attribute__((unused)) int level,
399
fprintf(stderr, "GnuTLS: %s", string);
248
int initgnutls(encrypted_session *es){
402
static int init_gnutls_global(const char *pubkeyfilename,
403
const char *seckeyfilename){
253
407
fprintf(stderr, "Initializing GnuTLS\n");
256
if ((ret = gnutls_global_init ())
257
!= GNUTLS_E_SUCCESS) {
258
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."
263
421
gnutls_global_set_log_level(11);
264
422
gnutls_global_set_log_function(debuggnutls);
267
/* openpgp credentials */
268
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
269
!= GNUTLS_E_SUCCESS) {
270
fprintf (stderr, "memory error: %s\n",
271
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();
276
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
277
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
438
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
439
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
281
443
ret = gnutls_certificate_set_openpgp_key_file
282
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
283
if (ret != GNUTLS_E_SUCCESS) {
285
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
287
ret, CERTFILE, KEYFILE);
288
fprintf(stdout, "The Error is: %s\n",
289
safer_gnutls_strerror(ret));
293
//GnuTLS server initialization
294
if ((ret = gnutls_dh_params_init (&es->dh_params))
295
!= GNUTLS_E_SUCCESS) {
296
fprintf (stderr, "Error in dh parameter initialization: %s\n",
297
safer_gnutls_strerror(ret));
301
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
302
!= GNUTLS_E_SUCCESS) {
303
fprintf (stderr, "Error in prime generation: %s\n",
304
safer_gnutls_strerror(ret));
308
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
310
// GnuTLS session creation
311
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
312
!= GNUTLS_E_SUCCESS){
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){
313
491
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
314
492
safer_gnutls_strerror(ret));
317
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
318
!= GNUTLS_E_SUCCESS) {
319
fprintf(stderr, "Syntax error at: %s\n", err);
320
fprintf(stderr, "GnuTLS error: %s\n",
321
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);
325
if ((ret = gnutls_credentials_set
326
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
327
!= GNUTLS_E_SUCCESS) {
328
fprintf(stderr, "Error setting a credentials set: %s\n",
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",
329
523
safer_gnutls_strerror(ret));
524
gnutls_deinit(*session);
333
528
/* ignore client certificate if any. */
334
gnutls_certificate_server_set_request (es->session,
529
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
337
gnutls_dh_set_prime_bits (es->session, DH_BITS);
531
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
342
void empty_log(__attribute__((unused)) AvahiLogLevel level,
343
__attribute__((unused)) const char *txt){}
536
/* Avahi log function callback */
537
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
538
__attribute__((unused)) const char *txt){}
345
int start_mandos_communication(const char *ip, uint16_t port,
346
unsigned int if_index){
348
struct sockaddr_in6 to;
349
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;
350
550
char *buffer = NULL;
351
char *decrypted_buffer;
551
char *decrypted_buffer = NULL;
352
552
size_t buffer_length = 0;
353
553
size_t buffer_capacity = 0;
354
ssize_t decrypted_buffer_size;
357
char interface[IF_NAMESIZE];
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);
360
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
585
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
364
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
589
tcp_sd = socket(pf, SOCK_STREAM, 0);
366
592
perror("socket");
370
if(if_indextoname(if_index, interface) == NULL){
372
perror("if_indextoname");
378
fprintf(stderr, "Binding to interface %s\n", interface);
381
memset(&to,0,sizeof(to)); /* Spurious warning */
382
to.sin6_family = AF_INET6;
383
ret = inet_pton(AF_INET6, ip, &to.sin6_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);
385
612
perror("inet_pton");
389
618
fprintf(stderr, "Bad address: %s\n", ip);
392
to.sin6_port = htons(port); /* Spurious warning */
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 */
394
to.sin6_scope_id = (uint32_t)if_index;
397
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
398
/* char addrstr[INET6_ADDRSTRLEN]; */
399
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
400
/* sizeof(addrstr)) == NULL){ */
401
/* perror("inet_ntop"); */
403
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
404
/* addrstr, ntohs(to.sin6_port)); */
408
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 */
410
694
perror("connect");
414
ret = initgnutls (&es);
420
gnutls_transport_set_ptr (es.session,
421
(gnutls_transport_ptr_t) tcp_sd);
704
const char *out = mandos_protocol_version;
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){
424
735
fprintf(stderr, "Establishing TLS session with %s\n", ip);
427
ret = gnutls_handshake (es.session);
429
if (ret != GNUTLS_E_SUCCESS){
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){
431
fprintf(stderr, "\n*** Handshake failed ***\n");
760
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
438
//Retrieve OpenPGP packet that contains the wanted password
767
/* Read OpenPGP packet that contains the wanted password */
441
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
770
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
446
if (buffer_length + BUFFER_SIZE > buffer_capacity){
447
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
452
buffer_capacity += BUFFER_SIZE;
455
ret = gnutls_record_recv
456
(es.session, buffer+buffer_length, BUFFER_SIZE);
781
buffer_capacity = incbuffer(&buffer, buffer_length,
783
if(buffer_capacity == 0){
795
sret = gnutls_record_recv(session, buffer+buffer_length,
462
802
case GNUTLS_E_INTERRUPTED:
463
803
case GNUTLS_E_AGAIN:
465
805
case GNUTLS_E_REHANDSHAKE:
466
ret = gnutls_handshake (es.session);
468
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");
475
822
fprintf(stderr, "Unknown error while reading data from"
476
" encrypted session with mandos server\n");
478
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
823
" encrypted session with Mandos server\n");
824
gnutls_bye(session, GNUTLS_SHUT_RDWR);
482
buffer_length += (size_t) ret;
486
if (buffer_length > 0){
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;
487
852
decrypted_buffer_size = pgp_packet_decrypt(buffer,
491
if (decrypted_buffer_size >= 0){
855
if(decrypted_buffer_size >= 0){
492
858
while(written < (size_t) decrypted_buffer_size){
493
ret = (int)fwrite (decrypted_buffer + written, 1,
494
(size_t)decrypted_buffer_size - written,
864
ret = (int)fwrite(decrypted_buffer + written, 1,
865
(size_t)decrypted_buffer_size - written,
496
867
if(ret == 0 and ferror(stdout)){
498
870
fprintf(stderr, "Error writing encrypted data: %s\n",
499
871
strerror(errno));
504
876
written += (size_t)ret;
506
free(decrypted_buffer);
882
/* Shutdown procedure */
887
free(decrypted_buffer);
890
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
898
gnutls_deinit(session);
515
fprintf(stderr, "Closing TLS session\n");
519
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
522
gnutls_deinit (es.session);
523
gnutls_certificate_free_credentials (es.cred);
524
gnutls_global_deinit ();
528
static AvahiSimplePoll *simple_poll = NULL;
529
static AvahiServer *server = NULL;
531
static void resolve_callback(
532
AvahiSServiceResolver *r,
533
AvahiIfIndex interface,
534
AVAHI_GCC_UNUSED AvahiProtocol protocol,
535
AvahiResolverEvent event,
539
const char *host_name,
540
const AvahiAddress *address,
542
AVAHI_GCC_UNUSED AvahiStringList *txt,
543
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
544
AVAHI_GCC_UNUSED void* userdata) {
546
assert(r); /* Spurious warning */
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){
548
924
/* Called whenever a service has been resolved successfully or
553
933
case AVAHI_RESOLVER_FAILURE:
554
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
555
" type '%s' in domain '%s': %s\n", name, type, domain,
556
avahi_strerror(avahi_server_errno(server)));
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)));
559
939
case AVAHI_RESOLVER_FOUND:
561
941
char ip[AVAHI_ADDRESS_STR_MAX];
562
942
avahi_address_snprint(ip, sizeof(ip), address);
564
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
565
" port %d\n", name, host_name, ip, port);
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);
567
int ret = start_mandos_communication(ip, port,
568
(unsigned int) interface);
948
int ret = start_mandos_communication(ip, port, interface,
949
avahi_proto_to_af(proto));
951
avahi_simple_poll_quit(mc.simple_poll);
574
955
avahi_s_service_resolver_free(r);
577
static void browse_callback(
578
AvahiSServiceBrowser *b,
579
AvahiIfIndex interface,
580
AvahiProtocol protocol,
581
AvahiBrowserEvent event,
585
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
588
AvahiServer *s = userdata;
589
assert(b); /* Spurious warning */
591
/* Called whenever a new services becomes available on the LAN or
592
is removed from the LAN */
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);
596
case AVAHI_BROWSER_FAILURE:
598
fprintf(stderr, "(Browser) %s\n",
599
avahi_strerror(avahi_server_errno(server)));
600
avahi_simple_poll_quit(simple_poll);
603
case AVAHI_BROWSER_NEW:
604
/* We ignore the returned resolver object. In the callback
605
function we free it. If the server is terminated before
606
the callback function is called the server will free
607
the resolver for us. */
609
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
611
AVAHI_PROTO_INET6, 0,
612
resolve_callback, s)))
613
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
614
avahi_strerror(avahi_server_errno(s)));
617
case AVAHI_BROWSER_REMOVE:
620
case AVAHI_BROWSER_ALL_FOR_NOW:
621
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1283
perror("argp_parse");
1284
exitcode = EX_OSERR;
1287
exitcode = EX_USAGE;
1293
avahi_set_log_function(empty_log);
626
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
627
AvahiServerConfig config;
628
AvahiSServiceBrowser *sb = NULL;
631
int returncode = EXIT_SUCCESS;
632
const char *interface = "eth0";
633
unsigned int if_index;
634
char *connect_to = NULL;
637
static struct option long_options[] = {
638
{"debug", no_argument, (int *)&debug, 1},
639
{"connect", required_argument, 0, 'c'},
640
{"interface", required_argument, 0, 'i'},
643
int option_index = 0;
644
ret = getopt_long (argc, argv, "i:", long_options,
665
if_index = if_nametoindex(interface);
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);
666
1398
if(if_index == 0){
667
1399
fprintf(stderr, "No such interface: \"%s\"\n", interface);
671
if(connect_to != NULL){
672
/* Connect directly, do not use Zeroconf */
673
/* (Mainly meant for debugging) */
674
char *address = strrchr(connect_to, ':');
676
fprintf(stderr, "No colon in address\n");
680
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
682
perror("Bad port number");
686
address = connect_to;
687
ret = start_mandos_communication(address, port, if_index);
696
avahi_set_log_function(empty_log);
699
/* Initialize the psuedo-RNG */
700
srand((unsigned int) time(NULL));
702
/* Allocate main loop object */
703
if (!(simple_poll = avahi_simple_poll_new())) {
704
fprintf(stderr, "Failed to create simple poll object.\n");
709
/* Do not publish any local records */
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;
1654
AvahiServerConfig config;
1655
/* Do not publish any local Zeroconf records */
710
1656
avahi_server_config_init(&config);
711
1657
config.publish_hinfo = 0;
712
1658
config.publish_addresses = 0;
713
1659
config.publish_workstation = 0;
714
1660
config.publish_domain = 0;
716
1662
/* Allocate a new server */
717
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
718
&config, NULL, NULL, &error);
720
/* 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 */
721
1668
avahi_server_config_free(&config);
723
/* Check if creating the server object succeeded */
725
fprintf(stderr, "Failed to create server: %s\n",
726
avahi_strerror(error));
727
returncode = EXIT_FAILURE;
731
/* Create the service browser */
732
sb = avahi_s_service_browser_new(server, (AvahiIfIndex)if_index,
734
"_mandos._tcp", NULL, 0,
735
browse_callback, server);
737
fprintf(stderr, "Failed to create service browser: %s\n",
738
avahi_strerror(avahi_server_errno(server)));
739
returncode = EXIT_FAILURE;
743
/* Run the main loop */
746
fprintf(stderr, "Starting avahi loop search\n");
749
avahi_simple_poll_loop(simple_poll);
754
fprintf(stderr, "%s exiting\n", argv[0]);
759
avahi_s_service_browser_free(sb);
762
avahi_server_free(server);
765
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());