47
100
#include <avahi-common/malloc.h>
48
101
#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() */
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,
71
120
#define BUFFER_SIZE 256
74
const char *certdir = "/conf/conf.d/cryptkeyreq/";
75
const char *certfile = "openpgp-client.txt";
76
const char *certkey = "openpgp-client-key.txt";
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
220
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
104
if (rc != GPG_ERR_NO_ERROR){
221
if(rc != GPG_ERR_NO_ERROR){
105
222
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
106
223
gpgme_strsource(rc), gpgme_strerror(rc));
110
/* Set GPGME home directory */
111
rc = gpgme_get_engine_info (&engine_info);
112
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){
113
230
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
114
231
gpgme_strsource(rc), gpgme_strerror(rc));
117
234
while(engine_info != NULL){
118
235
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
119
236
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
120
engine_info->file_name, homedir);
237
engine_info->file_name, tempdir);
123
240
engine_info = engine_info->next;
125
242
if(engine_info == NULL){
126
fprintf(stderr, "Could not set home dir to %s\n", homedir);
130
/* Create new GPGME data buffer from packet buffer */
131
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
132
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){
133
283
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
134
284
gpgme_strsource(rc), gpgme_strerror(rc));
196
/* Delete the GPGME FILE pointer cryptotext data buffer */
197
gpgme_data_release(dh_crypto);
334
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
199
337
/* Seek back to the beginning of the GPGME plaintext data buffer */
200
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;
204
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
205
*new_packet = realloc(*new_packet,
206
(unsigned int)new_packet_capacity
208
if (*new_packet == NULL){
212
new_packet_capacity += BUFFER_SIZE;
346
plaintext_capacity = incbuffer(plaintext,
347
(size_t)plaintext_length,
349
if(plaintext_capacity == 0){
351
plaintext_length = -1;
215
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
355
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
217
357
/* Print the data, if any */
222
363
perror("gpgme_data_read");
225
new_packet_length += ret;
228
/* FIXME: check characters before printing to screen so to not print
229
terminal control characters */
231
/* fprintf(stderr, "decrypted password is: "); */
232
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
233
/* 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);
236
383
/* Delete the GPGME plaintext data buffer */
237
384
gpgme_data_release(dh_plain);
238
return new_packet_length;
385
return plaintext_length;
241
static const char * safer_gnutls_strerror (int value) {
242
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 */
244
392
ret = "(unknown)";
248
void debuggnutls(__attribute__((unused)) int level,
250
fprintf(stderr, "%s", string);
396
/* GnuTLS log function callback */
397
static void debuggnutls(__attribute__((unused)) int level,
399
fprintf(stderr, "GnuTLS: %s", string);
253
int initgnutls(encrypted_session *es){
402
static int init_gnutls_global(const char *pubkeyfilename,
403
const char *seckeyfilename){
258
407
fprintf(stderr, "Initializing GnuTLS\n");
261
if ((ret = gnutls_global_init ())
262
!= GNUTLS_E_SUCCESS) {
263
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."
268
421
gnutls_global_set_log_level(11);
269
422
gnutls_global_set_log_function(debuggnutls);
272
/* openpgp credentials */
273
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
274
!= GNUTLS_E_SUCCESS) {
275
fprintf (stderr, "memory error: %s\n",
276
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();
281
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
282
" 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,
286
443
ret = gnutls_certificate_set_openpgp_key_file
287
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
288
if (ret != GNUTLS_E_SUCCESS) {
290
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
292
ret, certfile, certkey);
293
fprintf(stdout, "The Error is: %s\n",
294
safer_gnutls_strerror(ret));
298
//GnuTLS server initialization
299
if ((ret = gnutls_dh_params_init (&es->dh_params))
300
!= GNUTLS_E_SUCCESS) {
301
fprintf (stderr, "Error in dh parameter initialization: %s\n",
302
safer_gnutls_strerror(ret));
306
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
307
!= GNUTLS_E_SUCCESS) {
308
fprintf (stderr, "Error in prime generation: %s\n",
309
safer_gnutls_strerror(ret));
313
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
315
// GnuTLS session creation
316
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
317
!= 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){
318
491
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
319
492
safer_gnutls_strerror(ret));
322
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
323
!= GNUTLS_E_SUCCESS) {
324
fprintf(stderr, "Syntax error at: %s\n", err);
325
fprintf(stderr, "GnuTLS error: %s\n",
326
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);
330
if ((ret = gnutls_credentials_set
331
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
332
!= GNUTLS_E_SUCCESS) {
333
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",
334
523
safer_gnutls_strerror(ret));
524
gnutls_deinit(*session);
338
528
/* ignore client certificate if any. */
339
gnutls_certificate_server_set_request (es->session,
529
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
342
gnutls_dh_set_prime_bits (es->session, DH_BITS);
531
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
347
void empty_log(__attribute__((unused)) AvahiLogLevel level,
348
__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){}
350
int start_mandos_communication(const char *ip, uint16_t port,
351
unsigned int if_index){
353
struct sockaddr_in6 to;
354
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;
355
550
char *buffer = NULL;
356
char *decrypted_buffer;
551
char *decrypted_buffer = NULL;
357
552
size_t buffer_length = 0;
358
553
size_t buffer_capacity = 0;
359
ssize_t decrypted_buffer_size;
362
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);
365
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
585
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
368
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
589
tcp_sd = socket(pf, SOCK_STREAM, 0);
370
592
perror("socket");
374
if(if_indextoname(if_index, interface) == NULL){
376
perror("if_indextoname");
382
fprintf(stderr, "Binding to interface %s\n", interface);
385
memset(&to,0,sizeof(to)); /* Spurious warning */
386
to.sin6_family = AF_INET6;
387
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);
389
612
perror("inet_pton");
393
618
fprintf(stderr, "Bad address: %s\n", ip);
396
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 */
398
to.sin6_scope_id = (uint32_t)if_index;
401
fprintf(stderr, "Connection to: %s\n", ip);
404
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
410
ret = initgnutls (&es);
416
gnutls_transport_set_ptr (es.session,
417
(gnutls_transport_ptr_t) tcp_sd);
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 */
693
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
706
const char *out = mandos_protocol_version;
709
size_t out_size = strlen(out);
710
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
711
out_size - written));
718
written += (size_t)ret;
719
if(written < out_size){
722
if(out == mandos_protocol_version){
420
737
fprintf(stderr, "Establishing TLS session with %s\n", ip);
423
ret = gnutls_handshake (es.session);
425
if (ret != GNUTLS_E_SUCCESS){
745
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
753
ret = gnutls_handshake(session);
758
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
760
if(ret != GNUTLS_E_SUCCESS){
427
fprintf(stderr, "\n*** Handshake failed ***\n");
762
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
434
//Retrieve OpenPGP packet that contains the wanted password
769
/* Read OpenPGP packet that contains the wanted password */
437
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
772
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
442
if (buffer_length + BUFFER_SIZE > buffer_capacity){
443
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
448
buffer_capacity += BUFFER_SIZE;
451
ret = gnutls_record_recv
452
(es.session, buffer+buffer_length, BUFFER_SIZE);
783
buffer_capacity = incbuffer(&buffer, buffer_length,
785
if(buffer_capacity == 0){
797
sret = gnutls_record_recv(session, buffer+buffer_length,
458
804
case GNUTLS_E_INTERRUPTED:
459
805
case GNUTLS_E_AGAIN:
461
807
case GNUTLS_E_REHANDSHAKE:
462
ret = gnutls_handshake (es.session);
464
fprintf(stderr, "\n*** Handshake failed ***\n");
809
ret = gnutls_handshake(session);
815
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
817
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
471
824
fprintf(stderr, "Unknown error while reading data from"
472
" encrypted session with mandos server\n");
474
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
825
" encrypted session with Mandos server\n");
826
gnutls_bye(session, GNUTLS_SHUT_RDWR);
478
buffer_length += (size_t) ret;
482
if (buffer_length > 0){
831
buffer_length += (size_t) sret;
836
fprintf(stderr, "Closing TLS session\n");
845
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
850
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
852
if(buffer_length > 0){
853
ssize_t decrypted_buffer_size;
483
854
decrypted_buffer_size = pgp_packet_decrypt(buffer,
487
if (decrypted_buffer_size >= 0){
488
while(written < decrypted_buffer_size){
489
ret = (int)fwrite (decrypted_buffer + written, 1,
490
(size_t)decrypted_buffer_size - written,
857
if(decrypted_buffer_size >= 0){
860
while(written < (size_t) decrypted_buffer_size){
866
ret = (int)fwrite(decrypted_buffer + written, 1,
867
(size_t)decrypted_buffer_size - written,
492
869
if(ret == 0 and ferror(stdout)){
494
872
fprintf(stderr, "Error writing encrypted data: %s\n",
495
873
strerror(errno));
500
878
written += (size_t)ret;
502
free(decrypted_buffer);
884
/* Shutdown procedure */
889
free(decrypted_buffer);
892
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
900
gnutls_deinit(session);
511
fprintf(stderr, "Closing TLS session\n");
515
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
518
gnutls_deinit (es.session);
519
gnutls_certificate_free_credentials (es.cred);
520
gnutls_global_deinit ();
524
static AvahiSimplePoll *simple_poll = NULL;
525
static AvahiServer *server = NULL;
527
static void resolve_callback(
528
AvahiSServiceResolver *r,
529
AvahiIfIndex interface,
530
AVAHI_GCC_UNUSED AvahiProtocol protocol,
531
AvahiResolverEvent event,
535
const char *host_name,
536
const AvahiAddress *address,
538
AVAHI_GCC_UNUSED AvahiStringList *txt,
539
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
540
AVAHI_GCC_UNUSED void* userdata) {
542
assert(r); /* Spurious warning */
910
static void resolve_callback(AvahiSServiceResolver *r,
911
AvahiIfIndex interface,
913
AvahiResolverEvent event,
917
const char *host_name,
918
const AvahiAddress *address,
920
AVAHI_GCC_UNUSED AvahiStringList *txt,
921
AVAHI_GCC_UNUSED AvahiLookupResultFlags
923
AVAHI_GCC_UNUSED void* userdata){
544
926
/* Called whenever a service has been resolved successfully or
549
935
case AVAHI_RESOLVER_FAILURE:
550
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
551
" type '%s' in domain '%s': %s\n", name, type, domain,
552
avahi_strerror(avahi_server_errno(server)));
936
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
937
" of type '%s' in domain '%s': %s\n", name, type, domain,
938
avahi_strerror(avahi_server_errno(mc.server)));
555
941
case AVAHI_RESOLVER_FOUND:
557
943
char ip[AVAHI_ADDRESS_STR_MAX];
558
944
avahi_address_snprint(ip, sizeof(ip), address);
560
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
561
" port %d\n", name, host_name, ip, port);
946
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
947
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
948
ip, (intmax_t)interface, port);
563
int ret = start_mandos_communication(ip, port,
564
(unsigned int) interface);
950
int ret = start_mandos_communication(ip, port, interface,
951
avahi_proto_to_af(proto));
953
avahi_simple_poll_quit(mc.simple_poll);
570
957
avahi_s_service_resolver_free(r);
573
static void browse_callback(
574
AvahiSServiceBrowser *b,
575
AvahiIfIndex interface,
576
AvahiProtocol protocol,
577
AvahiBrowserEvent event,
581
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
584
AvahiServer *s = userdata;
585
assert(b); /* Spurious warning */
587
/* Called whenever a new services becomes available on the LAN or
588
is removed from the LAN */
960
static void browse_callback(AvahiSServiceBrowser *b,
961
AvahiIfIndex interface,
962
AvahiProtocol protocol,
963
AvahiBrowserEvent event,
967
AVAHI_GCC_UNUSED AvahiLookupResultFlags
969
AVAHI_GCC_UNUSED void* userdata){
972
/* Called whenever a new services becomes available on the LAN or
973
is removed from the LAN */
981
case AVAHI_BROWSER_FAILURE:
983
fprintf(stderr, "(Avahi browser) %s\n",
984
avahi_strerror(avahi_server_errno(mc.server)));
985
avahi_simple_poll_quit(mc.simple_poll);
988
case AVAHI_BROWSER_NEW:
989
/* We ignore the returned Avahi resolver object. In the callback
990
function we free it. If the Avahi server is terminated before
991
the callback function is called the Avahi server will free the
994
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
995
name, type, domain, protocol, 0,
996
resolve_callback, NULL) == NULL)
997
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
998
name, avahi_strerror(avahi_server_errno(mc.server)));
1001
case AVAHI_BROWSER_REMOVE:
1004
case AVAHI_BROWSER_ALL_FOR_NOW:
1005
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1007
fprintf(stderr, "No Mandos server found, still searching...\n");
1013
/* stop main loop after sigterm has been called */
1014
static void handle_sigterm(int sig){
1019
signal_received = sig;
1020
int old_errno = errno;
1021
if(mc.simple_poll != NULL){
1022
avahi_simple_poll_quit(mc.simple_poll);
1028
* This function determines if a directory entry in /sys/class/net
1029
* corresponds to an acceptable network device.
1030
* (This function is passed to scandir(3) as a filter function.)
1032
int good_interface(const struct dirent *if_entry){
1034
char *flagname = NULL;
1035
if(if_entry->d_name[0] == '.'){
1038
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1044
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1051
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1052
/* read line from flags_fd */
1053
ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1054
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1055
flagstring[(size_t)to_read] = '\0';
1056
if(flagstring == NULL){
1062
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1079
tmpmax = strtoimax(flagstring, &tmp, 0);
1080
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1081
and not (isspace(*tmp)))
1082
or tmpmax != (ifreq_flags)tmpmax){
1084
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1085
flagstring, if_entry->d_name);
1091
ifreq_flags flags = (ifreq_flags)tmpmax;
1092
/* Reject the loopback device */
1093
if(flags & IFF_LOOPBACK){
1095
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1100
/* Accept point-to-point devices only if connect_to is specified */
1101
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1103
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1108
/* Otherwise, reject non-broadcast-capable devices */
1109
if(not (flags & IFF_BROADCAST)){
1111
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1116
/* Reject non-ARP interfaces (including dummy interfaces) */
1117
if(flags & IFF_NOARP){
1119
fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n",
1124
/* Accept this device */
1126
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1132
int main(int argc, char *argv[]){
1133
AvahiSServiceBrowser *sb = NULL;
1138
int exitcode = EXIT_SUCCESS;
1139
const char *interface = "";
1140
struct ifreq network;
1142
bool take_down_interface = false;
1145
char tempdir[] = "/tmp/mandosXXXXXX";
1146
bool tempdir_created = false;
1147
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1148
const char *seckey = PATHDIR "/" SECKEY;
1149
const char *pubkey = PATHDIR "/" PUBKEY;
1151
bool gnutls_initialized = false;
1152
bool gpgme_initialized = false;
1155
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1156
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1161
/* Lower any group privileges we might have, just to be safe */
1168
/* Lower user privileges (temporarily) */
1180
struct argp_option options[] = {
1181
{ .name = "debug", .key = 128,
1182
.doc = "Debug mode", .group = 3 },
1183
{ .name = "connect", .key = 'c',
1184
.arg = "ADDRESS:PORT",
1185
.doc = "Connect directly to a specific Mandos server",
1187
{ .name = "interface", .key = 'i',
1189
.doc = "Network interface that will be used to search for"
1192
{ .name = "seckey", .key = 's',
1194
.doc = "OpenPGP secret key file base name",
1196
{ .name = "pubkey", .key = 'p',
1198
.doc = "OpenPGP public key file base name",
1200
{ .name = "dh-bits", .key = 129,
1202
.doc = "Bit length of the prime number used in the"
1203
" Diffie-Hellman key exchange",
1205
{ .name = "priority", .key = 130,
1207
.doc = "GnuTLS priority string for the TLS handshake",
1209
{ .name = "delay", .key = 131,
1211
.doc = "Maximum delay to wait for interface startup",
1214
* These reproduce what we would get without ARGP_NO_HELP
1216
{ .name = "help", .key = '?',
1217
.doc = "Give this help list", .group = -1 },
1218
{ .name = "usage", .key = -3,
1219
.doc = "Give a short usage message", .group = -1 },
1220
{ .name = "version", .key = 'V',
1221
.doc = "Print program version", .group = -1 },
1225
error_t parse_opt(int key, char *arg,
1226
struct argp_state *state){
1229
case 128: /* --debug */
1232
case 'c': /* --connect */
1235
case 'i': /* --interface */
1238
case 's': /* --seckey */
1241
case 'p': /* --pubkey */
1244
case 129: /* --dh-bits */
1246
tmpmax = strtoimax(arg, &tmp, 10);
1247
if(errno != 0 or tmp == arg or *tmp != '\0'
1248
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1249
argp_error(state, "Bad number of DH bits");
1251
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1253
case 130: /* --priority */
1256
case 131: /* --delay */
1258
delay = strtof(arg, &tmp);
1259
if(errno != 0 or tmp == arg or *tmp != '\0'){
1260
argp_error(state, "Bad delay");
1264
* These reproduce what we would get without ARGP_NO_HELP
1266
case '?': /* --help */
1267
argp_state_help(state, state->out_stream,
1268
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1269
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1270
case -3: /* --usage */
1271
argp_state_help(state, state->out_stream,
1272
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1273
case 'V': /* --version */
1274
fprintf(state->out_stream, "%s\n", argp_program_version);
1275
exit(argp_err_exit_status);
1278
return ARGP_ERR_UNKNOWN;
1283
struct argp argp = { .options = options, .parser = parse_opt,
1285
.doc = "Mandos client -- Get and decrypt"
1286
" passwords from a Mandos server" };
1287
ret = argp_parse(&argp, argc, argv,
1288
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
592
case AVAHI_BROWSER_FAILURE:
594
fprintf(stderr, "(Browser) %s\n",
595
avahi_strerror(avahi_server_errno(server)));
596
avahi_simple_poll_quit(simple_poll);
599
case AVAHI_BROWSER_NEW:
600
/* We ignore the returned resolver object. In the callback
601
function we free it. If the server is terminated before
602
the callback function is called the server will free
603
the resolver for us. */
605
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
607
AVAHI_PROTO_INET6, 0,
608
resolve_callback, s)))
609
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
610
avahi_strerror(avahi_server_errno(s)));
613
case AVAHI_BROWSER_REMOVE:
616
case AVAHI_BROWSER_ALL_FOR_NOW:
617
case AVAHI_BROWSER_CACHE_EXHAUSTED:
622
/* combinds two strings and returns the malloced new string. som sane checks could/should be added */
623
const char *combinestrings(const char *first, const char *second){
625
tmp = malloc(strlen(first) + strlen(second));
636
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1295
perror("argp_parse");
1296
exitcode = EX_OSERR;
1299
exitcode = EX_USAGE;
1305
avahi_set_log_function(empty_log);
1308
if(interface[0] == '\0'){
1309
struct dirent **direntries;
1310
ret = scandir(sys_class_net, &direntries, good_interface,
1313
/* Pick the first good interface */
1314
interface = strdup(direntries[0]->d_name);
1316
fprintf(stderr, "Using interface \"%s\"\n", interface);
1318
if(interface == NULL){
1321
exitcode = EXIT_FAILURE;
1327
fprintf(stderr, "Could not find a network interface\n");
1328
exitcode = EXIT_FAILURE;
1333
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1334
from the signal handler */
1335
/* Initialize the pseudo-RNG for Avahi */
1336
srand((unsigned int) time(NULL));
1337
mc.simple_poll = avahi_simple_poll_new();
1338
if(mc.simple_poll == NULL){
1339
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1340
exitcode = EX_UNAVAILABLE;
1344
sigemptyset(&sigterm_action.sa_mask);
1345
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1347
perror("sigaddset");
1348
exitcode = EX_OSERR;
1351
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1353
perror("sigaddset");
1354
exitcode = EX_OSERR;
1357
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1359
perror("sigaddset");
1360
exitcode = EX_OSERR;
1363
/* Need to check if the handler is SIG_IGN before handling:
1364
| [[info:libc:Initial Signal Actions]] |
1365
| [[info:libc:Basic Signal Handling]] |
1367
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1369
perror("sigaction");
1372
if(old_sigterm_action.sa_handler != SIG_IGN){
1373
ret = sigaction(SIGINT, &sigterm_action, NULL);
1375
perror("sigaction");
1376
exitcode = EX_OSERR;
1380
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1382
perror("sigaction");
1385
if(old_sigterm_action.sa_handler != SIG_IGN){
1386
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1388
perror("sigaction");
1389
exitcode = EX_OSERR;
1393
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1395
perror("sigaction");
1398
if(old_sigterm_action.sa_handler != SIG_IGN){
1399
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1401
perror("sigaction");
1402
exitcode = EX_OSERR;
1407
/* If the interface is down, bring it up */
1408
if(strcmp(interface, "none") != 0){
1409
if_index = (AvahiIfIndex) if_nametoindex(interface);
1411
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1412
exitcode = EX_UNAVAILABLE;
1420
/* Re-raise priviliges */
1428
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1429
messages about the network interface to mess up the prompt */
1430
ret = klogctl(8, NULL, 5);
1431
bool restore_loglevel = true;
1433
restore_loglevel = false;
1436
#endif /* __linux__ */
1438
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1441
exitcode = EX_OSERR;
1443
if(restore_loglevel){
1444
ret = klogctl(7, NULL, 0);
1449
#endif /* __linux__ */
1450
/* Lower privileges */
1458
strcpy(network.ifr_name, interface);
1459
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1461
perror("ioctl SIOCGIFFLAGS");
1463
if(restore_loglevel){
1464
ret = klogctl(7, NULL, 0);
1469
#endif /* __linux__ */
1470
exitcode = EX_OSERR;
1471
/* Lower privileges */
1479
if((network.ifr_flags & IFF_UP) == 0){
1480
network.ifr_flags |= IFF_UP;
1481
take_down_interface = true;
1482
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1484
take_down_interface = false;
1485
perror("ioctl SIOCSIFFLAGS +IFF_UP");
1486
exitcode = EX_OSERR;
1488
if(restore_loglevel){
1489
ret = klogctl(7, NULL, 0);
1494
#endif /* __linux__ */
1495
/* Lower privileges */
1504
/* sleep checking until interface is running */
1505
for(int i=0; i < delay * 4; i++){
1506
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1508
perror("ioctl SIOCGIFFLAGS");
1509
} else if(network.ifr_flags & IFF_RUNNING){
1512
struct timespec sleeptime = { .tv_nsec = 250000000 };
1513
ret = nanosleep(&sleeptime, NULL);
1514
if(ret == -1 and errno != EINTR){
1515
perror("nanosleep");
1518
if(not take_down_interface){
1519
/* We won't need the socket anymore */
1520
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1526
if(restore_loglevel){
1527
/* Restores kernel loglevel to default */
1528
ret = klogctl(7, NULL, 0);
1533
#endif /* __linux__ */
1534
/* Lower privileges */
1536
if(take_down_interface){
1537
/* Lower privileges */
1543
/* Lower privileges permanently */
1555
ret = init_gnutls_global(pubkey, seckey);
1557
fprintf(stderr, "init_gnutls_global failed\n");
1558
exitcode = EX_UNAVAILABLE;
1561
gnutls_initialized = true;
1568
tempdir_created = true;
1569
if(mkdtemp(tempdir) == NULL){
1570
tempdir_created = false;
1579
if(not init_gpgme(pubkey, seckey, tempdir)){
1580
fprintf(stderr, "init_gpgme failed\n");
1581
exitcode = EX_UNAVAILABLE;
1584
gpgme_initialized = true;
1591
if(connect_to != NULL){
1592
/* Connect directly, do not use Zeroconf */
1593
/* (Mainly meant for debugging) */
1594
char *address = strrchr(connect_to, ':');
1595
if(address == NULL){
1596
fprintf(stderr, "No colon in address\n");
1597
exitcode = EX_USAGE;
1607
tmpmax = strtoimax(address+1, &tmp, 10);
1608
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1609
or tmpmax != (uint16_t)tmpmax){
1610
fprintf(stderr, "Bad port number\n");
1611
exitcode = EX_USAGE;
1619
port = (uint16_t)tmpmax;
1621
address = connect_to;
1622
/* Colon in address indicates IPv6 */
1624
if(strchr(address, ':') != NULL){
1634
while(not quit_now){
1635
ret = start_mandos_communication(address, port, if_index, af);
1636
if(quit_now or ret == 0){
1643
exitcode = EXIT_SUCCESS;
637
1654
AvahiServerConfig config;
638
AvahiSServiceBrowser *sb = NULL;
641
int returncode = EXIT_SUCCESS;
642
const char *interface = "eth0";
645
static struct option long_options[] = {
646
{"debug", no_argument, (int *)&debug, 1},
647
{"interface", required_argument, 0, 'i'},
648
{"certdir", required_argument, 0, 'd'},
649
{"certkey", required_argument, 0, 'c'},
650
{"certfile", required_argument, 0, 'k'},
653
int option_index = 0;
654
ret = getopt_long (argc, argv, "i:", long_options,
681
certfile = combinestrings(certdir, certfile);
682
if (certfile == NULL){
686
certkey = combinestrings(certdir, certkey);
687
if (certkey == NULL){
692
avahi_set_log_function(empty_log);
695
/* Initialize the psuedo-RNG */
696
srand((unsigned int) time(NULL));
698
/* Allocate main loop object */
699
if (!(simple_poll = avahi_simple_poll_new())) {
700
fprintf(stderr, "Failed to create simple poll object.\n");
705
/* Do not publish any local records */
1655
/* Do not publish any local Zeroconf records */
706
1656
avahi_server_config_init(&config);
707
1657
config.publish_hinfo = 0;
708
1658
config.publish_addresses = 0;
709
1659
config.publish_workstation = 0;
710
1660
config.publish_domain = 0;
712
1662
/* Allocate a new server */
713
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
714
&config, NULL, NULL, &error);
716
/* 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 */
717
1668
avahi_server_config_free(&config);
719
/* Check if creating the server object succeeded */
721
fprintf(stderr, "Failed to create server: %s\n",
722
avahi_strerror(error));
723
returncode = EXIT_FAILURE;
727
/* Create the service browser */
728
sb = avahi_s_service_browser_new(server,
730
if_nametoindex(interface),
732
"_mandos._tcp", NULL, 0,
733
browse_callback, server);
735
fprintf(stderr, "Failed to create service browser: %s\n",
736
avahi_strerror(avahi_server_errno(server)));
737
returncode = EXIT_FAILURE;
741
/* Run the main loop */
744
fprintf(stderr, "Starting avahi loop search\n");
747
avahi_simple_poll_loop(simple_poll);
752
fprintf(stderr, "%s exiting\n", argv[0]);
757
avahi_s_service_browser_free(sb);
760
avahi_server_free(server);
763
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());