47
110
#include <avahi-common/malloc.h>
48
111
#include <avahi-common/error.h>
51
#include <sys/types.h> /* socket(), setsockopt(),
53
#include <sys/socket.h> /* socket(), setsockopt(),
55
struct in6_addr, inet_pton() */
56
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
57
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
59
#include <unistd.h> /* close() */
60
#include <netinet/in.h>
61
#include <stdbool.h> /* true */
62
#include <string.h> /* memset */
63
#include <arpa/inet.h> /* inet_pton() */
64
#include <iso646.h> /* not */
67
#include <errno.h> /* perror() */
74
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
76
#define CERTFILE CERT_ROOT "openpgp-client.txt"
77
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
114
#include <gnutls/gnutls.h> /* All GnuTLS types, constants and
117
init_gnutls_session(),
119
#include <gnutls/openpgp.h>
120
/* gnutls_certificate_set_openpgp_key_file(),
121
GNUTLS_OPENPGP_FMT_BASE64 */
124
#include <gpgme.h> /* All GPGME types, constants and
127
GPGME_PROTOCOL_OpenPGP,
78
130
#define BUFFER_SIZE 256
132
#define PATHDIR "/conf/conf.d/mandos"
133
#define SECKEY "seckey.txt"
134
#define PUBKEY "pubkey.txt"
135
#define HOOKDIR "/lib/mandos/network-hooks.d"
81
137
bool debug = false;
138
static const char mandos_protocol_version[] = "1";
139
const char *argp_program_version = "mandos-client " VERSION;
140
const char *argp_program_bug_address = "<mandos@recompile.se>";
141
static const char sys_class_net[] = "/sys/class/net";
142
char *connect_to = NULL;
143
const char *hookdir = HOOKDIR;
148
/* Doubly linked list that need to be circularly linked when used */
149
typedef struct server{
152
AvahiIfIndex if_index;
154
struct timespec last_seen;
159
/* Used for passing in values through the Avahi callback functions */
84
gnutls_session_t session;
85
162
gnutls_certificate_credentials_t cred;
163
unsigned int dh_bits;
86
164
gnutls_dh_params_t dh_params;
90
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
91
char **new_packet, const char *homedir){
92
gpgme_data_t dh_crypto, dh_plain;
165
const char *priority;
167
server *current_server;
169
size_t interfaces_size;
172
/* global so signal handler can reach it*/
173
AvahiSimplePoll *simple_poll;
175
sig_atomic_t quit_now = 0;
176
int signal_received = 0;
178
/* Function to use when printing errors */
179
void perror_plus(const char *print_text){
181
fprintf(stderr, "Mandos plugin %s: ",
182
program_invocation_short_name);
187
__attribute__((format (gnu_printf, 2, 3), nonnull))
188
int fprintf_plus(FILE *stream, const char *format, ...){
190
va_start (ap, format);
192
TEMP_FAILURE_RETRY(fprintf(stream, "Mandos plugin %s: ",
193
program_invocation_short_name));
194
return (int)TEMP_FAILURE_RETRY(vfprintf(stream, format, ap));
198
* Make additional room in "buffer" for at least BUFFER_SIZE more
199
* bytes. "buffer_capacity" is how much is currently allocated,
200
* "buffer_length" is how much is already used.
202
__attribute__((nonnull, warn_unused_result))
203
size_t incbuffer(char **buffer, size_t buffer_length,
204
size_t buffer_capacity){
205
if(buffer_length + BUFFER_SIZE > buffer_capacity){
206
char *new_buf = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
208
int old_errno = errno;
215
buffer_capacity += BUFFER_SIZE;
217
return buffer_capacity;
220
/* Add server to set of servers to retry periodically */
221
__attribute__((nonnull, warn_unused_result))
222
bool add_server(const char *ip, in_port_t port, AvahiIfIndex if_index,
223
int af, server **current_server){
225
server *new_server = malloc(sizeof(server));
226
if(new_server == NULL){
227
perror_plus("malloc");
230
*new_server = (server){ .ip = strdup(ip),
232
.if_index = if_index,
234
if(new_server->ip == NULL){
235
perror_plus("strdup");
238
ret = clock_gettime(CLOCK_MONOTONIC, &(new_server->last_seen));
240
perror_plus("clock_gettime");
243
/* Special case of first server */
244
if(*current_server == NULL){
245
new_server->next = new_server;
246
new_server->prev = new_server;
247
*current_server = new_server;
249
/* Place the new server last in the list */
250
new_server->next = *current_server;
251
new_server->prev = (*current_server)->prev;
252
new_server->prev->next = new_server;
253
(*current_server)->prev = new_server;
261
__attribute__((nonnull, warn_unused_result))
262
static bool init_gpgme(const char * const seckey,
263
const char * const pubkey,
264
const char * const tempdir,
96
ssize_t new_packet_capacity = 0;
97
ssize_t new_packet_length = 0;
98
267
gpgme_engine_info_t engine_info;
101
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
270
* Helper function to insert pub and seckey to the engine keyring.
272
bool import_key(const char * const filename){
275
gpgme_data_t pgp_data;
277
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
283
rc = gpgme_data_new_from_fd(&pgp_data, fd);
284
if(rc != GPG_ERR_NO_ERROR){
285
fprintf_plus(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
286
gpgme_strsource(rc), gpgme_strerror(rc));
290
rc = gpgme_op_import(mc->ctx, pgp_data);
291
if(rc != GPG_ERR_NO_ERROR){
292
fprintf_plus(stderr, "bad gpgme_op_import: %s: %s\n",
293
gpgme_strsource(rc), gpgme_strerror(rc));
297
ret = (int)TEMP_FAILURE_RETRY(close(fd));
299
perror_plus("close");
301
gpgme_data_release(pgp_data);
306
fprintf_plus(stderr, "Initializing GPGME\n");
105
310
gpgme_check_version(NULL);
106
gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
311
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
312
if(rc != GPG_ERR_NO_ERROR){
313
fprintf_plus(stderr, "bad gpgme_engine_check_version: %s: %s\n",
314
gpgme_strsource(rc), gpgme_strerror(rc));
108
/* Set GPGME home directory */
109
rc = gpgme_get_engine_info (&engine_info);
110
if (rc != GPG_ERR_NO_ERROR){
111
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
112
gpgme_strsource(rc), gpgme_strerror(rc));
318
/* Set GPGME home directory for the OpenPGP engine only */
319
rc = gpgme_get_engine_info(&engine_info);
320
if(rc != GPG_ERR_NO_ERROR){
321
fprintf_plus(stderr, "bad gpgme_get_engine_info: %s: %s\n",
322
gpgme_strsource(rc), gpgme_strerror(rc));
115
325
while(engine_info != NULL){
116
326
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
117
327
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
118
engine_info->file_name, homedir);
328
engine_info->file_name, tempdir);
121
331
engine_info = engine_info->next;
123
333
if(engine_info == NULL){
124
fprintf(stderr, "Could not set home dir to %s\n", homedir);
128
/* Create new GPGME data buffer from packet buffer */
129
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
130
if (rc != GPG_ERR_NO_ERROR){
131
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
132
gpgme_strsource(rc), gpgme_strerror(rc));
334
fprintf_plus(stderr, "Could not set GPGME home dir to %s\n",
339
/* Create new GPGME "context" */
340
rc = gpgme_new(&(mc->ctx));
341
if(rc != GPG_ERR_NO_ERROR){
342
fprintf_plus(stderr, "Mandos plugin mandos-client: "
343
"bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
348
if(not import_key(pubkey) or not import_key(seckey)){
356
* Decrypt OpenPGP data.
357
* Returns -1 on error
359
__attribute__((nonnull, warn_unused_result))
360
static ssize_t pgp_packet_decrypt(const char *cryptotext,
364
gpgme_data_t dh_crypto, dh_plain;
367
size_t plaintext_capacity = 0;
368
ssize_t plaintext_length = 0;
371
fprintf_plus(stderr, "Trying to decrypt OpenPGP data\n");
374
/* Create new GPGME data buffer from memory cryptotext */
375
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
377
if(rc != GPG_ERR_NO_ERROR){
378
fprintf_plus(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
379
gpgme_strsource(rc), gpgme_strerror(rc));
136
383
/* Create new empty GPGME data buffer for the plaintext */
137
384
rc = gpgme_data_new(&dh_plain);
138
if (rc != GPG_ERR_NO_ERROR){
139
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
140
gpgme_strsource(rc), gpgme_strerror(rc));
144
/* Create new GPGME "context" */
145
rc = gpgme_new(&ctx);
146
if (rc != GPG_ERR_NO_ERROR){
147
fprintf(stderr, "bad gpgme_new: %s: %s\n",
148
gpgme_strsource(rc), gpgme_strerror(rc));
152
/* Decrypt data from the FILE pointer to the plaintext data
154
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
155
if (rc != GPG_ERR_NO_ERROR){
156
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
157
gpgme_strsource(rc), gpgme_strerror(rc));
162
fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
166
gpgme_decrypt_result_t result;
167
result = gpgme_op_decrypt_result(ctx);
169
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
171
fprintf(stderr, "Unsupported algorithm: %s\n",
172
result->unsupported_algorithm);
173
fprintf(stderr, "Wrong key usage: %d\n",
174
result->wrong_key_usage);
175
if(result->file_name != NULL){
176
fprintf(stderr, "File name: %s\n", result->file_name);
178
gpgme_recipient_t recipient;
179
recipient = result->recipients;
385
if(rc != GPG_ERR_NO_ERROR){
386
fprintf_plus(stderr, "Mandos plugin mandos-client: "
387
"bad gpgme_data_new: %s: %s\n",
388
gpgme_strsource(rc), gpgme_strerror(rc));
389
gpgme_data_release(dh_crypto);
393
/* Decrypt data from the cryptotext data buffer to the plaintext
395
rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
396
if(rc != GPG_ERR_NO_ERROR){
397
fprintf_plus(stderr, "bad gpgme_op_decrypt: %s: %s\n",
398
gpgme_strsource(rc), gpgme_strerror(rc));
399
plaintext_length = -1;
401
gpgme_decrypt_result_t result;
402
result = gpgme_op_decrypt_result(mc->ctx);
404
fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
406
fprintf_plus(stderr, "Unsupported algorithm: %s\n",
407
result->unsupported_algorithm);
408
fprintf_plus(stderr, "Wrong key usage: %u\n",
409
result->wrong_key_usage);
410
if(result->file_name != NULL){
411
fprintf_plus(stderr, "File name: %s\n", result->file_name);
413
gpgme_recipient_t recipient;
414
recipient = result->recipients;
181
415
while(recipient != NULL){
182
fprintf(stderr, "Public key algorithm: %s\n",
183
gpgme_pubkey_algo_name(recipient->pubkey_algo));
184
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
185
fprintf(stderr, "Secret key available: %s\n",
186
recipient->status == GPG_ERR_NO_SECKEY
416
fprintf_plus(stderr, "Public key algorithm: %s\n",
417
gpgme_pubkey_algo_name
418
(recipient->pubkey_algo));
419
fprintf_plus(stderr, "Key ID: %s\n", recipient->keyid);
420
fprintf_plus(stderr, "Secret key available: %s\n",
421
recipient->status == GPG_ERR_NO_SECKEY
188
423
recipient = recipient->next;
194
/* Delete the GPGME FILE pointer cryptotext data buffer */
195
gpgme_data_release(dh_crypto);
431
fprintf_plus(stderr, "Decryption of OpenPGP data succeeded\n");
197
434
/* Seek back to the beginning of the GPGME plaintext data buffer */
198
gpgme_data_seek(dh_plain, 0, SEEK_SET);
435
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
436
perror_plus("gpgme_data_seek");
437
plaintext_length = -1;
202
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
203
*new_packet = realloc(*new_packet,
204
(unsigned int)new_packet_capacity
206
if (*new_packet == NULL){
210
new_packet_capacity += BUFFER_SIZE;
443
plaintext_capacity = incbuffer(plaintext,
444
(size_t)plaintext_length,
446
if(plaintext_capacity == 0){
447
perror_plus("incbuffer");
448
plaintext_length = -1;
213
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
452
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
215
454
/* Print the data, if any */
220
perror("gpgme_data_read");
223
new_packet_length += ret;
226
/* FIXME: check characters before printing to screen so to not print
227
terminal control characters */
229
/* fprintf(stderr, "decrypted password is: "); */
230
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
231
/* fprintf(stderr, "\n"); */
460
perror_plus("gpgme_data_read");
461
plaintext_length = -1;
464
plaintext_length += ret;
468
fprintf_plus(stderr, "Decrypted password is: ");
469
for(ssize_t i = 0; i < plaintext_length; i++){
470
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
472
fprintf(stderr, "\n");
477
/* Delete the GPGME cryptotext data buffer */
478
gpgme_data_release(dh_crypto);
234
480
/* Delete the GPGME plaintext data buffer */
235
481
gpgme_data_release(dh_plain);
236
return new_packet_length;
482
return plaintext_length;
239
static const char * safer_gnutls_strerror (int value) {
240
const char *ret = gnutls_strerror (value);
485
__attribute__((warn_unused_result))
486
static const char *safer_gnutls_strerror(int value){
487
const char *ret = gnutls_strerror(value);
242
489
ret = "(unknown)";
246
void debuggnutls(__attribute__((unused)) int level,
248
fprintf(stderr, "%s", string);
493
/* GnuTLS log function callback */
494
__attribute__((nonnull))
495
static void debuggnutls(__attribute__((unused)) int level,
497
fprintf_plus(stderr, "GnuTLS: %s", string);
251
int initgnutls(encrypted_session *es){
500
__attribute__((nonnull, warn_unused_result))
501
static int init_gnutls_global(const char *pubkeyfilename,
502
const char *seckeyfilename,
256
fprintf(stderr, "Initializing GnuTLS\n");
507
fprintf_plus(stderr, "Initializing GnuTLS\n");
259
if ((ret = gnutls_global_init ())
260
!= GNUTLS_E_SUCCESS) {
261
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
510
ret = gnutls_global_init();
511
if(ret != GNUTLS_E_SUCCESS){
512
fprintf_plus(stderr, "GnuTLS global_init: %s\n",
513
safer_gnutls_strerror(ret));
518
/* "Use a log level over 10 to enable all debugging options."
266
521
gnutls_global_set_log_level(11);
267
522
gnutls_global_set_log_function(debuggnutls);
270
/* openpgp credentials */
271
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
272
!= GNUTLS_E_SUCCESS) {
273
fprintf (stderr, "memory error: %s\n",
274
safer_gnutls_strerror(ret));
525
/* OpenPGP credentials */
526
ret = gnutls_certificate_allocate_credentials(&mc->cred);
527
if(ret != GNUTLS_E_SUCCESS){
528
fprintf_plus(stderr, "GnuTLS memory error: %s\n",
529
safer_gnutls_strerror(ret));
530
gnutls_global_deinit();
279
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
280
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
535
fprintf_plus(stderr, "Attempting to use OpenPGP public key %s and"
536
" secret key %s as GnuTLS credentials\n",
284
541
ret = gnutls_certificate_set_openpgp_key_file
285
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
286
if (ret != GNUTLS_E_SUCCESS) {
288
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
290
ret, CERTFILE, KEYFILE);
291
fprintf(stdout, "The Error is: %s\n",
292
safer_gnutls_strerror(ret));
296
//GnuTLS server initialization
297
if ((ret = gnutls_dh_params_init (&es->dh_params))
298
!= GNUTLS_E_SUCCESS) {
299
fprintf (stderr, "Error in dh parameter initialization: %s\n",
300
safer_gnutls_strerror(ret));
304
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
305
!= GNUTLS_E_SUCCESS) {
306
fprintf (stderr, "Error in prime generation: %s\n",
307
safer_gnutls_strerror(ret));
311
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
313
// GnuTLS session creation
314
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
315
!= GNUTLS_E_SUCCESS){
316
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
317
safer_gnutls_strerror(ret));
320
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
321
!= GNUTLS_E_SUCCESS) {
322
fprintf(stderr, "Syntax error at: %s\n", err);
323
fprintf(stderr, "GnuTLS error: %s\n",
324
safer_gnutls_strerror(ret));
328
if ((ret = gnutls_credentials_set
329
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
330
!= GNUTLS_E_SUCCESS) {
331
fprintf(stderr, "Error setting a credentials set: %s\n",
332
safer_gnutls_strerror(ret));
542
(mc->cred, pubkeyfilename, seckeyfilename,
543
GNUTLS_OPENPGP_FMT_BASE64);
544
if(ret != GNUTLS_E_SUCCESS){
546
"Error[%d] while reading the OpenPGP key pair ('%s',"
547
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
548
fprintf_plus(stderr, "The GnuTLS error is: %s\n",
549
safer_gnutls_strerror(ret));
553
/* GnuTLS server initialization */
554
ret = gnutls_dh_params_init(&mc->dh_params);
555
if(ret != GNUTLS_E_SUCCESS){
556
fprintf_plus(stderr, "Error in GnuTLS DH parameter"
557
" initialization: %s\n",
558
safer_gnutls_strerror(ret));
561
ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
562
if(ret != GNUTLS_E_SUCCESS){
563
fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
564
safer_gnutls_strerror(ret));
568
gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
574
gnutls_certificate_free_credentials(mc->cred);
575
gnutls_global_deinit();
576
gnutls_dh_params_deinit(mc->dh_params);
580
__attribute__((nonnull, warn_unused_result))
581
static int init_gnutls_session(gnutls_session_t *session,
584
/* GnuTLS session creation */
586
ret = gnutls_init(session, GNUTLS_SERVER);
590
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
591
if(ret != GNUTLS_E_SUCCESS){
593
"Error in GnuTLS session initialization: %s\n",
594
safer_gnutls_strerror(ret));
600
ret = gnutls_priority_set_direct(*session, mc->priority, &err);
602
gnutls_deinit(*session);
605
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
606
if(ret != GNUTLS_E_SUCCESS){
607
fprintf_plus(stderr, "Syntax error at: %s\n", err);
608
fprintf_plus(stderr, "GnuTLS error: %s\n",
609
safer_gnutls_strerror(ret));
610
gnutls_deinit(*session);
616
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
619
gnutls_deinit(*session);
622
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
623
if(ret != GNUTLS_E_SUCCESS){
624
fprintf_plus(stderr, "Error setting GnuTLS credentials: %s\n",
625
safer_gnutls_strerror(ret));
626
gnutls_deinit(*session);
336
630
/* ignore client certificate if any. */
337
gnutls_certificate_server_set_request (es->session,
631
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
340
gnutls_dh_set_prime_bits (es->session, DH_BITS);
633
gnutls_dh_set_prime_bits(*session, mc->dh_bits);
345
void empty_log(__attribute__((unused)) AvahiLogLevel level,
346
__attribute__((unused)) const char *txt){}
638
/* Avahi log function callback */
639
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
640
__attribute__((unused)) const char *txt){}
348
int start_mandos_communication(char *ip, uint16_t port,
349
unsigned int if_index){
351
struct sockaddr_in6 to;
352
encrypted_session es;
642
/* Called when a Mandos server is found */
643
__attribute__((nonnull, warn_unused_result))
644
static int start_mandos_communication(const char *ip, in_port_t port,
645
AvahiIfIndex if_index,
646
int af, mandos_context *mc){
647
int ret, tcp_sd = -1;
649
struct sockaddr_storage to;
353
650
char *buffer = NULL;
354
char *decrypted_buffer;
651
char *decrypted_buffer = NULL;
355
652
size_t buffer_length = 0;
356
653
size_t buffer_capacity = 0;
357
ssize_t decrypted_buffer_size;
359
char interface[IF_NAMESIZE];
362
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
365
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
371
if(if_indextoname(if_index, interface) == NULL){
373
perror("if_indextoname");
379
fprintf(stderr, "Binding to interface %s\n", interface);
382
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
384
perror("setsockopt bindtodevice");
388
memset(&to,0,sizeof(to));
389
to.sin6_family = AF_INET6;
390
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
656
gnutls_session_t session;
657
int pf; /* Protocol family */
674
fprintf_plus(stderr, "Bad address family: %d\n", af);
679
/* If the interface is specified and we have a list of interfaces */
680
if(if_index != AVAHI_IF_UNSPEC and mc->interfaces != NULL){
681
/* Check if the interface is one of the interfaces we are using */
684
char *interface = NULL;
685
while((interface=argz_next(mc->interfaces, mc->interfaces_size,
687
if(if_nametoindex(interface) == (unsigned int)if_index){
694
/* This interface does not match any in the list, so we don't
695
connect to the server */
697
char interface[IF_NAMESIZE];
698
if(if_indextoname((unsigned int)if_index, interface) == NULL){
699
perror_plus("if_indextoname");
701
fprintf_plus(stderr, "Skipping server on non-used interface"
703
if_indextoname((unsigned int)if_index,
711
ret = init_gnutls_session(&session, mc);
717
fprintf_plus(stderr, "Setting up a TCP connection to %s, port %"
718
PRIuMAX "\n", ip, (uintmax_t)port);
721
tcp_sd = socket(pf, SOCK_STREAM, 0);
724
perror_plus("socket");
734
memset(&to, 0, sizeof(to));
736
((struct sockaddr_in6 *)&to)->sin6_family = (sa_family_t)af;
737
ret = inet_pton(af, ip, &((struct sockaddr_in6 *)&to)->sin6_addr);
739
((struct sockaddr_in *)&to)->sin_family = (sa_family_t)af;
740
ret = inet_pton(af, ip, &((struct sockaddr_in *)&to)->sin_addr);
744
perror_plus("inet_pton");
396
fprintf(stderr, "Bad address: %s\n", ip);
399
/* Spurious warnings for the next line, see for instance
400
<http://bugs.debian.org/488884> */
401
to.sin6_port = htons(port);
403
to.sin6_scope_id = (uint32_t)if_index;
406
fprintf(stderr, "Connection to: %s\n", ip);
409
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
415
ret = initgnutls (&es);
421
gnutls_transport_set_ptr (es.session,
422
(gnutls_transport_ptr_t) tcp_sd);
425
fprintf(stderr, "Establishing TLS session with %s\n", ip);
428
ret = gnutls_handshake (es.session);
430
if (ret != GNUTLS_E_SUCCESS){
431
fprintf(stderr, "\n*** Handshake failed ***\n");
437
//Retrieve OpenPGP packet that contains the wanted password
440
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
445
if (buffer_length + BUFFER_SIZE > buffer_capacity){
446
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
451
buffer_capacity += BUFFER_SIZE;
454
ret = gnutls_record_recv
455
(es.session, buffer+buffer_length, BUFFER_SIZE);
750
fprintf_plus(stderr, "Bad address: %s\n", ip);
755
((struct sockaddr_in6 *)&to)->sin6_port = htons(port);
756
if(IN6_IS_ADDR_LINKLOCAL
757
(&((struct sockaddr_in6 *)&to)->sin6_addr)){
758
if(if_index == AVAHI_IF_UNSPEC){
759
fprintf_plus(stderr, "An IPv6 link-local address is"
760
" incomplete without a network interface\n");
764
/* Set the network interface number as scope */
765
((struct sockaddr_in6 *)&to)->sin6_scope_id = (uint32_t)if_index;
768
((struct sockaddr_in *)&to)->sin_port = htons(port);
777
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
778
char interface[IF_NAMESIZE];
779
if(if_indextoname((unsigned int)if_index, interface) == NULL){
780
perror_plus("if_indextoname");
782
fprintf_plus(stderr, "Connection to: %s%%%s, port %" PRIuMAX
783
"\n", ip, interface, (uintmax_t)port);
786
fprintf_plus(stderr, "Connection to: %s, port %" PRIuMAX "\n",
787
ip, (uintmax_t)port);
789
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
790
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
792
ret = getnameinfo((struct sockaddr *)&to,
793
sizeof(struct sockaddr_in6),
794
addrstr, sizeof(addrstr), NULL, 0,
797
ret = getnameinfo((struct sockaddr *)&to,
798
sizeof(struct sockaddr_in),
799
addrstr, sizeof(addrstr), NULL, 0,
802
if(ret == EAI_SYSTEM){
803
perror_plus("getnameinfo");
804
} else if(ret != 0) {
805
fprintf_plus(stderr, "getnameinfo: %s", gai_strerror(ret));
806
} else if(strcmp(addrstr, ip) != 0){
807
fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
817
ret = connect(tcp_sd, (struct sockaddr *)&to,
818
sizeof(struct sockaddr_in6));
820
ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
821
sizeof(struct sockaddr_in));
824
if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
826
perror_plus("connect");
837
const char *out = mandos_protocol_version;
840
size_t out_size = strlen(out);
841
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
842
out_size - written));
845
perror_plus("write");
849
written += (size_t)ret;
850
if(written < out_size){
853
if(out == mandos_protocol_version){
868
fprintf_plus(stderr, "Establishing TLS session with %s\n", ip);
876
/* This casting via intptr_t is to eliminate warning about casting
877
an int to a pointer type. This is exactly how the GnuTLS Guile
878
function "set-session-transport-fd!" does it. */
879
gnutls_transport_set_ptr(session,
880
(gnutls_transport_ptr_t)(intptr_t)tcp_sd);
888
ret = gnutls_handshake(session);
893
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
895
if(ret != GNUTLS_E_SUCCESS){
897
fprintf_plus(stderr, "*** GnuTLS Handshake failed ***\n");
904
/* Read OpenPGP packet that contains the wanted password */
907
fprintf_plus(stderr, "Retrieving OpenPGP encrypted password from"
918
buffer_capacity = incbuffer(&buffer, buffer_length,
920
if(buffer_capacity == 0){
922
perror_plus("incbuffer");
932
sret = gnutls_record_recv(session, buffer+buffer_length,
461
939
case GNUTLS_E_INTERRUPTED:
462
940
case GNUTLS_E_AGAIN:
464
942
case GNUTLS_E_REHANDSHAKE:
465
ret = gnutls_handshake (es.session);
467
fprintf(stderr, "\n*** Handshake failed ***\n");
944
ret = gnutls_handshake(session);
950
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
952
fprintf_plus(stderr, "*** GnuTLS Re-handshake failed "
474
fprintf(stderr, "Unknown error while reading data from"
475
" encrypted session with mandos server\n");
477
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
960
fprintf_plus(stderr, "Unknown error while reading data from"
961
" encrypted session with Mandos server\n");
962
gnutls_bye(session, GNUTLS_SHUT_RDWR);
481
buffer_length += (size_t) ret;
485
if (buffer_length > 0){
486
decrypted_buffer_size = pgp_packet_decrypt(buffer,
490
if (decrypted_buffer_size >= 0){
491
while(decrypted_buffer_size > 0){
492
ret = fwrite (decrypted_buffer, 1, (size_t)decrypted_buffer_size,
967
buffer_length += (size_t) sret;
972
fprintf_plus(stderr, "Closing TLS session\n");
981
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
986
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
988
if(buffer_length > 0){
989
ssize_t decrypted_buffer_size;
990
decrypted_buffer_size = pgp_packet_decrypt(buffer, buffer_length,
991
&decrypted_buffer, mc);
992
if(decrypted_buffer_size >= 0){
995
while(written < (size_t) decrypted_buffer_size){
1001
ret = (int)fwrite(decrypted_buffer + written, 1,
1002
(size_t)decrypted_buffer_size - written,
494
1004
if(ret == 0 and ferror(stdout)){
496
fprintf(stderr, "Error writing encrypted data: %s\n",
1007
fprintf_plus(stderr, "Error writing encrypted data: %s\n",
502
decrypted_buffer += ret;
503
decrypted_buffer_size -= ret;
505
free(decrypted_buffer);
1013
written += (size_t)ret;
1019
/* Shutdown procedure */
1024
free(decrypted_buffer);
1027
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
1033
perror_plus("close");
1035
gnutls_deinit(session);
514
fprintf(stderr, "Closing TLS session\n");
518
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
521
gnutls_deinit (es.session);
522
gnutls_certificate_free_credentials (es.cred);
523
gnutls_global_deinit ();
527
static AvahiSimplePoll *simple_poll = NULL;
528
static AvahiServer *server = NULL;
530
static void resolve_callback(
531
AvahiSServiceResolver *r,
532
AVAHI_GCC_UNUSED AvahiIfIndex interface,
533
AVAHI_GCC_UNUSED AvahiProtocol protocol,
534
AvahiResolverEvent event,
538
const char *host_name,
539
const AvahiAddress *address,
541
AVAHI_GCC_UNUSED AvahiStringList *txt,
542
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
543
AVAHI_GCC_UNUSED void* userdata) {
1045
__attribute__((nonnull))
1046
static void resolve_callback(AvahiSServiceResolver *r,
1047
AvahiIfIndex interface,
1048
AvahiProtocol proto,
1049
AvahiResolverEvent event,
1053
const char *host_name,
1054
const AvahiAddress *address,
1056
AVAHI_GCC_UNUSED AvahiStringList *txt,
1057
AVAHI_GCC_UNUSED AvahiLookupResultFlags
547
1064
/* Called whenever a service has been resolved successfully or
552
1073
case AVAHI_RESOLVER_FAILURE:
553
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
554
" type '%s' in domain '%s': %s\n", name, type, domain,
555
avahi_strerror(avahi_server_errno(server)));
1074
fprintf_plus(stderr, "(Avahi Resolver) Failed to resolve service "
1075
"'%s' of type '%s' in domain '%s': %s\n", name, type,
1077
avahi_strerror(avahi_server_errno
1078
(((mandos_context*)mc)->server)));
558
1081
case AVAHI_RESOLVER_FOUND:
560
1083
char ip[AVAHI_ADDRESS_STR_MAX];
561
1084
avahi_address_snprint(ip, sizeof(ip), address);
563
fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
564
host_name, ip, port);
1086
fprintf_plus(stderr, "Mandos server \"%s\" found on %s (%s, %"
1087
PRIdMAX ") on port %" PRIu16 "\n", name,
1088
host_name, ip, (intmax_t)interface, port);
566
int ret = start_mandos_communication(ip, port,
1090
int ret = start_mandos_communication(ip, (in_port_t)port,
1092
avahi_proto_to_af(proto),
1095
avahi_simple_poll_quit(simple_poll);
1097
if(not add_server(ip, (in_port_t)port, interface,
1098
avahi_proto_to_af(proto),
1099
&((mandos_context*)mc)->current_server)){
1100
fprintf_plus(stderr, "Failed to add server \"%s\" to server"
576
1106
avahi_s_service_resolver_free(r);
579
static void browse_callback(
580
AvahiSServiceBrowser *b,
581
AvahiIfIndex interface,
582
AvahiProtocol protocol,
583
AvahiBrowserEvent event,
587
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
590
AvahiServer *s = userdata;
593
/* Called whenever a new services becomes available on the LAN or
594
is removed from the LAN */
1109
static void browse_callback(AvahiSServiceBrowser *b,
1110
AvahiIfIndex interface,
1111
AvahiProtocol protocol,
1112
AvahiBrowserEvent event,
1116
AVAHI_GCC_UNUSED AvahiLookupResultFlags
1123
/* Called whenever a new services becomes available on the LAN or
1124
is removed from the LAN */
1132
case AVAHI_BROWSER_FAILURE:
1134
fprintf_plus(stderr, "(Avahi browser) %s\n",
1135
avahi_strerror(avahi_server_errno
1136
(((mandos_context*)mc)->server)));
1137
avahi_simple_poll_quit(simple_poll);
1140
case AVAHI_BROWSER_NEW:
1141
/* We ignore the returned Avahi resolver object. In the callback
1142
function we free it. If the Avahi server is terminated before
1143
the callback function is called the Avahi server will free the
1146
if(avahi_s_service_resolver_new(((mandos_context*)mc)->server,
1147
interface, protocol, name, type,
1148
domain, protocol, 0,
1149
resolve_callback, mc) == NULL)
1150
fprintf_plus(stderr, "Avahi: Failed to resolve service '%s':"
1152
avahi_strerror(avahi_server_errno
1153
(((mandos_context*)mc)->server)));
1156
case AVAHI_BROWSER_REMOVE:
1159
case AVAHI_BROWSER_ALL_FOR_NOW:
1160
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1162
fprintf_plus(stderr, "No Mandos server found, still"
1169
/* Signal handler that stops main loop after SIGTERM */
1170
static void handle_sigterm(int sig){
1175
signal_received = sig;
1176
int old_errno = errno;
1177
/* set main loop to exit */
1178
if(simple_poll != NULL){
1179
avahi_simple_poll_quit(simple_poll);
1184
__attribute__((nonnull, warn_unused_result))
1185
bool get_flags(const char *ifname, struct ifreq *ifr){
1189
int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1192
perror_plus("socket");
1196
strcpy(ifr->ifr_name, ifname);
1197
ret = ioctl(s, SIOCGIFFLAGS, ifr);
1201
perror_plus("ioctl SIOCGIFFLAGS");
1209
__attribute__((nonnull, warn_unused_result))
1210
bool good_flags(const char *ifname, const struct ifreq *ifr){
1212
/* Reject the loopback device */
1213
if(ifr->ifr_flags & IFF_LOOPBACK){
1215
fprintf_plus(stderr, "Rejecting loopback interface \"%s\"\n",
1220
/* Accept point-to-point devices only if connect_to is specified */
1221
if(connect_to != NULL and (ifr->ifr_flags & IFF_POINTOPOINT)){
1223
fprintf_plus(stderr, "Accepting point-to-point interface"
1224
" \"%s\"\n", ifname);
1228
/* Otherwise, reject non-broadcast-capable devices */
1229
if(not (ifr->ifr_flags & IFF_BROADCAST)){
1231
fprintf_plus(stderr, "Rejecting non-broadcast interface"
1232
" \"%s\"\n", ifname);
1236
/* Reject non-ARP interfaces (including dummy interfaces) */
1237
if(ifr->ifr_flags & IFF_NOARP){
1239
fprintf_plus(stderr, "Rejecting non-ARP interface \"%s\"\n",
1245
/* Accept this device */
1247
fprintf_plus(stderr, "Interface \"%s\" is good\n", ifname);
1253
* This function determines if a directory entry in /sys/class/net
1254
* corresponds to an acceptable network device.
1255
* (This function is passed to scandir(3) as a filter function.)
1257
__attribute__((nonnull, warn_unused_result))
1258
int good_interface(const struct dirent *if_entry){
1259
if(if_entry->d_name[0] == '.'){
1264
if(not get_flags(if_entry->d_name, &ifr)){
1266
fprintf_plus(stderr, "Failed to get flags for interface "
1267
"\"%s\"\n", if_entry->d_name);
1272
if(not good_flags(if_entry->d_name, &ifr)){
1279
* This function determines if a network interface is up.
1281
__attribute__((nonnull, warn_unused_result))
1282
bool interface_is_up(const char *interface){
1284
if(not get_flags(interface, &ifr)){
1286
fprintf_plus(stderr, "Failed to get flags for interface "
1287
"\"%s\"\n", interface);
1292
return (bool)(ifr.ifr_flags & IFF_UP);
1296
* This function determines if a network interface is running
1298
__attribute__((nonnull, warn_unused_result))
1299
bool interface_is_running(const char *interface){
1301
if(not get_flags(interface, &ifr)){
1303
fprintf_plus(stderr, "Failed to get flags for interface "
1304
"\"%s\"\n", interface);
1309
return (bool)(ifr.ifr_flags & IFF_RUNNING);
1312
__attribute__((nonnull, pure, warn_unused_result))
1313
int notdotentries(const struct dirent *direntry){
1314
/* Skip "." and ".." */
1315
if(direntry->d_name[0] == '.'
1316
and (direntry->d_name[1] == '\0'
1317
or (direntry->d_name[1] == '.'
1318
and direntry->d_name[2] == '\0'))){
1324
/* Is this directory entry a runnable program? */
1325
__attribute__((nonnull, warn_unused_result))
1326
int runnable_hook(const struct dirent *direntry){
1331
if((direntry->d_name)[0] == '\0'){
1336
sret = strspn(direntry->d_name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1337
"abcdefghijklmnopqrstuvwxyz"
1340
if((direntry->d_name)[sret] != '\0'){
1341
/* Contains non-allowed characters */
1343
fprintf_plus(stderr, "Ignoring hook \"%s\" with bad name\n",
1349
ret = fstatat(hookdir_fd, direntry->d_name, &st, 0);
1352
perror_plus("Could not stat hook");
1356
if(not (S_ISREG(st.st_mode))){
1357
/* Not a regular file */
1359
fprintf_plus(stderr, "Ignoring hook \"%s\" - not a file\n",
1364
if(not (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))){
1365
/* Not executable */
1367
fprintf_plus(stderr, "Ignoring hook \"%s\" - not executable\n",
1373
fprintf_plus(stderr, "Hook \"%s\" is acceptable\n",
1379
__attribute__((nonnull, warn_unused_result))
1380
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval,
1381
mandos_context *mc){
1383
struct timespec now;
1384
struct timespec waited_time;
1385
intmax_t block_time;
1388
if(mc->current_server == NULL){
1390
fprintf_plus(stderr, "Wait until first server is found."
1393
ret = avahi_simple_poll_iterate(s, -1);
1396
fprintf_plus(stderr, "Check current_server if we should run"
1399
/* the current time */
1400
ret = clock_gettime(CLOCK_MONOTONIC, &now);
1402
perror_plus("clock_gettime");
1405
/* Calculating in ms how long time between now and server
1406
who we visted longest time ago. Now - last seen. */
1407
waited_time.tv_sec = (now.tv_sec
1408
- mc->current_server->last_seen.tv_sec);
1409
waited_time.tv_nsec = (now.tv_nsec
1410
- mc->current_server->last_seen.tv_nsec);
1411
/* total time is 10s/10,000ms.
1412
Converting to s from ms by dividing by 1,000,
1413
and ns to ms by dividing by 1,000,000. */
1414
block_time = ((retry_interval
1415
- ((intmax_t)waited_time.tv_sec * 1000))
1416
- ((intmax_t)waited_time.tv_nsec / 1000000));
1419
fprintf_plus(stderr, "Blocking for %" PRIdMAX " ms\n",
1423
if(block_time <= 0){
1424
ret = start_mandos_communication(mc->current_server->ip,
1425
mc->current_server->port,
1426
mc->current_server->if_index,
1427
mc->current_server->af, mc);
1429
avahi_simple_poll_quit(s);
1432
ret = clock_gettime(CLOCK_MONOTONIC,
1433
&mc->current_server->last_seen);
1435
perror_plus("clock_gettime");
1438
mc->current_server = mc->current_server->next;
1439
block_time = 0; /* Call avahi to find new Mandos
1440
servers, but don't block */
1443
ret = avahi_simple_poll_iterate(s, (int)block_time);
1446
if(ret > 0 or errno != EINTR){
1447
return (ret != 1) ? ret : 0;
1453
/* Set effective uid to 0, return errno */
1454
__attribute__((warn_unused_result))
1455
error_t raise_privileges(void){
1456
error_t old_errno = errno;
1457
error_t ret_errno = 0;
1458
if(seteuid(0) == -1){
1460
perror_plus("seteuid");
1466
/* Set effective and real user ID to 0. Return errno. */
1467
__attribute__((warn_unused_result))
1468
error_t raise_privileges_permanently(void){
1469
error_t old_errno = errno;
1470
error_t ret_errno = raise_privileges();
1475
if(setuid(0) == -1){
1477
perror_plus("seteuid");
1483
/* Set effective user ID to unprivileged saved user ID */
1484
__attribute__((warn_unused_result))
1485
error_t lower_privileges(void){
1486
error_t old_errno = errno;
1487
error_t ret_errno = 0;
1488
if(seteuid(uid) == -1){
1490
perror_plus("seteuid");
1496
/* Lower privileges permanently */
1497
__attribute__((warn_unused_result))
1498
error_t lower_privileges_permanently(void){
1499
error_t old_errno = errno;
1500
error_t ret_errno = 0;
1501
if(setuid(uid) == -1){
1503
perror_plus("setuid");
1511
* Based on the example in the GNU LibC manual chapter 13.13 "File
1512
* Descriptor Flags".
1513
| [[info:libc:Descriptor%20Flags][File Descriptor Flags]] |
1515
__attribute__((warn_unused_result))
1516
static int set_cloexec_flag(int fd){
1517
int ret = (int)TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0));
1518
/* If reading the flags failed, return error indication now. */
1522
/* Store modified flag word in the descriptor. */
1523
return (int)TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD,
1526
#endif /* not O_CLOEXEC */
1528
__attribute__((nonnull))
1529
void run_network_hooks(const char *mode, const char *interface,
1531
struct dirent **direntries;
1532
if(hookdir_fd == -1){
1533
hookdir_fd = open(hookdir, O_RDONLY |
1536
#else /* not O_CLOEXEC */
1538
#endif /* not O_CLOEXEC */
1540
if(hookdir_fd == -1){
1541
if(errno == ENOENT){
1543
fprintf_plus(stderr, "Network hook directory \"%s\" not"
1544
" found\n", hookdir);
1547
perror_plus("open");
1552
if(set_cloexec_flag(hookdir_fd) < 0){
1553
perror_plus("set_cloexec_flag");
1554
if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
1555
perror_plus("close");
1561
#endif /* not O_CLOEXEC */
1564
#if __GLIBC_PREREQ(2, 15)
1565
int numhooks = scandirat(hookdir_fd, ".", &direntries,
1566
runnable_hook, alphasort);
1567
#else /* not __GLIBC_PREREQ(2, 15) */
1568
int numhooks = scandir(hookdir, &direntries, runnable_hook,
1570
#endif /* not __GLIBC_PREREQ(2, 15) */
1571
#else /* not __GLIBC__ */
1572
int numhooks = scandir(hookdir, &direntries, runnable_hook,
1574
#endif /* not __GLIBC__ */
1576
perror_plus("scandir");
1579
struct dirent *direntry;
1581
int devnull = open("/dev/null", O_RDONLY);
1582
for(int i = 0; i < numhooks; i++){
1583
direntry = direntries[i];
1585
fprintf_plus(stderr, "Running network hook \"%s\"\n",
1588
pid_t hook_pid = fork();
1591
/* Raise privileges */
1592
if(raise_privileges_permanently() != 0){
1593
perror_plus("Failed to raise privileges");
1600
perror_plus("setgid");
1603
/* Reset supplementary groups */
1605
ret = setgroups(0, NULL);
1607
perror_plus("setgroups");
1610
ret = dup2(devnull, STDIN_FILENO);
1612
perror_plus("dup2(devnull, STDIN_FILENO)");
1615
ret = close(devnull);
1617
perror_plus("close");
1620
ret = dup2(STDERR_FILENO, STDOUT_FILENO);
1622
perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
1625
ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
1627
perror_plus("setenv");
1630
ret = setenv("DEVICE", interface, 1);
1632
perror_plus("setenv");
1635
ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
1637
perror_plus("setenv");
1640
ret = setenv("MODE", mode, 1);
1642
perror_plus("setenv");
1646
ret = asprintf(&delaystring, "%f", (double)delay);
1648
perror_plus("asprintf");
1651
ret = setenv("DELAY", delaystring, 1);
1654
perror_plus("setenv");
1658
if(connect_to != NULL){
1659
ret = setenv("CONNECT", connect_to, 1);
1661
perror_plus("setenv");
1665
if(fexecve(hookdir_fd, (char *const [])
1666
{ direntry->d_name, NULL }, environ) == -1){
1667
perror_plus("fexecve");
1668
_exit(EXIT_FAILURE);
1672
if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1673
perror_plus("waitpid");
1676
if(WIFEXITED(status)){
1677
if(WEXITSTATUS(status) != 0){
1678
fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1679
" with status %d\n", direntry->d_name,
1680
WEXITSTATUS(status));
1683
} else if(WIFSIGNALED(status)){
1684
fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1685
" signal %d\n", direntry->d_name,
1689
fprintf_plus(stderr, "Warning: network hook \"%s\""
1690
" crashed\n", direntry->d_name);
1695
fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1699
if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
1700
perror_plus("close");
1707
__attribute__((nonnull, warn_unused_result))
1708
error_t bring_up_interface(const char *const interface,
1710
error_t old_errno = errno;
1712
struct ifreq network;
1713
unsigned int if_index = if_nametoindex(interface);
1715
fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
1725
if(not interface_is_up(interface)){
1726
error_t ret_errno = 0, ioctl_errno = 0;
1727
if(not get_flags(interface, &network)){
1729
fprintf_plus(stderr, "Failed to get flags for interface "
1730
"\"%s\"\n", interface);
1734
network.ifr_flags |= IFF_UP; /* set flag */
1736
int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1739
perror_plus("socket");
1745
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1747
perror_plus("close");
1754
fprintf_plus(stderr, "Bringing up interface \"%s\"\n",
1758
/* Raise privileges */
1759
ret_errno = raise_privileges();
1761
perror_plus("Failed to raise privileges");
1766
bool restore_loglevel = false;
1768
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1769
messages about the network interface to mess up the prompt */
1770
ret_linux = klogctl(8, NULL, 5);
1771
if(ret_linux == -1){
1772
perror_plus("klogctl");
1774
restore_loglevel = true;
1777
#endif /* __linux__ */
1778
int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
1779
ioctl_errno = errno;
1781
if(restore_loglevel){
1782
ret_linux = klogctl(7, NULL, 0);
1783
if(ret_linux == -1){
1784
perror_plus("klogctl");
1787
#endif /* __linux__ */
1789
/* If raise_privileges() succeeded above */
1791
/* Lower privileges */
1792
ret_errno = lower_privileges();
1795
perror_plus("Failed to lower privileges");
1799
/* Close the socket */
1800
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1802
perror_plus("close");
1805
if(ret_setflags == -1){
1806
errno = ioctl_errno;
1807
perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1812
fprintf_plus(stderr, "Interface \"%s\" is already up; good\n",
1816
/* Sleep checking until interface is running.
1817
Check every 0.25s, up to total time of delay */
1818
for(int i=0; i < delay * 4; i++){
1819
if(interface_is_running(interface)){
1822
struct timespec sleeptime = { .tv_nsec = 250000000 };
1823
ret = nanosleep(&sleeptime, NULL);
1824
if(ret == -1 and errno != EINTR){
1825
perror_plus("nanosleep");
1833
__attribute__((nonnull, warn_unused_result))
1834
error_t take_down_interface(const char *const interface){
1835
error_t old_errno = errno;
1836
struct ifreq network;
1837
unsigned int if_index = if_nametoindex(interface);
1839
fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
1843
if(interface_is_up(interface)){
1844
error_t ret_errno = 0, ioctl_errno = 0;
1845
if(not get_flags(interface, &network) and debug){
1847
fprintf_plus(stderr, "Failed to get flags for interface "
1848
"\"%s\"\n", interface);
1852
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1854
int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1857
perror_plus("socket");
1863
fprintf_plus(stderr, "Taking down interface \"%s\"\n",
1867
/* Raise privileges */
1868
ret_errno = raise_privileges();
1870
perror_plus("Failed to raise privileges");
1873
int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network);
1874
ioctl_errno = errno;
1876
/* If raise_privileges() succeeded above */
1878
/* Lower privileges */
1879
ret_errno = lower_privileges();
1882
perror_plus("Failed to lower privileges");
1886
/* Close the socket */
1887
int ret = (int)TEMP_FAILURE_RETRY(close(sd));
1889
perror_plus("close");
1892
if(ret_setflags == -1){
1893
errno = ioctl_errno;
1894
perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
1899
fprintf_plus(stderr, "Interface \"%s\" is already down; odd\n",
1907
int main(int argc, char *argv[]){
1908
mandos_context mc = { .server = NULL, .dh_bits = 1024,
1909
.priority = "SECURE256:!CTYPE-X.509:"
1910
"+CTYPE-OPENPGP", .current_server = NULL,
1911
.interfaces = NULL, .interfaces_size = 0 };
1912
AvahiSServiceBrowser *sb = NULL;
1917
int exitcode = EXIT_SUCCESS;
1918
char *interfaces_to_take_down = NULL;
1919
size_t interfaces_to_take_down_size = 0;
1920
char run_tempdir[] = "/run/tmp/mandosXXXXXX";
1921
char old_tempdir[] = "/tmp/mandosXXXXXX";
1922
char *tempdir = NULL;
1923
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1924
const char *seckey = PATHDIR "/" SECKEY;
1925
const char *pubkey = PATHDIR "/" PUBKEY;
1926
char *interfaces_hooks = NULL;
1928
bool gnutls_initialized = false;
1929
bool gpgme_initialized = false;
1931
double retry_interval = 10; /* 10s between trying a server and
1932
retrying the same server again */
1934
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1935
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1940
/* Lower any group privileges we might have, just to be safe */
1944
perror_plus("setgid");
1947
/* Lower user privileges (temporarily) */
1951
perror_plus("seteuid");
1959
struct argp_option options[] = {
1960
{ .name = "debug", .key = 128,
1961
.doc = "Debug mode", .group = 3 },
1962
{ .name = "connect", .key = 'c',
1963
.arg = "ADDRESS:PORT",
1964
.doc = "Connect directly to a specific Mandos server",
1966
{ .name = "interface", .key = 'i',
1968
.doc = "Network interface that will be used to search for"
1971
{ .name = "seckey", .key = 's',
1973
.doc = "OpenPGP secret key file base name",
1975
{ .name = "pubkey", .key = 'p',
1977
.doc = "OpenPGP public key file base name",
1979
{ .name = "dh-bits", .key = 129,
1981
.doc = "Bit length of the prime number used in the"
1982
" Diffie-Hellman key exchange",
1984
{ .name = "priority", .key = 130,
1986
.doc = "GnuTLS priority string for the TLS handshake",
1988
{ .name = "delay", .key = 131,
1990
.doc = "Maximum delay to wait for interface startup",
1992
{ .name = "retry", .key = 132,
1994
.doc = "Retry interval used when denied by the Mandos server",
1996
{ .name = "network-hook-dir", .key = 133,
1998
.doc = "Directory where network hooks are located",
2001
* These reproduce what we would get without ARGP_NO_HELP
2003
{ .name = "help", .key = '?',
2004
.doc = "Give this help list", .group = -1 },
2005
{ .name = "usage", .key = -3,
2006
.doc = "Give a short usage message", .group = -1 },
2007
{ .name = "version", .key = 'V',
2008
.doc = "Print program version", .group = -1 },
2012
error_t parse_opt(int key, char *arg,
2013
struct argp_state *state){
2016
case 128: /* --debug */
2019
case 'c': /* --connect */
2022
case 'i': /* --interface */
2023
ret_errno = argz_add_sep(&mc.interfaces, &mc.interfaces_size,
2026
argp_error(state, "%s", strerror(ret_errno));
2029
case 's': /* --seckey */
2032
case 'p': /* --pubkey */
2035
case 129: /* --dh-bits */
2037
tmpmax = strtoimax(arg, &tmp, 10);
2038
if(errno != 0 or tmp == arg or *tmp != '\0'
2039
or tmpmax != (typeof(mc.dh_bits))tmpmax){
2040
argp_error(state, "Bad number of DH bits");
2042
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
2044
case 130: /* --priority */
2047
case 131: /* --delay */
2049
delay = strtof(arg, &tmp);
2050
if(errno != 0 or tmp == arg or *tmp != '\0'){
2051
argp_error(state, "Bad delay");
2053
case 132: /* --retry */
2055
retry_interval = strtod(arg, &tmp);
2056
if(errno != 0 or tmp == arg or *tmp != '\0'
2057
or (retry_interval * 1000) > INT_MAX
2058
or retry_interval < 0){
2059
argp_error(state, "Bad retry interval");
2062
case 133: /* --network-hook-dir */
2066
* These reproduce what we would get without ARGP_NO_HELP
2068
case '?': /* --help */
2069
argp_state_help(state, state->out_stream,
2070
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
2071
& ~(unsigned int)ARGP_HELP_EXIT_OK);
2072
case -3: /* --usage */
2073
argp_state_help(state, state->out_stream,
2074
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
2075
case 'V': /* --version */
2076
fprintf_plus(state->out_stream, "%s\n", argp_program_version);
2077
exit(argp_err_exit_status);
2080
return ARGP_ERR_UNKNOWN;
2085
struct argp argp = { .options = options, .parser = parse_opt,
2087
.doc = "Mandos client -- Get and decrypt"
2088
" passwords from a Mandos server" };
2089
ret = argp_parse(&argp, argc, argv,
2090
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
598
case AVAHI_BROWSER_FAILURE:
600
fprintf(stderr, "(Browser) %s\n",
601
avahi_strerror(avahi_server_errno(server)));
602
avahi_simple_poll_quit(simple_poll);
605
case AVAHI_BROWSER_NEW:
606
/* We ignore the returned resolver object. In the callback
607
function we free it. If the server is terminated before
608
the callback function is called the server will free
609
the resolver for us. */
611
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
613
AVAHI_PROTO_INET6, 0,
614
resolve_callback, s)))
615
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
616
avahi_strerror(avahi_server_errno(s)));
619
case AVAHI_BROWSER_REMOVE:
622
case AVAHI_BROWSER_ALL_FOR_NOW:
623
case AVAHI_BROWSER_CACHE_EXHAUSTED:
628
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
2097
perror_plus("argp_parse");
2098
exitcode = EX_OSERR;
2101
exitcode = EX_USAGE;
2107
/* Work around Debian bug #633582:
2108
<http://bugs.debian.org/633582> */
2110
/* Re-raise privileges */
2111
ret_errno = raise_privileges();
2114
perror_plus("Failed to raise privileges");
2118
if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
2119
int seckey_fd = open(seckey, O_RDONLY);
2120
if(seckey_fd == -1){
2121
perror_plus("open");
2123
ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
2125
perror_plus("fstat");
2127
if(S_ISREG(st.st_mode)
2128
and st.st_uid == 0 and st.st_gid == 0){
2129
ret = fchown(seckey_fd, uid, gid);
2131
perror_plus("fchown");
2135
TEMP_FAILURE_RETRY(close(seckey_fd));
2139
if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){
2140
int pubkey_fd = open(pubkey, O_RDONLY);
2141
if(pubkey_fd == -1){
2142
perror_plus("open");
2144
ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
2146
perror_plus("fstat");
2148
if(S_ISREG(st.st_mode)
2149
and st.st_uid == 0 and st.st_gid == 0){
2150
ret = fchown(pubkey_fd, uid, gid);
2152
perror_plus("fchown");
2156
TEMP_FAILURE_RETRY(close(pubkey_fd));
2160
/* Lower privileges */
2161
ret_errno = lower_privileges();
2164
perror_plus("Failed to lower privileges");
2169
/* Remove invalid interface names (except "none") */
2171
char *interface = NULL;
2172
while((interface = argz_next(mc.interfaces, mc.interfaces_size,
2174
if(strcmp(interface, "none") != 0
2175
and if_nametoindex(interface) == 0){
2176
if(interface[0] != '\0'){
2177
fprintf_plus(stderr, "Not using nonexisting interface"
2178
" \"%s\"\n", interface);
2180
argz_delete(&mc.interfaces, &mc.interfaces_size, interface);
2186
/* Run network hooks */
2188
if(mc.interfaces != NULL){
2189
interfaces_hooks = malloc(mc.interfaces_size);
2190
if(interfaces_hooks == NULL){
2191
perror_plus("malloc");
2194
memcpy(interfaces_hooks, mc.interfaces, mc.interfaces_size);
2195
argz_stringify(interfaces_hooks, mc.interfaces_size, (int)',');
2197
run_network_hooks("start", interfaces_hooks != NULL ?
2198
interfaces_hooks : "", delay);
2202
avahi_set_log_function(empty_log);
2205
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
2206
from the signal handler */
2207
/* Initialize the pseudo-RNG for Avahi */
2208
srand((unsigned int) time(NULL));
2209
simple_poll = avahi_simple_poll_new();
2210
if(simple_poll == NULL){
2211
fprintf_plus(stderr,
2212
"Avahi: Failed to create simple poll object.\n");
2213
exitcode = EX_UNAVAILABLE;
2217
sigemptyset(&sigterm_action.sa_mask);
2218
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
2220
perror_plus("sigaddset");
2221
exitcode = EX_OSERR;
2224
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
2226
perror_plus("sigaddset");
2227
exitcode = EX_OSERR;
2230
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
2232
perror_plus("sigaddset");
2233
exitcode = EX_OSERR;
2236
/* Need to check if the handler is SIG_IGN before handling:
2237
| [[info:libc:Initial Signal Actions]] |
2238
| [[info:libc:Basic Signal Handling]] |
2240
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
2242
perror_plus("sigaction");
2245
if(old_sigterm_action.sa_handler != SIG_IGN){
2246
ret = sigaction(SIGINT, &sigterm_action, NULL);
2248
perror_plus("sigaction");
2249
exitcode = EX_OSERR;
2253
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
2255
perror_plus("sigaction");
2258
if(old_sigterm_action.sa_handler != SIG_IGN){
2259
ret = sigaction(SIGHUP, &sigterm_action, NULL);
2261
perror_plus("sigaction");
2262
exitcode = EX_OSERR;
2266
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
2268
perror_plus("sigaction");
2271
if(old_sigterm_action.sa_handler != SIG_IGN){
2272
ret = sigaction(SIGTERM, &sigterm_action, NULL);
2274
perror_plus("sigaction");
2275
exitcode = EX_OSERR;
2280
/* If no interfaces were specified, make a list */
2281
if(mc.interfaces == NULL){
2282
struct dirent **direntries;
2283
/* Look for any good interfaces */
2284
ret = scandir(sys_class_net, &direntries, good_interface,
2287
/* Add all found interfaces to interfaces list */
2288
for(int i = 0; i < ret; ++i){
2289
ret_errno = argz_add(&mc.interfaces, &mc.interfaces_size,
2290
direntries[i]->d_name);
2293
perror_plus("argz_add");
2297
fprintf_plus(stderr, "Will use interface \"%s\"\n",
2298
direntries[i]->d_name);
2304
fprintf_plus(stderr, "Could not find a network interface\n");
2305
exitcode = EXIT_FAILURE;
2310
/* Bring up interfaces which are down, and remove any "none"s */
2312
char *interface = NULL;
2313
while((interface = argz_next(mc.interfaces, mc.interfaces_size,
2315
/* If interface name is "none", stop bringing up interfaces.
2316
Also remove all instances of "none" from the list */
2317
if(strcmp(interface, "none") == 0){
2318
argz_delete(&mc.interfaces, &mc.interfaces_size,
2321
while((interface = argz_next(mc.interfaces,
2322
mc.interfaces_size, interface))){
2323
if(strcmp(interface, "none") == 0){
2324
argz_delete(&mc.interfaces, &mc.interfaces_size,
2331
bool interface_was_up = interface_is_up(interface);
2332
errno = bring_up_interface(interface, delay);
2333
if(not interface_was_up){
2335
perror_plus("Failed to bring up interface");
2337
errno = argz_add(&interfaces_to_take_down,
2338
&interfaces_to_take_down_size,
2341
perror_plus("argz_add");
2346
if(debug and (interfaces_to_take_down == NULL)){
2347
fprintf_plus(stderr, "No interfaces were brought up\n");
2351
/* If we only got one interface, explicitly use only that one */
2352
if(argz_count(mc.interfaces, mc.interfaces_size) == 1){
2354
fprintf_plus(stderr, "Using only interface \"%s\"\n",
2357
if_index = (AvahiIfIndex)if_nametoindex(mc.interfaces);
2364
ret = init_gnutls_global(pubkey, seckey, &mc);
2366
fprintf_plus(stderr, "init_gnutls_global failed\n");
2367
exitcode = EX_UNAVAILABLE;
2370
gnutls_initialized = true;
2377
/* Try /run/tmp before /tmp */
2378
tempdir = mkdtemp(run_tempdir);
2379
if(tempdir == NULL and errno == ENOENT){
2381
fprintf_plus(stderr, "Tempdir %s did not work, trying %s\n",
2382
run_tempdir, old_tempdir);
2384
tempdir = mkdtemp(old_tempdir);
2386
if(tempdir == NULL){
2387
perror_plus("mkdtemp");
2395
if(not init_gpgme(pubkey, seckey, tempdir, &mc)){
2396
fprintf_plus(stderr, "init_gpgme failed\n");
2397
exitcode = EX_UNAVAILABLE;
2400
gpgme_initialized = true;
2407
if(connect_to != NULL){
2408
/* Connect directly, do not use Zeroconf */
2409
/* (Mainly meant for debugging) */
2410
char *address = strrchr(connect_to, ':');
2412
if(address == NULL){
2413
fprintf_plus(stderr, "No colon in address\n");
2414
exitcode = EX_USAGE;
2424
tmpmax = strtoimax(address+1, &tmp, 10);
2425
if(errno != 0 or tmp == address+1 or *tmp != '\0'
2426
or tmpmax != (in_port_t)tmpmax){
2427
fprintf_plus(stderr, "Bad port number\n");
2428
exitcode = EX_USAGE;
2436
port = (in_port_t)tmpmax;
2438
/* Colon in address indicates IPv6 */
2440
if(strchr(connect_to, ':') != NULL){
2442
/* Accept [] around IPv6 address - see RFC 5952 */
2443
if(connect_to[0] == '[' and address[-1] == ']')
2451
address = connect_to;
2457
while(not quit_now){
2458
ret = start_mandos_communication(address, port, if_index, af,
2460
if(quit_now or ret == 0){
2464
fprintf_plus(stderr, "Retrying in %d seconds\n",
2465
(int)retry_interval);
2467
sleep((unsigned int)retry_interval);
2471
exitcode = EXIT_SUCCESS;
629
2482
AvahiServerConfig config;
630
AvahiSServiceBrowser *sb = NULL;
633
int returncode = EXIT_SUCCESS;
634
const char *interface = "eth0";
637
static struct option long_options[] = {
638
{"debug", no_argument, (int *)&debug, 1},
639
{"interface", required_argument, 0, 'i'},
642
int option_index = 0;
643
ret = getopt_long (argc, argv, "i:", long_options,
662
avahi_set_log_function(empty_log);
665
/* Initialize the psuedo-RNG */
666
srand((unsigned int) time(NULL));
668
/* Allocate main loop object */
669
if (!(simple_poll = avahi_simple_poll_new())) {
670
fprintf(stderr, "Failed to create simple poll object.\n");
675
/* Do not publish any local records */
2483
/* Do not publish any local Zeroconf records */
676
2484
avahi_server_config_init(&config);
677
2485
config.publish_hinfo = 0;
678
2486
config.publish_addresses = 0;
679
2487
config.publish_workstation = 0;
680
2488
config.publish_domain = 0;
682
2490
/* Allocate a new server */
683
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
684
&config, NULL, NULL, &error);
686
/* Free the configuration data */
2491
mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
2492
&config, NULL, NULL, &ret_errno);
2494
/* Free the Avahi configuration data */
687
2495
avahi_server_config_free(&config);
689
/* Check if creating the server object succeeded */
691
fprintf(stderr, "Failed to create server: %s\n",
692
avahi_strerror(error));
693
returncode = EXIT_FAILURE;
697
/* Create the service browser */
698
sb = avahi_s_service_browser_new(server,
700
if_nametoindex(interface),
702
"_mandos._tcp", NULL, 0,
703
browse_callback, server);
705
fprintf(stderr, "Failed to create service browser: %s\n",
706
avahi_strerror(avahi_server_errno(server)));
707
returncode = EXIT_FAILURE;
711
/* Run the main loop */
714
fprintf(stderr, "Starting avahi loop search\n");
717
avahi_simple_poll_loop(simple_poll);
722
fprintf(stderr, "%s exiting\n", argv[0]);
727
avahi_s_service_browser_free(sb);
730
avahi_server_free(server);
733
avahi_simple_poll_free(simple_poll);
2498
/* Check if creating the Avahi server object succeeded */
2499
if(mc.server == NULL){
2500
fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
2501
avahi_strerror(ret_errno));
2502
exitcode = EX_UNAVAILABLE;
2510
/* Create the Avahi service browser */
2511
sb = avahi_s_service_browser_new(mc.server, if_index,
2512
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
2513
NULL, 0, browse_callback,
2516
fprintf_plus(stderr, "Failed to create service browser: %s\n",
2517
avahi_strerror(avahi_server_errno(mc.server)));
2518
exitcode = EX_UNAVAILABLE;
2526
/* Run the main loop */
2529
fprintf_plus(stderr, "Starting Avahi loop search\n");
2532
ret = avahi_loop_with_timeout(simple_poll,
2533
(int)(retry_interval * 1000), &mc);
2535
fprintf_plus(stderr, "avahi_loop_with_timeout exited %s\n",
2536
(ret == 0) ? "successfully" : "with error");
2542
fprintf_plus(stderr, "%s exiting\n", argv[0]);
2545
/* Cleanup things */
2546
free(mc.interfaces);
2549
avahi_s_service_browser_free(sb);
2551
if(mc.server != NULL)
2552
avahi_server_free(mc.server);
2554
if(simple_poll != NULL)
2555
avahi_simple_poll_free(simple_poll);
2557
if(gnutls_initialized){
2558
gnutls_certificate_free_credentials(mc.cred);
2559
gnutls_global_deinit();
2560
gnutls_dh_params_deinit(mc.dh_params);
2563
if(gpgme_initialized){
2564
gpgme_release(mc.ctx);
2567
/* Cleans up the circular linked list of Mandos servers the client
2569
if(mc.current_server != NULL){
2570
mc.current_server->prev->next = NULL;
2571
while(mc.current_server != NULL){
2572
server *next = mc.current_server->next;
2573
free(mc.current_server);
2574
mc.current_server = next;
2578
/* Re-raise privileges */
2580
ret_errno = raise_privileges();
2582
perror_plus("Failed to raise privileges");
2585
/* Run network hooks */
2586
run_network_hooks("stop", interfaces_hooks != NULL ?
2587
interfaces_hooks : "", delay);
2589
/* Take down the network interfaces which were brought up */
2591
char *interface = NULL;
2592
while((interface=argz_next(interfaces_to_take_down,
2593
interfaces_to_take_down_size,
2595
ret_errno = take_down_interface(interface);
2598
perror_plus("Failed to take down interface");
2601
if(debug and (interfaces_to_take_down == NULL)){
2602
fprintf_plus(stderr, "No interfaces needed to be taken"
2608
ret_errno = lower_privileges_permanently();
2610
perror_plus("Failed to lower privileges permanently");
2614
free(interfaces_to_take_down);
2615
free(interfaces_hooks);
2617
/* Removes the GPGME temp directory and all files inside */
2618
if(tempdir != NULL){
2619
struct dirent **direntries = NULL;
2620
struct dirent *direntry = NULL;
2621
int numentries = scandir(tempdir, &direntries, notdotentries,
2624
for(int i = 0; i < numentries; i++){
2625
direntry = direntries[i];
2626
char *fullname = NULL;
2627
ret = asprintf(&fullname, "%s/%s", tempdir,
2630
perror_plus("asprintf");
2633
ret = remove(fullname);
2635
fprintf_plus(stderr, "remove(\"%s\"): %s\n", fullname,
2642
/* need to clean even if 0 because man page doesn't specify */
2644
if(numentries == -1){
2645
perror_plus("scandir");
2647
ret = rmdir(tempdir);
2648
if(ret == -1 and errno != ENOENT){
2649
perror_plus("rmdir");
2654
sigemptyset(&old_sigterm_action.sa_mask);
2655
old_sigterm_action.sa_handler = SIG_DFL;
2656
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
2657
&old_sigterm_action,
2660
perror_plus("sigaction");
2663
ret = raise(signal_received);
2664
} while(ret != 0 and errno == EINTR);
2666
perror_plus("raise");
2669
TEMP_FAILURE_RETRY(pause());