31
32
/* Needed by GPGME, specifically gpgme_data_seek() */
33
#ifndef _LARGEFILE_SOURCE
32
34
#define _LARGEFILE_SOURCE
36
#ifndef _FILE_OFFSET_BITS
33
37
#define _FILE_OFFSET_BITS 64
39
#include <net/if.h> /* if_nametoindex */
40
#include <sys/ioctl.h> // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
41
#include <net/if.h> // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
40
#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), asprintf() */
42
#include <stdio.h> /* fprintf(), stderr, fwrite(),
43
stdout, ferror(), remove() */
44
#include <stdint.h> /* uint16_t, uint32_t */
45
#include <stddef.h> /* NULL, size_t, ssize_t */
46
#include <stdlib.h> /* free(), EXIT_SUCCESS, EXIT_FAILURE,
47
srand(), strtof(), abort() */
48
#include <stdbool.h> /* bool, false, true */
49
#include <string.h> /* memset(), strcmp(), strlen(),
50
strerror(), asprintf(), strcpy() */
51
#include <sys/ioctl.h> /* ioctl */
52
#include <sys/types.h> /* socket(), inet_pton(), sockaddr,
53
sockaddr_in6, PF_INET6,
54
SOCK_STREAM, uid_t, gid_t, open(),
56
#include <sys/stat.h> /* open() */
57
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
58
inet_pton(), connect() */
59
#include <fcntl.h> /* open() */
60
#include <dirent.h> /* opendir(), struct dirent, readdir()
62
#include <inttypes.h> /* PRIu16, PRIdMAX, intmax_t,
64
#include <assert.h> /* assert() */
65
#include <errno.h> /* perror(), errno */
66
#include <time.h> /* nanosleep(), time() */
67
#include <net/if.h> /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
68
SIOCSIFFLAGS, if_indextoname(),
69
if_nametoindex(), IF_NAMESIZE */
70
#include <netinet/in.h> /* IN6_IS_ADDR_LINKLOCAL,
71
INET_ADDRSTRLEN, INET6_ADDRSTRLEN
73
#include <unistd.h> /* close(), SEEK_SET, off_t, write(),
74
getuid(), getgid(), seteuid(),
76
#include <arpa/inet.h> /* inet_pton(), htons */
77
#include <iso646.h> /* not, or, and */
78
#include <argp.h> /* struct argp_option, error_t, struct
79
argp_state, struct argp,
80
argp_parse(), ARGP_KEY_ARG,
81
ARGP_KEY_END, ARGP_ERR_UNKNOWN */
82
#include <signal.h> /* sigemptyset(), sigaddset(),
83
sigaction(), SIGTERM, sig_atomic_t,
87
#include <sys/klog.h> /* klogctl() */
88
#endif /* __linux__ */
91
/* All Avahi types, constants and functions
43
94
#include <avahi-core/core.h>
44
95
#include <avahi-core/lookup.h>
45
96
#include <avahi-core/log.h>
47
98
#include <avahi-common/malloc.h>
48
99
#include <avahi-common/error.h>
51
#include <sys/types.h> /* socket(), inet_pton() */
52
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
53
struct in6_addr, inet_pton() */
54
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
55
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
57
#include <unistd.h> /* close() */
58
#include <netinet/in.h>
59
#include <stdbool.h> /* true */
60
#include <string.h> /* memset */
61
#include <arpa/inet.h> /* inet_pton() */
62
#include <iso646.h> /* not */
65
#include <errno.h> /* perror() */
102
#include <gnutls/gnutls.h> /* All GnuTLS types, constants and
105
init_gnutls_session(),
107
#include <gnutls/openpgp.h>
108
/* gnutls_certificate_set_openpgp_key_file(),
109
GNUTLS_OPENPGP_FMT_BASE64 */
112
#include <gpgme.h> /* All GPGME types, constants and
115
GPGME_PROTOCOL_OpenPGP,
71
118
#define BUFFER_SIZE 256
74
static const char *certdir = "/conf/conf.d/mandos";
75
static const char *certfile = "openpgp-client.txt";
76
static const char *certkey = "openpgp-client-key.txt";
120
#define PATHDIR "/conf/conf.d/mandos"
121
#define SECKEY "seckey.txt"
122
#define PUBKEY "pubkey.txt"
78
124
bool debug = false;
125
static const char mandos_protocol_version[] = "1";
126
const char *argp_program_version = "mandos-client " VERSION;
127
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
129
/* Used for passing in values through the Avahi callback functions */
81
gnutls_session_t session;
131
AvahiSimplePoll *simple_poll;
82
133
gnutls_certificate_credentials_t cred;
134
unsigned int dh_bits;
83
135
gnutls_dh_params_t dh_params;
87
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
90
gpgme_data_t dh_crypto, dh_plain;
136
const char *priority;
140
/* global context so signal handler can reach it*/
141
mandos_context mc = { .simple_poll = NULL, .server = NULL,
142
.dh_bits = 1024, .priority = "SECURE256"
143
":!CTYPE-X.509:+CTYPE-OPENPGP" };
145
sig_atomic_t quit_now = 0;
146
int signal_received = 0;
149
* Make additional room in "buffer" for at least BUFFER_SIZE more
150
* bytes. "buffer_capacity" is how much is currently allocated,
151
* "buffer_length" is how much is already used.
153
size_t incbuffer(char **buffer, size_t buffer_length,
154
size_t buffer_capacity){
155
if(buffer_length + BUFFER_SIZE > buffer_capacity){
156
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
160
buffer_capacity += BUFFER_SIZE;
162
return buffer_capacity;
168
static bool init_gpgme(const char *seckey,
169
const char *pubkey, const char *tempdir){
94
ssize_t new_packet_capacity = 0;
95
ssize_t new_packet_length = 0;
96
171
gpgme_engine_info_t engine_info;
99
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
175
* Helper function to insert pub and seckey to the engine keyring.
177
bool import_key(const char *filename){
180
gpgme_data_t pgp_data;
182
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
188
rc = gpgme_data_new_from_fd(&pgp_data, fd);
189
if(rc != GPG_ERR_NO_ERROR){
190
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
191
gpgme_strsource(rc), gpgme_strerror(rc));
195
rc = gpgme_op_import(mc.ctx, pgp_data);
196
if(rc != GPG_ERR_NO_ERROR){
197
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
198
gpgme_strsource(rc), gpgme_strerror(rc));
202
ret = (int)TEMP_FAILURE_RETRY(close(fd));
206
gpgme_data_release(pgp_data);
211
fprintf(stderr, "Initializing GPGME\n");
103
215
gpgme_check_version(NULL);
104
216
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
105
if (rc != GPG_ERR_NO_ERROR){
217
if(rc != GPG_ERR_NO_ERROR){
106
218
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
107
219
gpgme_strsource(rc), gpgme_strerror(rc));
111
/* Set GPGME home directory */
112
rc = gpgme_get_engine_info (&engine_info);
113
if (rc != GPG_ERR_NO_ERROR){
223
/* Set GPGME home directory for the OpenPGP engine only */
224
rc = gpgme_get_engine_info(&engine_info);
225
if(rc != GPG_ERR_NO_ERROR){
114
226
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
115
227
gpgme_strsource(rc), gpgme_strerror(rc));
118
230
while(engine_info != NULL){
119
231
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
120
232
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
121
engine_info->file_name, homedir);
233
engine_info->file_name, tempdir);
124
236
engine_info = engine_info->next;
126
238
if(engine_info == NULL){
127
fprintf(stderr, "Could not set home dir to %s\n", homedir);
131
/* Create new GPGME data buffer from packet buffer */
132
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
133
if (rc != GPG_ERR_NO_ERROR){
239
fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
243
/* Create new GPGME "context" */
244
rc = gpgme_new(&(mc.ctx));
245
if(rc != GPG_ERR_NO_ERROR){
246
fprintf(stderr, "bad gpgme_new: %s: %s\n",
247
gpgme_strsource(rc), gpgme_strerror(rc));
251
if(not import_key(pubkey) or not import_key(seckey)){
259
* Decrypt OpenPGP data.
260
* Returns -1 on error
262
static ssize_t pgp_packet_decrypt(const char *cryptotext,
265
gpgme_data_t dh_crypto, dh_plain;
268
size_t plaintext_capacity = 0;
269
ssize_t plaintext_length = 0;
272
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
275
/* Create new GPGME data buffer from memory cryptotext */
276
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
278
if(rc != GPG_ERR_NO_ERROR){
134
279
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
135
280
gpgme_strsource(rc), gpgme_strerror(rc));
197
/* Delete the GPGME FILE pointer cryptotext data buffer */
198
gpgme_data_release(dh_crypto);
330
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
200
333
/* Seek back to the beginning of the GPGME plaintext data buffer */
201
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
202
perror("pgpme_data_seek");
334
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
335
perror("gpgme_data_seek");
336
plaintext_length = -1;
207
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
208
*new_packet = realloc(*new_packet,
209
(unsigned int)new_packet_capacity
211
if (*new_packet == NULL){
215
new_packet_capacity += BUFFER_SIZE;
342
plaintext_capacity = incbuffer(plaintext,
343
(size_t)plaintext_length,
345
if(plaintext_capacity == 0){
347
plaintext_length = -1;
218
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
351
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
220
353
/* Print the data, if any */
225
359
perror("gpgme_data_read");
228
new_packet_length += ret;
231
/* FIXME: check characters before printing to screen so to not print
232
terminal control characters */
234
/* fprintf(stderr, "decrypted password is: "); */
235
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
236
/* fprintf(stderr, "\n"); */
360
plaintext_length = -1;
363
plaintext_length += ret;
367
fprintf(stderr, "Decrypted password is: ");
368
for(ssize_t i = 0; i < plaintext_length; i++){
369
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
371
fprintf(stderr, "\n");
376
/* Delete the GPGME cryptotext data buffer */
377
gpgme_data_release(dh_crypto);
239
379
/* Delete the GPGME plaintext data buffer */
240
380
gpgme_data_release(dh_plain);
241
return new_packet_length;
381
return plaintext_length;
244
static const char * safer_gnutls_strerror (int value) {
245
const char *ret = gnutls_strerror (value);
384
static const char * safer_gnutls_strerror(int value){
385
const char *ret = gnutls_strerror(value); /* Spurious warning from
386
-Wunreachable-code */
247
388
ret = "(unknown)";
392
/* GnuTLS log function callback */
251
393
static void debuggnutls(__attribute__((unused)) int level,
252
394
const char* string){
253
fprintf(stderr, "%s", string);
395
fprintf(stderr, "GnuTLS: %s", string);
256
static int initgnutls(encrypted_session *es){
398
static int init_gnutls_global(const char *pubkeyfilename,
399
const char *seckeyfilename){
261
403
fprintf(stderr, "Initializing GnuTLS\n");
264
if ((ret = gnutls_global_init ())
265
!= GNUTLS_E_SUCCESS) {
266
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
406
ret = gnutls_global_init();
407
if(ret != GNUTLS_E_SUCCESS){
408
fprintf(stderr, "GnuTLS global_init: %s\n",
409
safer_gnutls_strerror(ret));
414
/* "Use a log level over 10 to enable all debugging options."
271
417
gnutls_global_set_log_level(11);
272
418
gnutls_global_set_log_function(debuggnutls);
275
/* openpgp credentials */
276
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
277
!= GNUTLS_E_SUCCESS) {
278
fprintf (stderr, "memory error: %s\n",
279
safer_gnutls_strerror(ret));
421
/* OpenPGP credentials */
422
gnutls_certificate_allocate_credentials(&mc.cred);
423
if(ret != GNUTLS_E_SUCCESS){
424
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
428
safer_gnutls_strerror(ret));
429
gnutls_global_deinit();
284
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
285
" and keyfile %s as GnuTLS credentials\n", certfile,
434
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
435
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
289
439
ret = gnutls_certificate_set_openpgp_key_file
290
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
291
if (ret != GNUTLS_E_SUCCESS) {
293
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
295
ret, certfile, certkey);
296
fprintf(stdout, "The Error is: %s\n",
297
safer_gnutls_strerror(ret));
301
//GnuTLS server initialization
302
if ((ret = gnutls_dh_params_init (&es->dh_params))
303
!= GNUTLS_E_SUCCESS) {
304
fprintf (stderr, "Error in dh parameter initialization: %s\n",
305
safer_gnutls_strerror(ret));
309
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
310
!= GNUTLS_E_SUCCESS) {
311
fprintf (stderr, "Error in prime generation: %s\n",
312
safer_gnutls_strerror(ret));
316
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
318
// GnuTLS session creation
319
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
320
!= GNUTLS_E_SUCCESS){
440
(mc.cred, pubkeyfilename, seckeyfilename,
441
GNUTLS_OPENPGP_FMT_BASE64);
442
if(ret != GNUTLS_E_SUCCESS){
444
"Error[%d] while reading the OpenPGP key pair ('%s',"
445
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
446
fprintf(stderr, "The GnuTLS error is: %s\n",
447
safer_gnutls_strerror(ret));
451
/* GnuTLS server initialization */
452
ret = gnutls_dh_params_init(&mc.dh_params);
453
if(ret != GNUTLS_E_SUCCESS){
454
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
455
" %s\n", safer_gnutls_strerror(ret));
458
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
459
if(ret != GNUTLS_E_SUCCESS){
460
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
461
safer_gnutls_strerror(ret));
465
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
471
gnutls_certificate_free_credentials(mc.cred);
472
gnutls_global_deinit();
473
gnutls_dh_params_deinit(mc.dh_params);
477
static int init_gnutls_session(gnutls_session_t *session){
479
/* GnuTLS session creation */
481
ret = gnutls_init(session, GNUTLS_SERVER);
485
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
486
if(ret != GNUTLS_E_SUCCESS){
321
487
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
322
488
safer_gnutls_strerror(ret));
325
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
326
!= GNUTLS_E_SUCCESS) {
327
fprintf(stderr, "Syntax error at: %s\n", err);
328
fprintf(stderr, "GnuTLS error: %s\n",
329
safer_gnutls_strerror(ret));
494
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
496
gnutls_deinit(*session);
499
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
500
if(ret != GNUTLS_E_SUCCESS){
501
fprintf(stderr, "Syntax error at: %s\n", err);
502
fprintf(stderr, "GnuTLS error: %s\n",
503
safer_gnutls_strerror(ret));
504
gnutls_deinit(*session);
333
if ((ret = gnutls_credentials_set
334
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
335
!= GNUTLS_E_SUCCESS) {
336
fprintf(stderr, "Error setting a credentials set: %s\n",
510
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
513
gnutls_deinit(*session);
516
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
517
if(ret != GNUTLS_E_SUCCESS){
518
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
337
519
safer_gnutls_strerror(ret));
520
gnutls_deinit(*session);
341
524
/* ignore client certificate if any. */
342
gnutls_certificate_server_set_request (es->session,
525
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
345
gnutls_dh_set_prime_bits (es->session, DH_BITS);
527
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
532
/* Avahi log function callback */
350
533
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
351
534
__attribute__((unused)) const char *txt){}
536
/* Called when a Mandos server is found */
353
537
static int start_mandos_communication(const char *ip, uint16_t port,
354
AvahiIfIndex if_index){
356
struct sockaddr_in6 to;
357
encrypted_session es;
538
AvahiIfIndex if_index,
540
int ret, tcp_sd = -1;
543
struct sockaddr_in in;
544
struct sockaddr_in6 in6;
358
546
char *buffer = NULL;
359
char *decrypted_buffer;
547
char *decrypted_buffer = NULL;
360
548
size_t buffer_length = 0;
361
549
size_t buffer_capacity = 0;
362
ssize_t decrypted_buffer_size;
365
char interface[IF_NAMESIZE];
552
gnutls_session_t session;
553
int pf; /* Protocol family */
567
fprintf(stderr, "Bad address family: %d\n", af);
571
ret = init_gnutls_session(&session);
368
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
577
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
372
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
581
tcp_sd = socket(pf, SOCK_STREAM, 0);
374
583
perror("socket");
379
if(if_indextoname((unsigned int)if_index, interface) == NULL){
381
perror("if_indextoname");
386
fprintf(stderr, "Binding to interface %s\n", interface);
389
memset(&to,0,sizeof(to)); /* Spurious warning */
390
to.sin6_family = AF_INET6;
391
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
591
memset(&to, 0, sizeof(to));
593
to.in6.sin6_family = (sa_family_t)af;
594
ret = inet_pton(af, ip, &to.in6.sin6_addr);
596
to.in.sin_family = (sa_family_t)af;
597
ret = inet_pton(af, ip, &to.in.sin_addr);
393
600
perror("inet_pton");
397
604
fprintf(stderr, "Bad address: %s\n", ip);
400
to.sin6_port = htons(port); /* Spurious warning */
608
to.in6.sin6_port = htons(port); /* Spurious warnings from
610
-Wunreachable-code */
612
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
613
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
615
if(if_index == AVAHI_IF_UNSPEC){
616
fprintf(stderr, "An IPv6 link-local address is incomplete"
617
" without a network interface\n");
620
/* Set the network interface number as scope */
621
to.in6.sin6_scope_id = (uint32_t)if_index;
624
to.in.sin_port = htons(port); /* Spurious warnings from
626
-Wunreachable-code */
402
to.sin6_scope_id = (uint32_t)if_index;
405
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
406
/* char addrstr[INET6_ADDRSTRLEN]; */
407
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
408
/* sizeof(addrstr)) == NULL){ */
409
/* perror("inet_ntop"); */
411
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
412
/* addrstr, ntohs(to.sin6_port)); */
416
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
634
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
635
char interface[IF_NAMESIZE];
636
if(if_indextoname((unsigned int)if_index, interface) == NULL){
637
perror("if_indextoname");
639
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
640
ip, interface, port);
643
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
646
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
647
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
650
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
653
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
659
if(strcmp(addrstr, ip) != 0){
660
fprintf(stderr, "Canonical address form: %s\n", addrstr);
670
ret = connect(tcp_sd, &to.in6, sizeof(to));
672
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
418
675
perror("connect");
422
ret = initgnutls (&es);
428
gnutls_transport_set_ptr (es.session,
429
(gnutls_transport_ptr_t) tcp_sd);
683
const char *out = mandos_protocol_version;
686
size_t out_size = strlen(out);
687
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
688
out_size - written));
693
written += (size_t)ret;
694
if(written < out_size){
697
if(out == mandos_protocol_version){
432
711
fprintf(stderr, "Establishing TLS session with %s\n", ip);
435
ret = gnutls_handshake (es.session);
437
if (ret != GNUTLS_E_SUCCESS){
718
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
725
ret = gnutls_handshake(session);
729
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
731
if(ret != GNUTLS_E_SUCCESS){
439
fprintf(stderr, "\n*** Handshake failed ***\n");
733
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
446
//Retrieve OpenPGP packet that contains the wanted password
739
/* Read OpenPGP packet that contains the wanted password */
449
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
742
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
454
if (buffer_length + BUFFER_SIZE > buffer_capacity){
455
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
460
buffer_capacity += BUFFER_SIZE;
463
ret = gnutls_record_recv
464
(es.session, buffer+buffer_length, BUFFER_SIZE);
752
buffer_capacity = incbuffer(&buffer, buffer_length,
754
if(buffer_capacity == 0){
763
sret = gnutls_record_recv(session, buffer+buffer_length,
470
770
case GNUTLS_E_INTERRUPTED:
471
771
case GNUTLS_E_AGAIN:
473
773
case GNUTLS_E_REHANDSHAKE:
474
ret = gnutls_handshake (es.session);
476
fprintf(stderr, "\n*** Handshake failed ***\n");
775
ret = gnutls_handshake(session);
780
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
782
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
483
788
fprintf(stderr, "Unknown error while reading data from"
484
" encrypted session with mandos server\n");
486
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
789
" encrypted session with Mandos server\n");
790
gnutls_bye(session, GNUTLS_SHUT_RDWR);
490
buffer_length += (size_t) ret;
494
if (buffer_length > 0){
794
buffer_length += (size_t) sret;
799
fprintf(stderr, "Closing TLS session\n");
807
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
811
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
813
if(buffer_length > 0){
814
ssize_t decrypted_buffer_size;
495
815
decrypted_buffer_size = pgp_packet_decrypt(buffer,
499
if (decrypted_buffer_size >= 0){
818
if(decrypted_buffer_size >= 0){
500
821
while(written < (size_t) decrypted_buffer_size){
501
ret = (int)fwrite (decrypted_buffer + written, 1,
502
(size_t)decrypted_buffer_size - written,
826
ret = (int)fwrite(decrypted_buffer + written, 1,
827
(size_t)decrypted_buffer_size - written,
504
829
if(ret == 0 and ferror(stdout)){
506
831
fprintf(stderr, "Error writing encrypted data: %s\n",
507
832
strerror(errno));
512
836
written += (size_t)ret;
514
free(decrypted_buffer);
523
fprintf(stderr, "Closing TLS session\n");
842
/* Shutdown procedure */
845
free(decrypted_buffer);
527
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
530
gnutls_deinit (es.session);
531
gnutls_certificate_free_credentials (es.cred);
532
gnutls_global_deinit ();
848
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
853
gnutls_deinit(session);
536
static AvahiSimplePoll *simple_poll = NULL;
537
static AvahiServer *server = NULL;
539
static void resolve_callback(
540
AvahiSServiceResolver *r,
541
AvahiIfIndex interface,
542
AVAHI_GCC_UNUSED AvahiProtocol protocol,
543
AvahiResolverEvent event,
547
const char *host_name,
548
const AvahiAddress *address,
550
AVAHI_GCC_UNUSED AvahiStringList *txt,
551
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
552
AVAHI_GCC_UNUSED void* userdata) {
554
assert(r); /* Spurious warning */
860
static void resolve_callback(AvahiSServiceResolver *r,
861
AvahiIfIndex interface,
863
AvahiResolverEvent event,
867
const char *host_name,
868
const AvahiAddress *address,
870
AVAHI_GCC_UNUSED AvahiStringList *txt,
871
AVAHI_GCC_UNUSED AvahiLookupResultFlags
873
AVAHI_GCC_UNUSED void* userdata){
556
876
/* Called whenever a service has been resolved successfully or
561
885
case AVAHI_RESOLVER_FAILURE:
562
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
563
" type '%s' in domain '%s': %s\n", name, type, domain,
564
avahi_strerror(avahi_server_errno(server)));
886
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
887
" of type '%s' in domain '%s': %s\n", name, type, domain,
888
avahi_strerror(avahi_server_errno(mc.server)));
567
891
case AVAHI_RESOLVER_FOUND:
569
893
char ip[AVAHI_ADDRESS_STR_MAX];
570
894
avahi_address_snprint(ip, sizeof(ip), address);
572
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
573
" port %d\n", name, host_name, ip, port);
896
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
897
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
898
ip, (intmax_t)interface, port);
575
int ret = start_mandos_communication(ip, port, interface);
900
int ret = start_mandos_communication(ip, port, interface,
901
avahi_proto_to_af(proto));
903
avahi_simple_poll_quit(mc.simple_poll);
581
907
avahi_s_service_resolver_free(r);
584
static void browse_callback(
585
AvahiSServiceBrowser *b,
586
AvahiIfIndex interface,
587
AvahiProtocol protocol,
588
AvahiBrowserEvent event,
592
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
595
AvahiServer *s = userdata;
596
assert(b); /* Spurious warning */
598
/* Called whenever a new services becomes available on the LAN or
599
is removed from the LAN */
603
case AVAHI_BROWSER_FAILURE:
605
fprintf(stderr, "(Browser) %s\n",
606
avahi_strerror(avahi_server_errno(server)));
607
avahi_simple_poll_quit(simple_poll);
610
case AVAHI_BROWSER_NEW:
611
/* We ignore the returned resolver object. In the callback
612
function we free it. If the server is terminated before
613
the callback function is called the server will free
614
the resolver for us. */
616
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
618
AVAHI_PROTO_INET6, 0,
619
resolve_callback, s)))
620
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
621
avahi_strerror(avahi_server_errno(s)));
624
case AVAHI_BROWSER_REMOVE:
627
case AVAHI_BROWSER_ALL_FOR_NOW:
628
case AVAHI_BROWSER_CACHE_EXHAUSTED:
910
static void browse_callback(AvahiSServiceBrowser *b,
911
AvahiIfIndex interface,
912
AvahiProtocol protocol,
913
AvahiBrowserEvent event,
917
AVAHI_GCC_UNUSED AvahiLookupResultFlags
919
AVAHI_GCC_UNUSED void* userdata){
922
/* Called whenever a new services becomes available on the LAN or
923
is removed from the LAN */
931
case AVAHI_BROWSER_FAILURE:
933
fprintf(stderr, "(Avahi browser) %s\n",
934
avahi_strerror(avahi_server_errno(mc.server)));
935
avahi_simple_poll_quit(mc.simple_poll);
938
case AVAHI_BROWSER_NEW:
939
/* We ignore the returned Avahi resolver object. In the callback
940
function we free it. If the Avahi server is terminated before
941
the callback function is called the Avahi server will free the
944
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
945
name, type, domain, protocol, 0,
946
resolve_callback, NULL) == NULL)
947
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
948
name, avahi_strerror(avahi_server_errno(mc.server)));
951
case AVAHI_BROWSER_REMOVE:
954
case AVAHI_BROWSER_ALL_FOR_NOW:
955
case AVAHI_BROWSER_CACHE_EXHAUSTED:
957
fprintf(stderr, "No Mandos server found, still searching...\n");
633
/* Combines file name and path and returns the malloced new
634
string. some sane checks could/should be added */
635
static const char *combinepath(const char *first, const char *second){
636
size_t f_len = strlen(first);
637
size_t s_len = strlen(second);
638
char *tmp = malloc(f_len + s_len + 2);
643
memcpy(tmp, first, f_len);
647
memcpy(tmp + f_len + 1, second, s_len);
649
tmp[f_len + 1 + s_len] = '\0';
654
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
655
AvahiServerConfig config;
656
AvahiSServiceBrowser *sb = NULL;
659
int returncode = EXIT_SUCCESS;
660
const char *interface = "eth0";
661
struct ifreq network;
663
char *connect_to = NULL;
664
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
963
/* stop main loop after sigterm has been called */
964
static void handle_sigterm(int sig){
969
signal_received = sig;
970
int old_errno = errno;
971
if(mc.simple_poll != NULL){
972
avahi_simple_poll_quit(mc.simple_poll);
977
int main(int argc, char *argv[]){
978
AvahiSServiceBrowser *sb = NULL;
983
int exitcode = EXIT_SUCCESS;
984
const char *interface = "eth0";
985
struct ifreq network;
987
bool take_down_interface = false;
990
char *connect_to = NULL;
991
char tempdir[] = "/tmp/mandosXXXXXX";
992
bool tempdir_created = false;
993
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
994
const char *seckey = PATHDIR "/" SECKEY;
995
const char *pubkey = PATHDIR "/" PUBKEY;
997
bool gnutls_initialized = false;
998
bool gpgme_initialized = false;
1001
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1002
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1007
/* Lower any group privileges we might have, just to be safe */
1014
/* Lower user privileges (temporarily) */
1026
struct argp_option options[] = {
1027
{ .name = "debug", .key = 128,
1028
.doc = "Debug mode", .group = 3 },
1029
{ .name = "connect", .key = 'c',
1030
.arg = "ADDRESS:PORT",
1031
.doc = "Connect directly to a specific Mandos server",
1033
{ .name = "interface", .key = 'i',
1035
.doc = "Network interface that will be used to search for"
1038
{ .name = "seckey", .key = 's',
1040
.doc = "OpenPGP secret key file base name",
1042
{ .name = "pubkey", .key = 'p',
1044
.doc = "OpenPGP public key file base name",
1046
{ .name = "dh-bits", .key = 129,
1048
.doc = "Bit length of the prime number used in the"
1049
" Diffie-Hellman key exchange",
1051
{ .name = "priority", .key = 130,
1053
.doc = "GnuTLS priority string for the TLS handshake",
1055
{ .name = "delay", .key = 131,
1057
.doc = "Maximum delay to wait for interface startup",
667
static struct option long_options[] = {
668
{"debug", no_argument, (int *)&debug, 1},
669
{"connect", required_argument, 0, 'C'},
670
{"interface", required_argument, 0, 'i'},
671
{"certdir", required_argument, 0, 'd'},
672
{"certkey", required_argument, 0, 'c'},
673
{"certfile", required_argument, 0, 'k'},
676
int option_index = 0;
677
ret = getopt_long (argc, argv, "i:", long_options,
1062
error_t parse_opt(int key, char *arg,
1063
struct argp_state *state){
1065
case 128: /* --debug */
1068
case 'c': /* --connect */
1071
case 'i': /* --interface */
1074
case 's': /* --seckey */
1077
case 'p': /* --pubkey */
1080
case 129: /* --dh-bits */
1082
tmpmax = strtoimax(arg, &tmp, 10);
1083
if(errno != 0 or tmp == arg or *tmp != '\0'
1084
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1085
fprintf(stderr, "Bad number of DH bits\n");
1088
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1090
case 130: /* --priority */
1093
case 131: /* --delay */
1095
delay = strtof(arg, &tmp);
1096
if(errno != 0 or tmp == arg or *tmp != '\0'){
1097
fprintf(stderr, "Bad delay\n");
1106
return ARGP_ERR_UNKNOWN;
707
certfile = combinepath(certdir, certfile);
708
if (certfile == NULL){
709
perror("combinepath");
710
returncode = EXIT_FAILURE;
714
certkey = combinepath(certdir, certkey);
715
if (certkey == NULL){
716
perror("combinepath");
717
returncode = EXIT_FAILURE;
1111
struct argp argp = { .options = options, .parser = parse_opt,
1113
.doc = "Mandos client -- Get and decrypt"
1114
" passwords from a Mandos server" };
1115
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
1116
if(ret == ARGP_ERR_UNKNOWN){
1117
fprintf(stderr, "Unknown error while parsing arguments\n");
1118
exitcode = EXIT_FAILURE;
1124
avahi_set_log_function(empty_log);
1127
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1128
from the signal handler */
1129
/* Initialize the pseudo-RNG for Avahi */
1130
srand((unsigned int) time(NULL));
1131
mc.simple_poll = avahi_simple_poll_new();
1132
if(mc.simple_poll == NULL){
1133
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1134
exitcode = EXIT_FAILURE;
1138
sigemptyset(&sigterm_action.sa_mask);
1139
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1141
perror("sigaddset");
1142
exitcode = EXIT_FAILURE;
1145
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1147
perror("sigaddset");
1148
exitcode = EXIT_FAILURE;
1151
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1153
perror("sigaddset");
1154
exitcode = EXIT_FAILURE;
1157
/* Need to check if the handler is SIG_IGN before handling:
1158
| [[info:libc:Initial Signal Actions]] |
1159
| [[info:libc:Basic Signal Handling]] |
1161
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1163
perror("sigaction");
1164
return EXIT_FAILURE;
1166
if(old_sigterm_action.sa_handler != SIG_IGN){
1167
ret = sigaction(SIGINT, &sigterm_action, NULL);
1169
perror("sigaction");
1170
exitcode = EXIT_FAILURE;
1174
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1176
perror("sigaction");
1177
return EXIT_FAILURE;
1179
if(old_sigterm_action.sa_handler != SIG_IGN){
1180
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1182
perror("sigaction");
1183
exitcode = EXIT_FAILURE;
1187
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1189
perror("sigaction");
1190
return EXIT_FAILURE;
1192
if(old_sigterm_action.sa_handler != SIG_IGN){
1193
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1195
perror("sigaction");
1196
exitcode = EXIT_FAILURE;
1201
/* If the interface is down, bring it up */
1202
if(interface[0] != '\0'){
721
1203
if_index = (AvahiIfIndex) if_nametoindex(interface);
722
1204
if(if_index == 0){
723
1205
fprintf(stderr, "No such interface: \"%s\"\n", interface);
727
if(connect_to != NULL){
728
/* Connect directly, do not use Zeroconf */
729
/* (Mainly meant for debugging) */
730
char *address = strrchr(connect_to, ':');
732
fprintf(stderr, "No colon in address\n");
736
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
738
perror("Bad port number");
742
address = connect_to;
743
ret = start_mandos_communication(address, port, if_index);
1206
exitcode = EXIT_FAILURE;
1214
/* Re-raise priviliges */
1222
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1223
messages to mess up the prompt */
1224
ret = klogctl(8, NULL, 5);
1225
bool restore_loglevel = true;
1227
restore_loglevel = false;
1230
#endif /* __linux__ */
751
1232
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
753
1234
perror("socket");
754
returncode = EXIT_FAILURE;
1235
exitcode = EXIT_FAILURE;
1237
if(restore_loglevel){
1238
ret = klogctl(7, NULL, 0);
1243
#endif /* __linux__ */
1244
/* Lower privileges */
757
strcpy(network.ifr_name, interface);
1252
strcpy(network.ifr_name, interface);
758
1253
ret = ioctl(sd, SIOCGIFFLAGS, &network);
761
1255
perror("ioctl SIOCGIFFLAGS");
762
returncode = EXIT_FAILURE;
1257
if(restore_loglevel){
1258
ret = klogctl(7, NULL, 0);
1263
#endif /* __linux__ */
1264
exitcode = EXIT_FAILURE;
1265
/* Lower privileges */
765
1273
if((network.ifr_flags & IFF_UP) == 0){
766
1274
network.ifr_flags |= IFF_UP;
1275
take_down_interface = true;
767
1276
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1278
take_down_interface = false;
769
1279
perror("ioctl SIOCSIFFLAGS");
770
returncode = EXIT_FAILURE;
777
avahi_set_log_function(empty_log);
780
/* Initialize the psuedo-RNG */
781
srand((unsigned int) time(NULL));
783
/* Allocate main loop object */
784
if (!(simple_poll = avahi_simple_poll_new())) {
785
fprintf(stderr, "Failed to create simple poll object.\n");
786
returncode = EXIT_FAILURE;
790
/* Do not publish any local records */
1280
exitcode = EXIT_FAILURE;
1282
if(restore_loglevel){
1283
ret = klogctl(7, NULL, 0);
1288
#endif /* __linux__ */
1289
/* Lower privileges */
1298
/* sleep checking until interface is running */
1299
for(int i=0; i < delay * 4; i++){
1300
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1302
perror("ioctl SIOCGIFFLAGS");
1303
} else if(network.ifr_flags & IFF_RUNNING){
1306
struct timespec sleeptime = { .tv_nsec = 250000000 };
1307
ret = nanosleep(&sleeptime, NULL);
1308
if(ret == -1 and errno != EINTR){
1309
perror("nanosleep");
1312
if(not take_down_interface){
1313
/* We won't need the socket anymore */
1314
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1320
if(restore_loglevel){
1321
/* Restores kernel loglevel to default */
1322
ret = klogctl(7, NULL, 0);
1327
#endif /* __linux__ */
1328
/* Lower privileges */
1330
if(take_down_interface){
1331
/* Lower privileges */
1337
/* Lower privileges permanently */
1349
ret = init_gnutls_global(pubkey, seckey);
1351
fprintf(stderr, "init_gnutls_global failed\n");
1352
exitcode = EXIT_FAILURE;
1355
gnutls_initialized = true;
1362
tempdir_created = true;
1363
if(mkdtemp(tempdir) == NULL){
1364
tempdir_created = false;
1373
if(not init_gpgme(pubkey, seckey, tempdir)){
1374
fprintf(stderr, "init_gpgme failed\n");
1375
exitcode = EXIT_FAILURE;
1378
gpgme_initialized = true;
1385
if(connect_to != NULL){
1386
/* Connect directly, do not use Zeroconf */
1387
/* (Mainly meant for debugging) */
1388
char *address = strrchr(connect_to, ':');
1389
if(address == NULL){
1390
fprintf(stderr, "No colon in address\n");
1391
exitcode = EXIT_FAILURE;
1401
tmpmax = strtoimax(address+1, &tmp, 10);
1402
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1403
or tmpmax != (uint16_t)tmpmax){
1404
fprintf(stderr, "Bad port number\n");
1405
exitcode = EXIT_FAILURE;
1413
port = (uint16_t)tmpmax;
1415
address = connect_to;
1416
/* Colon in address indicates IPv6 */
1418
if(strchr(address, ':') != NULL){
1428
ret = start_mandos_communication(address, port, if_index, af);
1430
exitcode = EXIT_FAILURE;
1432
exitcode = EXIT_SUCCESS;
1442
AvahiServerConfig config;
1443
/* Do not publish any local Zeroconf records */
791
1444
avahi_server_config_init(&config);
792
1445
config.publish_hinfo = 0;
793
1446
config.publish_addresses = 0;
794
1447
config.publish_workstation = 0;
795
1448
config.publish_domain = 0;
797
1450
/* Allocate a new server */
798
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
799
&config, NULL, NULL, &error);
801
/* Free the configuration data */
1451
mc.server = avahi_server_new(avahi_simple_poll_get
1452
(mc.simple_poll), &config, NULL,
1455
/* Free the Avahi configuration data */
802
1456
avahi_server_config_free(&config);
804
/* Check if creating the server object succeeded */
806
fprintf(stderr, "Failed to create server: %s\n",
807
avahi_strerror(error));
808
returncode = EXIT_FAILURE;
812
/* Create the service browser */
813
sb = avahi_s_service_browser_new(server, if_index,
815
"_mandos._tcp", NULL, 0,
816
browse_callback, server);
818
fprintf(stderr, "Failed to create service browser: %s\n",
819
avahi_strerror(avahi_server_errno(server)));
820
returncode = EXIT_FAILURE;
824
/* Run the main loop */
827
fprintf(stderr, "Starting avahi loop search\n");
830
avahi_simple_poll_loop(simple_poll);
835
fprintf(stderr, "%s exiting\n", argv[0]);
840
avahi_s_service_browser_free(sb);
843
avahi_server_free(server);
846
avahi_simple_poll_free(simple_poll);
1459
/* Check if creating the Avahi server object succeeded */
1460
if(mc.server == NULL){
1461
fprintf(stderr, "Failed to create Avahi server: %s\n",
1462
avahi_strerror(error));
1463
exitcode = EXIT_FAILURE;
1471
/* Create the Avahi service browser */
1472
sb = avahi_s_service_browser_new(mc.server, if_index,
1473
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1474
NULL, 0, browse_callback, NULL);
1476
fprintf(stderr, "Failed to create service browser: %s\n",
1477
avahi_strerror(avahi_server_errno(mc.server)));
1478
exitcode = EXIT_FAILURE;
1486
/* Run the main loop */
1489
fprintf(stderr, "Starting Avahi loop search\n");
1492
avahi_simple_poll_loop(mc.simple_poll);
1497
fprintf(stderr, "%s exiting\n", argv[0]);
1500
/* Cleanup things */
1502
avahi_s_service_browser_free(sb);
1504
if(mc.server != NULL)
1505
avahi_server_free(mc.server);
1507
if(mc.simple_poll != NULL)
1508
avahi_simple_poll_free(mc.simple_poll);
1510
if(gnutls_initialized){
1511
gnutls_certificate_free_credentials(mc.cred);
1512
gnutls_global_deinit();
1513
gnutls_dh_params_deinit(mc.dh_params);
1516
if(gpgme_initialized){
1517
gpgme_release(mc.ctx);
1520
/* Take down the network interface */
1521
if(take_down_interface){
1522
/* Re-raise priviliges */
1529
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1531
perror("ioctl SIOCGIFFLAGS");
1532
} else if(network.ifr_flags & IFF_UP) {
1533
network.ifr_flags &= ~IFF_UP; /* clear flag */
1534
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1536
perror("ioctl SIOCSIFFLAGS");
1539
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1543
/* Lower privileges permanently */
1552
/* Removes the temp directory used by GPGME */
1553
if(tempdir_created){
1555
struct dirent *direntry;
1556
d = opendir(tempdir);
1558
if(errno != ENOENT){
1563
direntry = readdir(d);
1564
if(direntry == NULL){
1567
/* Skip "." and ".." */
1568
if(direntry->d_name[0] == '.'
1569
and (direntry->d_name[1] == '\0'
1570
or (direntry->d_name[1] == '.'
1571
and direntry->d_name[2] == '\0'))){
1574
char *fullname = NULL;
1575
ret = asprintf(&fullname, "%s/%s", tempdir,
1581
ret = remove(fullname);
1583
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1590
ret = rmdir(tempdir);
1591
if(ret == -1 and errno != ENOENT){
1597
sigemptyset(&old_sigterm_action.sa_mask);
1598
old_sigterm_action.sa_handler = SIG_DFL;
1599
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1600
&old_sigterm_action,
1603
perror("sigaction");
1606
ret = raise(signal_received);
1607
} while(ret != 0 and errno == EINTR);
1612
TEMP_FAILURE_RETRY(pause());