46
100
#include <avahi-common/malloc.h>
47
101
#include <avahi-common/error.h>
50
#include <sys/types.h> /* socket(), inet_pton() */
51
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
52
struct in6_addr, inet_pton() */
53
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
54
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
56
#include <unistd.h> /* close() */
57
#include <netinet/in.h>
58
#include <stdbool.h> /* true */
59
#include <string.h> /* memset */
60
#include <arpa/inet.h> /* inet_pton() */
61
#include <iso646.h> /* not */
64
#include <errno.h> /* perror() */
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,
70
120
#define BUFFER_SIZE 256
73
const char *certdir = "/conf/conf.d/cryptkeyreq/";
74
const char *certfile = "openpgp-client.txt";
75
const char *certkey = "openpgp-client-key.txt";
122
#define PATHDIR "/conf/conf.d/mandos"
123
#define SECKEY "seckey.txt"
124
#define PUBKEY "pubkey.txt"
77
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
/* Doubly linked list that need to be circular linked when ever used */
134
typedef struct server{
137
AvahiIfIndex if_index;
139
struct timespec last_seen;
144
/* Used for passing in values through the Avahi callback functions */
80
gnutls_session_t session;
146
AvahiSimplePoll *simple_poll;
81
148
gnutls_certificate_credentials_t cred;
149
unsigned int dh_bits;
82
150
gnutls_dh_params_t dh_params;
86
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
87
char **new_packet, const char *homedir){
88
gpgme_data_t dh_crypto, dh_plain;
151
const char *priority;
153
server *current_server;
156
/* global context so signal handler can reach it*/
157
mandos_context mc = { .simple_poll = NULL, .server = NULL,
158
.dh_bits = 1024, .priority = "SECURE256"
159
":!CTYPE-X.509:+CTYPE-OPENPGP", .current_server = NULL };
161
sig_atomic_t quit_now = 0;
162
int signal_received = 0;
164
/* Function to use when printing errors */
165
void perror_plus(const char *print_text){
166
fprintf(stderr, "Mandos plugin %s: ", program_invocation_short_name);
171
* Make additional room in "buffer" for at least BUFFER_SIZE more
172
* bytes. "buffer_capacity" is how much is currently allocated,
173
* "buffer_length" is how much is already used.
175
size_t incbuffer(char **buffer, size_t buffer_length,
176
size_t buffer_capacity){
177
if(buffer_length + BUFFER_SIZE > buffer_capacity){
178
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
182
buffer_capacity += BUFFER_SIZE;
184
return buffer_capacity;
187
int add_server(const char *ip, uint16_t port,
188
AvahiIfIndex if_index,
191
server *new_server = malloc(sizeof(server));
192
if(new_server == NULL){
193
perror_plus("malloc");
196
*new_server = (server){ .ip = strdup(ip),
198
.if_index = if_index,
200
if(new_server->ip == NULL){
201
perror_plus("strdup");
204
/* uniqe case of first server */
205
if (mc.current_server == NULL){
206
new_server->next = new_server;
207
new_server->prev = new_server;
208
mc.current_server = new_server;
209
/* Placing the new server last in the list */
211
new_server->next = mc.current_server;
212
new_server->prev = mc.current_server->prev;
213
new_server->prev->next = new_server;
214
mc.current_server->prev = new_server;
216
ret = clock_gettime(CLOCK_MONOTONIC, &mc.current_server->last_seen);
218
perror_plus("clock_gettime");
227
static bool init_gpgme(const char *seckey,
228
const char *pubkey, const char *tempdir){
92
ssize_t new_packet_capacity = 0;
93
ssize_t new_packet_length = 0;
94
230
gpgme_engine_info_t engine_info;
97
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
234
* Helper function to insert pub and seckey to the engine keyring.
236
bool import_key(const char *filename){
239
gpgme_data_t pgp_data;
241
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
247
rc = gpgme_data_new_from_fd(&pgp_data, fd);
248
if(rc != GPG_ERR_NO_ERROR){
249
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
250
gpgme_strsource(rc), gpgme_strerror(rc));
254
rc = gpgme_op_import(mc.ctx, pgp_data);
255
if(rc != GPG_ERR_NO_ERROR){
256
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
257
gpgme_strsource(rc), gpgme_strerror(rc));
261
ret = (int)TEMP_FAILURE_RETRY(close(fd));
263
perror_plus("close");
265
gpgme_data_release(pgp_data);
270
fprintf(stderr, "Initializing GPGME\n");
101
274
gpgme_check_version(NULL);
102
275
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
103
if (rc != GPG_ERR_NO_ERROR){
276
if(rc != GPG_ERR_NO_ERROR){
104
277
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
105
278
gpgme_strsource(rc), gpgme_strerror(rc));
109
/* Set GPGME home directory */
110
rc = gpgme_get_engine_info (&engine_info);
111
if (rc != GPG_ERR_NO_ERROR){
282
/* Set GPGME home directory for the OpenPGP engine only */
283
rc = gpgme_get_engine_info(&engine_info);
284
if(rc != GPG_ERR_NO_ERROR){
112
285
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
113
286
gpgme_strsource(rc), gpgme_strerror(rc));
116
289
while(engine_info != NULL){
117
290
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
118
291
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
119
engine_info->file_name, homedir);
292
engine_info->file_name, tempdir);
122
295
engine_info = engine_info->next;
124
297
if(engine_info == NULL){
125
fprintf(stderr, "Could not set home dir to %s\n", homedir);
129
/* Create new GPGME data buffer from packet buffer */
130
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
131
if (rc != GPG_ERR_NO_ERROR){
298
fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
302
/* Create new GPGME "context" */
303
rc = gpgme_new(&(mc.ctx));
304
if(rc != GPG_ERR_NO_ERROR){
305
fprintf(stderr, "bad gpgme_new: %s: %s\n",
306
gpgme_strsource(rc), gpgme_strerror(rc));
310
if(not import_key(pubkey) or not import_key(seckey)){
318
* Decrypt OpenPGP data.
319
* Returns -1 on error
321
static ssize_t pgp_packet_decrypt(const char *cryptotext,
324
gpgme_data_t dh_crypto, dh_plain;
327
size_t plaintext_capacity = 0;
328
ssize_t plaintext_length = 0;
331
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
334
/* Create new GPGME data buffer from memory cryptotext */
335
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
337
if(rc != GPG_ERR_NO_ERROR){
132
338
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
133
339
gpgme_strsource(rc), gpgme_strerror(rc));
195
/* Delete the GPGME FILE pointer cryptotext data buffer */
196
gpgme_data_release(dh_crypto);
389
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
198
392
/* Seek back to the beginning of the GPGME plaintext data buffer */
199
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
200
perror("pgpme_data_seek");
393
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
394
perror_plus("gpgme_data_seek");
395
plaintext_length = -1;
205
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
206
*new_packet = realloc(*new_packet,
207
(unsigned int)new_packet_capacity
209
if (*new_packet == NULL){
213
new_packet_capacity += BUFFER_SIZE;
401
plaintext_capacity = incbuffer(plaintext,
402
(size_t)plaintext_length,
404
if(plaintext_capacity == 0){
405
perror_plus("incbuffer");
406
plaintext_length = -1;
216
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
410
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
218
412
/* Print the data, if any */
223
perror("gpgme_data_read");
226
new_packet_length += ret;
229
/* FIXME: check characters before printing to screen so to not print
230
terminal control characters */
232
/* fprintf(stderr, "decrypted password is: "); */
233
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
234
/* fprintf(stderr, "\n"); */
418
perror_plus("gpgme_data_read");
419
plaintext_length = -1;
422
plaintext_length += ret;
426
fprintf(stderr, "Decrypted password is: ");
427
for(ssize_t i = 0; i < plaintext_length; i++){
428
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
430
fprintf(stderr, "\n");
435
/* Delete the GPGME cryptotext data buffer */
436
gpgme_data_release(dh_crypto);
237
438
/* Delete the GPGME plaintext data buffer */
238
439
gpgme_data_release(dh_plain);
239
return new_packet_length;
440
return plaintext_length;
242
static const char * safer_gnutls_strerror (int value) {
243
const char *ret = gnutls_strerror (value);
443
static const char * safer_gnutls_strerror(int value){
444
const char *ret = gnutls_strerror(value); /* Spurious warning from
445
-Wunreachable-code */
245
447
ret = "(unknown)";
249
void debuggnutls(__attribute__((unused)) int level,
251
fprintf(stderr, "%s", string);
451
/* GnuTLS log function callback */
452
static void debuggnutls(__attribute__((unused)) int level,
454
fprintf(stderr, "GnuTLS: %s", string);
254
int initgnutls(encrypted_session *es){
457
static int init_gnutls_global(const char *pubkeyfilename,
458
const char *seckeyfilename){
259
462
fprintf(stderr, "Initializing GnuTLS\n");
262
if ((ret = gnutls_global_init ())
263
!= GNUTLS_E_SUCCESS) {
264
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
465
ret = gnutls_global_init();
466
if(ret != GNUTLS_E_SUCCESS){
467
fprintf(stderr, "GnuTLS global_init: %s\n",
468
safer_gnutls_strerror(ret));
473
/* "Use a log level over 10 to enable all debugging options."
269
476
gnutls_global_set_log_level(11);
270
477
gnutls_global_set_log_function(debuggnutls);
273
/* openpgp credentials */
274
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
275
!= GNUTLS_E_SUCCESS) {
276
fprintf (stderr, "memory error: %s\n",
277
safer_gnutls_strerror(ret));
480
/* OpenPGP credentials */
481
gnutls_certificate_allocate_credentials(&mc.cred);
482
if(ret != GNUTLS_E_SUCCESS){
483
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
487
safer_gnutls_strerror(ret));
488
gnutls_global_deinit();
282
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
283
" and keyfile %s as GnuTLS credentials\n", certfile,
493
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
494
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
287
498
ret = gnutls_certificate_set_openpgp_key_file
288
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
289
if (ret != GNUTLS_E_SUCCESS) {
291
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
293
ret, certfile, certkey);
294
fprintf(stdout, "The Error is: %s\n",
295
safer_gnutls_strerror(ret));
299
//GnuTLS server initialization
300
if ((ret = gnutls_dh_params_init (&es->dh_params))
301
!= GNUTLS_E_SUCCESS) {
302
fprintf (stderr, "Error in dh parameter initialization: %s\n",
303
safer_gnutls_strerror(ret));
307
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
308
!= GNUTLS_E_SUCCESS) {
309
fprintf (stderr, "Error in prime generation: %s\n",
310
safer_gnutls_strerror(ret));
314
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
316
// GnuTLS session creation
317
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
318
!= GNUTLS_E_SUCCESS){
499
(mc.cred, pubkeyfilename, seckeyfilename,
500
GNUTLS_OPENPGP_FMT_BASE64);
501
if(ret != GNUTLS_E_SUCCESS){
503
"Error[%d] while reading the OpenPGP key pair ('%s',"
504
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
505
fprintf(stderr, "The GnuTLS error is: %s\n",
506
safer_gnutls_strerror(ret));
510
/* GnuTLS server initialization */
511
ret = gnutls_dh_params_init(&mc.dh_params);
512
if(ret != GNUTLS_E_SUCCESS){
513
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
514
" %s\n", safer_gnutls_strerror(ret));
517
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
518
if(ret != GNUTLS_E_SUCCESS){
519
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
520
safer_gnutls_strerror(ret));
524
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
530
gnutls_certificate_free_credentials(mc.cred);
531
gnutls_global_deinit();
532
gnutls_dh_params_deinit(mc.dh_params);
536
static int init_gnutls_session(gnutls_session_t *session){
538
/* GnuTLS session creation */
540
ret = gnutls_init(session, GNUTLS_SERVER);
544
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
545
if(ret != GNUTLS_E_SUCCESS){
319
546
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
320
547
safer_gnutls_strerror(ret));
323
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
324
!= GNUTLS_E_SUCCESS) {
325
fprintf(stderr, "Syntax error at: %s\n", err);
326
fprintf(stderr, "GnuTLS error: %s\n",
327
safer_gnutls_strerror(ret));
553
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
555
gnutls_deinit(*session);
558
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
559
if(ret != GNUTLS_E_SUCCESS){
560
fprintf(stderr, "Syntax error at: %s\n", err);
561
fprintf(stderr, "GnuTLS error: %s\n",
562
safer_gnutls_strerror(ret));
563
gnutls_deinit(*session);
331
if ((ret = gnutls_credentials_set
332
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
333
!= GNUTLS_E_SUCCESS) {
334
fprintf(stderr, "Error setting a credentials set: %s\n",
569
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
572
gnutls_deinit(*session);
575
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
576
if(ret != GNUTLS_E_SUCCESS){
577
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
335
578
safer_gnutls_strerror(ret));
579
gnutls_deinit(*session);
339
583
/* ignore client certificate if any. */
340
gnutls_certificate_server_set_request (es->session,
584
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
343
gnutls_dh_set_prime_bits (es->session, DH_BITS);
586
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
348
void empty_log(__attribute__((unused)) AvahiLogLevel level,
349
__attribute__((unused)) const char *txt){}
591
/* Avahi log function callback */
592
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
593
__attribute__((unused)) const char *txt){}
351
int start_mandos_communication(const char *ip, uint16_t port,
352
AvahiIfIndex if_index){
354
struct sockaddr_in6 to;
355
encrypted_session es;
595
/* Called when a Mandos server is found */
596
static int start_mandos_communication(const char *ip, uint16_t port,
597
AvahiIfIndex if_index,
599
int ret, tcp_sd = -1;
602
struct sockaddr_in in;
603
struct sockaddr_in6 in6;
356
605
char *buffer = NULL;
357
char *decrypted_buffer;
606
char *decrypted_buffer = NULL;
358
607
size_t buffer_length = 0;
359
608
size_t buffer_capacity = 0;
360
ssize_t decrypted_buffer_size;
363
char interface[IF_NAMESIZE];
366
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
370
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
376
if(if_indextoname((unsigned int)if_index, interface) == NULL){
378
perror("if_indextoname");
384
fprintf(stderr, "Binding to interface %s\n", interface);
387
memset(&to,0,sizeof(to)); /* Spurious warning */
388
to.sin6_family = AF_INET6;
389
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
611
gnutls_session_t session;
612
int pf; /* Protocol family */
629
fprintf(stderr, "Bad address family: %d\n", af);
634
ret = init_gnutls_session(&session);
640
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
644
tcp_sd = socket(pf, SOCK_STREAM, 0);
647
perror_plus("socket");
657
memset(&to, 0, sizeof(to));
659
to.in6.sin6_family = (sa_family_t)af;
660
ret = inet_pton(af, ip, &to.in6.sin6_addr);
662
to.in.sin_family = (sa_family_t)af;
663
ret = inet_pton(af, ip, &to.in.sin_addr);
667
perror_plus("inet_pton");
395
673
fprintf(stderr, "Bad address: %s\n", ip);
398
to.sin6_port = htons(port); /* Spurious warning */
678
to.in6.sin6_port = htons(port); /* Spurious warnings from
680
-Wunreachable-code */
682
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
683
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
685
if(if_index == AVAHI_IF_UNSPEC){
686
fprintf(stderr, "An IPv6 link-local address is incomplete"
687
" without a network interface\n");
691
/* Set the network interface number as scope */
692
to.in6.sin6_scope_id = (uint32_t)if_index;
695
to.in.sin_port = htons(port); /* Spurious warnings from
697
-Wunreachable-code */
400
to.sin6_scope_id = (uint32_t)if_index;
403
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
404
/* char addrstr[INET6_ADDRSTRLEN]; */
405
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
406
/* sizeof(addrstr)) == NULL){ */
407
/* perror("inet_ntop"); */
409
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
410
/* addrstr, ntohs(to.sin6_port)); */
414
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
420
ret = initgnutls (&es);
426
gnutls_transport_set_ptr (es.session,
427
(gnutls_transport_ptr_t) tcp_sd);
706
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
707
char interface[IF_NAMESIZE];
708
if(if_indextoname((unsigned int)if_index, interface) == NULL){
709
perror_plus("if_indextoname");
711
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
712
ip, interface, port);
715
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
718
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
719
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
722
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
725
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
729
perror_plus("inet_ntop");
731
if(strcmp(addrstr, ip) != 0){
732
fprintf(stderr, "Canonical address form: %s\n", addrstr);
743
ret = connect(tcp_sd, &to.in6, sizeof(to));
745
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
748
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
750
perror_plus("connect");
761
const char *out = mandos_protocol_version;
764
size_t out_size = strlen(out);
765
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
766
out_size - written));
769
perror_plus("write");
773
written += (size_t)ret;
774
if(written < out_size){
777
if(out == mandos_protocol_version){
430
792
fprintf(stderr, "Establishing TLS session with %s\n", ip);
433
ret = gnutls_handshake (es.session);
435
if (ret != GNUTLS_E_SUCCESS){
800
/* Spurious warnings from -Wint-to-pointer-cast */
801
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
809
ret = gnutls_handshake(session);
814
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
816
if(ret != GNUTLS_E_SUCCESS){
437
fprintf(stderr, "\n*** Handshake failed ***\n");
818
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
444
//Retrieve OpenPGP packet that contains the wanted password
825
/* Read OpenPGP packet that contains the wanted password */
447
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
828
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
452
if (buffer_length + BUFFER_SIZE > buffer_capacity){
453
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
458
buffer_capacity += BUFFER_SIZE;
461
ret = gnutls_record_recv
462
(es.session, buffer+buffer_length, BUFFER_SIZE);
839
buffer_capacity = incbuffer(&buffer, buffer_length,
841
if(buffer_capacity == 0){
843
perror_plus("incbuffer");
853
sret = gnutls_record_recv(session, buffer+buffer_length,
468
860
case GNUTLS_E_INTERRUPTED:
469
861
case GNUTLS_E_AGAIN:
471
863
case GNUTLS_E_REHANDSHAKE:
472
ret = gnutls_handshake (es.session);
474
fprintf(stderr, "\n*** Handshake failed ***\n");
865
ret = gnutls_handshake(session);
871
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
873
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
481
880
fprintf(stderr, "Unknown error while reading data from"
482
" encrypted session with mandos server\n");
484
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
881
" encrypted session with Mandos server\n");
882
gnutls_bye(session, GNUTLS_SHUT_RDWR);
488
buffer_length += (size_t) ret;
492
if (buffer_length > 0){
887
buffer_length += (size_t) sret;
892
fprintf(stderr, "Closing TLS session\n");
901
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
906
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
908
if(buffer_length > 0){
909
ssize_t decrypted_buffer_size;
493
910
decrypted_buffer_size = pgp_packet_decrypt(buffer,
497
if (decrypted_buffer_size >= 0){
913
if(decrypted_buffer_size >= 0){
498
916
while(written < (size_t) decrypted_buffer_size){
499
ret = (int)fwrite (decrypted_buffer + written, 1,
500
(size_t)decrypted_buffer_size - written,
922
ret = (int)fwrite(decrypted_buffer + written, 1,
923
(size_t)decrypted_buffer_size - written,
502
925
if(ret == 0 and ferror(stdout)){
504
928
fprintf(stderr, "Error writing encrypted data: %s\n",
505
929
strerror(errno));
510
934
written += (size_t)ret;
512
free(decrypted_buffer);
940
/* Shutdown procedure */
945
free(decrypted_buffer);
948
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
954
perror_plus("close");
956
gnutls_deinit(session);
521
fprintf(stderr, "Closing TLS session\n");
525
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
528
gnutls_deinit (es.session);
529
gnutls_certificate_free_credentials (es.cred);
530
gnutls_global_deinit ();
534
static AvahiSimplePoll *simple_poll = NULL;
535
static AvahiServer *server = NULL;
537
static void resolve_callback(
538
AvahiSServiceResolver *r,
539
AvahiIfIndex interface,
540
AVAHI_GCC_UNUSED AvahiProtocol protocol,
541
AvahiResolverEvent event,
545
const char *host_name,
546
const AvahiAddress *address,
548
AVAHI_GCC_UNUSED AvahiStringList *txt,
549
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
550
AVAHI_GCC_UNUSED void* userdata) {
552
assert(r); /* Spurious warning */
966
static void resolve_callback(AvahiSServiceResolver *r,
967
AvahiIfIndex interface,
969
AvahiResolverEvent event,
973
const char *host_name,
974
const AvahiAddress *address,
976
AVAHI_GCC_UNUSED AvahiStringList *txt,
977
AVAHI_GCC_UNUSED AvahiLookupResultFlags
979
AVAHI_GCC_UNUSED void* userdata){
554
982
/* Called whenever a service has been resolved successfully or
559
991
case AVAHI_RESOLVER_FAILURE:
560
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
561
" type '%s' in domain '%s': %s\n", name, type, domain,
562
avahi_strerror(avahi_server_errno(server)));
992
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
993
" of type '%s' in domain '%s': %s\n", name, type, domain,
994
avahi_strerror(avahi_server_errno(mc.server)));
565
997
case AVAHI_RESOLVER_FOUND:
567
999
char ip[AVAHI_ADDRESS_STR_MAX];
568
1000
avahi_address_snprint(ip, sizeof(ip), address);
570
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
571
" port %d\n", name, host_name, ip, port);
1002
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
1003
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
1004
ip, (intmax_t)interface, port);
573
int ret = start_mandos_communication(ip, port, interface);
1006
int ret = start_mandos_communication(ip, port, interface,
1007
avahi_proto_to_af(proto));
1009
avahi_simple_poll_quit(mc.simple_poll);
1011
ret = add_server(ip, port, interface,
1012
avahi_proto_to_af(proto));
579
1016
avahi_s_service_resolver_free(r);
582
static void browse_callback(
583
AvahiSServiceBrowser *b,
584
AvahiIfIndex interface,
585
AvahiProtocol protocol,
586
AvahiBrowserEvent event,
590
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
593
AvahiServer *s = userdata;
594
assert(b); /* Spurious warning */
596
/* Called whenever a new services becomes available on the LAN or
597
is removed from the LAN */
1019
static void browse_callback(AvahiSServiceBrowser *b,
1020
AvahiIfIndex interface,
1021
AvahiProtocol protocol,
1022
AvahiBrowserEvent event,
1026
AVAHI_GCC_UNUSED AvahiLookupResultFlags
1028
AVAHI_GCC_UNUSED void* userdata){
1031
/* Called whenever a new services becomes available on the LAN or
1032
is removed from the LAN */
1040
case AVAHI_BROWSER_FAILURE:
1042
fprintf(stderr, "(Avahi browser) %s\n",
1043
avahi_strerror(avahi_server_errno(mc.server)));
1044
avahi_simple_poll_quit(mc.simple_poll);
1047
case AVAHI_BROWSER_NEW:
1048
/* We ignore the returned Avahi resolver object. In the callback
1049
function we free it. If the Avahi server is terminated before
1050
the callback function is called the Avahi server will free the
1053
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
1054
name, type, domain, protocol, 0,
1055
resolve_callback, NULL) == NULL)
1056
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
1057
name, avahi_strerror(avahi_server_errno(mc.server)));
1060
case AVAHI_BROWSER_REMOVE:
1063
case AVAHI_BROWSER_ALL_FOR_NOW:
1064
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1066
fprintf(stderr, "No Mandos server found, still searching...\n");
1072
/* Signal handler that stops main loop after sigterm has been called */
1073
static void handle_sigterm(int sig){
1078
signal_received = sig;
1079
int old_errno = errno;
1080
/* set main loop to exit */
1081
if(mc.simple_poll != NULL){
1082
avahi_simple_poll_quit(mc.simple_poll);
1088
* This function determines if a directory entry in /sys/class/net
1089
* corresponds to an acceptable network device.
1090
* (This function is passed to scandir(3) as a filter function.)
1092
int good_interface(const struct dirent *if_entry){
1094
char *flagname = NULL;
1095
if(if_entry->d_name[0] == '.'){
1098
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1101
perror_plus("asprintf");
1104
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1106
perror_plus("open");
1111
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1112
/* read line from flags_fd */
1113
ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1114
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1115
flagstring[(size_t)to_read] = '\0';
1116
if(flagstring == NULL){
1117
perror_plus("malloc");
1122
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1125
perror_plus("read");
1139
tmpmax = strtoimax(flagstring, &tmp, 0);
1140
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1141
and not (isspace(*tmp)))
1142
or tmpmax != (ifreq_flags)tmpmax){
1144
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1145
flagstring, if_entry->d_name);
1151
ifreq_flags flags = (ifreq_flags)tmpmax;
1152
/* Reject the loopback device */
1153
if(flags & IFF_LOOPBACK){
1155
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1160
/* Accept point-to-point devices only if connect_to is specified */
1161
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1163
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1168
/* Otherwise, reject non-broadcast-capable devices */
1169
if(not (flags & IFF_BROADCAST)){
1171
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1176
/* Reject non-ARP interfaces (including dummy interfaces) */
1177
if(flags & IFF_NOARP){
1179
fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n",
1184
/* Accept this device */
1186
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1192
int notdotentries(const struct dirent *direntry){
1193
/* Skip "." and ".." */
1194
if(direntry->d_name[0] == '.'
1195
and (direntry->d_name[1] == '\0'
1196
or (direntry->d_name[1] == '.'
1197
and direntry->d_name[2] == '\0'))){
1203
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval){
1205
struct timespec now;
1206
struct timespec waited_time;
1207
intmax_t block_time;
1210
if(mc.current_server == NULL){
1212
fprintf(stderr, "Wait until first server is found. No timeout!\n");
1214
ret = avahi_simple_poll_iterate(s, -1);
1217
fprintf(stderr, "Check current_server if we should run it, or wait\n");
1219
/* the current time */
1220
ret = clock_gettime(CLOCK_MONOTONIC, &now);
1222
perror_plus("clock_gettime");
1225
/* Calculating in ms how long time between now and server
1226
who we visted longest time ago. Now - last seen. */
1227
waited_time.tv_sec = now.tv_sec - mc.current_server->last_seen.tv_sec;
1228
waited_time.tv_nsec = now.tv_nsec - mc.current_server->last_seen.tv_nsec;
1229
/* total time is 10s/10000ms. Converting to s to ms by 1000/s, and ns to ms by divind by 1000000. */
1230
block_time = (retry_interval - ((intmax_t)waited_time.tv_sec * 1000)) - ((intmax_t)waited_time.tv_nsec / 1000000);
1233
fprintf(stderr, "Blocking for %ld ms\n", block_time);
1236
if(block_time <= 0){
1237
ret = start_mandos_communication(mc.current_server->ip,
1238
mc.current_server->port,
1239
mc.current_server->if_index,
1240
mc.current_server->af);
1242
avahi_simple_poll_quit(mc.simple_poll);
1245
ret = clock_gettime(CLOCK_MONOTONIC, &mc.current_server->last_seen);
1247
perror_plus("clock_gettime");
1250
mc.current_server = mc.current_server->next;
1251
block_time = 0; /* call avahi to find new mandos servers, but dont block */
1254
ret = avahi_simple_poll_iterate(s, (int)block_time);
1257
if (ret > 0 or errno != EINTR) {
1258
return (ret != 1) ? ret : 0;
1264
int main(int argc, char *argv[]){
1265
AvahiSServiceBrowser *sb = NULL;
1270
int exitcode = EXIT_SUCCESS;
1271
const char *interface = "";
1272
struct ifreq network;
1274
bool take_down_interface = false;
1277
char tempdir[] = "/tmp/mandosXXXXXX";
1278
bool tempdir_created = false;
1279
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1280
const char *seckey = PATHDIR "/" SECKEY;
1281
const char *pubkey = PATHDIR "/" PUBKEY;
1283
bool gnutls_initialized = false;
1284
bool gpgme_initialized = false;
1286
double retry_interval = 10; /* 10s between retrying a server and checking again*/
1288
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1289
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1294
/* Lower any group privileges we might have, just to be safe */
1298
perror_plus("setgid");
1301
/* Lower user privileges (temporarily) */
1305
perror_plus("seteuid");
1313
struct argp_option options[] = {
1314
{ .name = "debug", .key = 128,
1315
.doc = "Debug mode", .group = 3 },
1316
{ .name = "connect", .key = 'c',
1317
.arg = "ADDRESS:PORT",
1318
.doc = "Connect directly to a specific Mandos server",
1320
{ .name = "interface", .key = 'i',
1322
.doc = "Network interface that will be used to search for"
1325
{ .name = "seckey", .key = 's',
1327
.doc = "OpenPGP secret key file base name",
1329
{ .name = "pubkey", .key = 'p',
1331
.doc = "OpenPGP public key file base name",
1333
{ .name = "dh-bits", .key = 129,
1335
.doc = "Bit length of the prime number used in the"
1336
" Diffie-Hellman key exchange",
1338
{ .name = "priority", .key = 130,
1340
.doc = "GnuTLS priority string for the TLS handshake",
1342
{ .name = "delay", .key = 131,
1344
.doc = "Maximum delay to wait for interface startup",
1346
{ .name = "retry", .key = 132,
1348
.doc = "Retry interval used when denied by the mandos server",
1351
* These reproduce what we would get without ARGP_NO_HELP
1353
{ .name = "help", .key = '?',
1354
.doc = "Give this help list", .group = -1 },
1355
{ .name = "usage", .key = -3,
1356
.doc = "Give a short usage message", .group = -1 },
1357
{ .name = "version", .key = 'V',
1358
.doc = "Print program version", .group = -1 },
1362
error_t parse_opt(int key, char *arg,
1363
struct argp_state *state){
1366
case 128: /* --debug */
1369
case 'c': /* --connect */
1372
case 'i': /* --interface */
1375
case 's': /* --seckey */
1378
case 'p': /* --pubkey */
1381
case 129: /* --dh-bits */
1383
tmpmax = strtoimax(arg, &tmp, 10);
1384
if(errno != 0 or tmp == arg or *tmp != '\0'
1385
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1386
argp_error(state, "Bad number of DH bits");
1388
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1390
case 130: /* --priority */
1393
case 131: /* --delay */
1395
delay = strtof(arg, &tmp);
1396
if(errno != 0 or tmp == arg or *tmp != '\0'){
1397
argp_error(state, "Bad delay");
1399
case 132: /* --retry */
1401
retry_interval = strtod(arg, &tmp);
1402
if(errno != 0 or tmp == arg or *tmp != '\0'
1403
or (retry_interval * 1000) > INT_MAX){
1404
argp_error(state, "Bad retry interval");
1408
* These reproduce what we would get without ARGP_NO_HELP
1410
case '?': /* --help */
1411
argp_state_help(state, state->out_stream,
1412
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1413
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1414
case -3: /* --usage */
1415
argp_state_help(state, state->out_stream,
1416
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1417
case 'V': /* --version */
1418
fprintf(state->out_stream, "%s\n", argp_program_version);
1419
exit(argp_err_exit_status);
1422
return ARGP_ERR_UNKNOWN;
1427
struct argp argp = { .options = options, .parser = parse_opt,
1429
.doc = "Mandos client -- Get and decrypt"
1430
" passwords from a Mandos server" };
1431
ret = argp_parse(&argp, argc, argv,
1432
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
601
case AVAHI_BROWSER_FAILURE:
603
fprintf(stderr, "(Browser) %s\n",
604
avahi_strerror(avahi_server_errno(server)));
605
avahi_simple_poll_quit(simple_poll);
608
case AVAHI_BROWSER_NEW:
609
/* We ignore the returned resolver object. In the callback
610
function we free it. If the server is terminated before
611
the callback function is called the server will free
612
the resolver for us. */
614
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
616
AVAHI_PROTO_INET6, 0,
617
resolve_callback, s)))
618
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
619
avahi_strerror(avahi_server_errno(s)));
622
case AVAHI_BROWSER_REMOVE:
625
case AVAHI_BROWSER_ALL_FOR_NOW:
626
case AVAHI_BROWSER_CACHE_EXHAUSTED:
631
/* combinds file name and path and returns the malloced new string. som sane checks could/should be added */
632
const char *combinepath(const char *first, const char *second){
634
tmp = malloc(strlen(first) + strlen(second) + 2);
640
if (first[0] != '\0' and first[strlen(first) - 1] != '/'){
648
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1439
perror_plus("argp_parse");
1440
exitcode = EX_OSERR;
1443
exitcode = EX_USAGE;
1449
avahi_set_log_function(empty_log);
1452
if(interface[0] == '\0'){
1453
struct dirent **direntries;
1454
ret = scandir(sys_class_net, &direntries, good_interface,
1457
/* Pick the first good interface */
1458
interface = strdup(direntries[0]->d_name);
1460
fprintf(stderr, "Using interface \"%s\"\n", interface);
1462
if(interface == NULL){
1463
perror_plus("malloc");
1465
exitcode = EXIT_FAILURE;
1471
fprintf(stderr, "Could not find a network interface\n");
1472
exitcode = EXIT_FAILURE;
1477
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1478
from the signal handler */
1479
/* Initialize the pseudo-RNG for Avahi */
1480
srand((unsigned int) time(NULL));
1481
mc.simple_poll = avahi_simple_poll_new();
1482
if(mc.simple_poll == NULL){
1483
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1484
exitcode = EX_UNAVAILABLE;
1488
sigemptyset(&sigterm_action.sa_mask);
1489
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1491
perror_plus("sigaddset");
1492
exitcode = EX_OSERR;
1495
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1497
perror_plus("sigaddset");
1498
exitcode = EX_OSERR;
1501
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1503
perror_plus("sigaddset");
1504
exitcode = EX_OSERR;
1507
/* Need to check if the handler is SIG_IGN before handling:
1508
| [[info:libc:Initial Signal Actions]] |
1509
| [[info:libc:Basic Signal Handling]] |
1511
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1513
perror_plus("sigaction");
1516
if(old_sigterm_action.sa_handler != SIG_IGN){
1517
ret = sigaction(SIGINT, &sigterm_action, NULL);
1519
perror_plus("sigaction");
1520
exitcode = EX_OSERR;
1524
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1526
perror_plus("sigaction");
1529
if(old_sigterm_action.sa_handler != SIG_IGN){
1530
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1532
perror_plus("sigaction");
1533
exitcode = EX_OSERR;
1537
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1539
perror_plus("sigaction");
1542
if(old_sigterm_action.sa_handler != SIG_IGN){
1543
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1545
perror_plus("sigaction");
1546
exitcode = EX_OSERR;
1551
/* If the interface is down, bring it up */
1552
if(strcmp(interface, "none") != 0){
1553
if_index = (AvahiIfIndex) if_nametoindex(interface);
1555
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1556
exitcode = EX_UNAVAILABLE;
1564
/* Re-raise priviliges */
1568
perror_plus("seteuid");
1572
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1573
messages about the network interface to mess up the prompt */
1574
ret = klogctl(8, NULL, 5);
1575
bool restore_loglevel = true;
1577
restore_loglevel = false;
1578
perror_plus("klogctl");
1580
#endif /* __linux__ */
1582
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1584
perror_plus("socket");
1585
exitcode = EX_OSERR;
1587
if(restore_loglevel){
1588
ret = klogctl(7, NULL, 0);
1590
perror_plus("klogctl");
1593
#endif /* __linux__ */
1594
/* Lower privileges */
1598
perror_plus("seteuid");
1602
strcpy(network.ifr_name, interface);
1603
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1605
perror_plus("ioctl SIOCGIFFLAGS");
1607
if(restore_loglevel){
1608
ret = klogctl(7, NULL, 0);
1610
perror_plus("klogctl");
1613
#endif /* __linux__ */
1614
exitcode = EX_OSERR;
1615
/* Lower privileges */
1619
perror_plus("seteuid");
1623
if((network.ifr_flags & IFF_UP) == 0){
1624
network.ifr_flags |= IFF_UP;
1625
take_down_interface = true;
1626
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1628
take_down_interface = false;
1629
perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1630
exitcode = EX_OSERR;
1632
if(restore_loglevel){
1633
ret = klogctl(7, NULL, 0);
1635
perror_plus("klogctl");
1638
#endif /* __linux__ */
1639
/* Lower privileges */
1643
perror_plus("seteuid");
1648
/* sleep checking until interface is running. Check every 0.25s, up to total time of delay */
1649
for(int i=0; i < delay * 4; i++){
1650
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1652
perror_plus("ioctl SIOCGIFFLAGS");
1653
} else if(network.ifr_flags & IFF_RUNNING){
1656
struct timespec sleeptime = { .tv_nsec = 250000000 };
1657
ret = nanosleep(&sleeptime, NULL);
1658
if(ret == -1 and errno != EINTR){
1659
perror_plus("nanosleep");
1662
if(not take_down_interface){
1663
/* We won't need the socket anymore */
1664
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1666
perror_plus("close");
1670
if(restore_loglevel){
1671
/* Restores kernel loglevel to default */
1672
ret = klogctl(7, NULL, 0);
1674
perror_plus("klogctl");
1677
#endif /* __linux__ */
1678
/* Lower privileges */
1680
if(take_down_interface){
1681
/* Lower privileges */
1684
perror_plus("seteuid");
1687
/* Lower privileges permanently */
1690
perror_plus("setuid");
1699
ret = init_gnutls_global(pubkey, seckey);
1701
fprintf(stderr, "init_gnutls_global failed\n");
1702
exitcode = EX_UNAVAILABLE;
1705
gnutls_initialized = true;
1712
if(mkdtemp(tempdir) == NULL){
1713
perror_plus("mkdtemp");
1716
tempdir_created = true;
1722
if(not init_gpgme(pubkey, seckey, tempdir)){
1723
fprintf(stderr, "init_gpgme failed\n");
1724
exitcode = EX_UNAVAILABLE;
1727
gpgme_initialized = true;
1734
if(connect_to != NULL){
1735
/* Connect directly, do not use Zeroconf */
1736
/* (Mainly meant for debugging) */
1737
char *address = strrchr(connect_to, ':');
1738
if(address == NULL){
1739
fprintf(stderr, "No colon in address\n");
1740
exitcode = EX_USAGE;
1750
tmpmax = strtoimax(address+1, &tmp, 10);
1751
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1752
or tmpmax != (uint16_t)tmpmax){
1753
fprintf(stderr, "Bad port number\n");
1754
exitcode = EX_USAGE;
1762
port = (uint16_t)tmpmax;
1764
address = connect_to;
1765
/* Colon in address indicates IPv6 */
1767
if(strchr(address, ':') != NULL){
1777
while(not quit_now){
1778
ret = start_mandos_communication(address, port, if_index, af);
1779
if(quit_now or ret == 0){
1782
sleep((int)retry_interval or 1);
1786
exitcode = EXIT_SUCCESS;
649
1797
AvahiServerConfig config;
650
AvahiSServiceBrowser *sb = NULL;
653
int returncode = EXIT_SUCCESS;
654
const char *interface = NULL;
655
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
656
char *connect_to = NULL;
659
static struct option long_options[] = {
660
{"debug", no_argument, (int *)&debug, 1},
661
{"connect", required_argument, 0, 'C'},
662
{"interface", required_argument, 0, 'i'},
663
{"certdir", required_argument, 0, 'd'},
664
{"certkey", required_argument, 0, 'c'},
665
{"certfile", required_argument, 0, 'k'},
668
int option_index = 0;
669
ret = getopt_long (argc, argv, "i:", long_options,
699
certfile = combinepath(certdir, certfile);
700
if (certfile == NULL){
704
if(interface != NULL){
705
if_index = (AvahiIfIndex) if_nametoindex(interface);
707
fprintf(stderr, "No such interface: \"%s\"\n", interface);
712
if(connect_to != NULL){
713
/* Connect directly, do not use Zeroconf */
714
/* (Mainly meant for debugging) */
715
char *address = strrchr(connect_to, ':');
717
fprintf(stderr, "No colon in address\n");
721
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
723
perror("Bad port number");
727
address = connect_to;
728
ret = start_mandos_communication(address, port, if_index);
736
certkey = combinepath(certdir, certkey);
737
if (certkey == NULL){
742
avahi_set_log_function(empty_log);
745
/* Initialize the psuedo-RNG */
746
srand((unsigned int) time(NULL));
748
/* Allocate main loop object */
749
if (!(simple_poll = avahi_simple_poll_new())) {
750
fprintf(stderr, "Failed to create simple poll object.\n");
755
/* Do not publish any local records */
1798
/* Do not publish any local Zeroconf records */
756
1799
avahi_server_config_init(&config);
757
1800
config.publish_hinfo = 0;
758
1801
config.publish_addresses = 0;
759
1802
config.publish_workstation = 0;
760
1803
config.publish_domain = 0;
762
1805
/* Allocate a new server */
763
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
764
&config, NULL, NULL, &error);
766
/* Free the configuration data */
1806
mc.server = avahi_server_new(avahi_simple_poll_get
1807
(mc.simple_poll), &config, NULL,
1810
/* Free the Avahi configuration data */
767
1811
avahi_server_config_free(&config);
769
/* Check if creating the server object succeeded */
771
fprintf(stderr, "Failed to create server: %s\n",
772
avahi_strerror(error));
773
returncode = EXIT_FAILURE;
777
/* Create the service browser */
778
sb = avahi_s_service_browser_new(server, if_index,
780
"_mandos._tcp", NULL, 0,
781
browse_callback, server);
783
fprintf(stderr, "Failed to create service browser: %s\n",
784
avahi_strerror(avahi_server_errno(server)));
785
returncode = EXIT_FAILURE;
789
/* Run the main loop */
792
fprintf(stderr, "Starting avahi loop search\n");
795
avahi_simple_poll_loop(simple_poll);
800
fprintf(stderr, "%s exiting\n", argv[0]);
805
avahi_s_service_browser_free(sb);
808
avahi_server_free(server);
811
avahi_simple_poll_free(simple_poll);
1814
/* Check if creating the Avahi server object succeeded */
1815
if(mc.server == NULL){
1816
fprintf(stderr, "Failed to create Avahi server: %s\n",
1817
avahi_strerror(error));
1818
exitcode = EX_UNAVAILABLE;
1826
/* Create the Avahi service browser */
1827
sb = avahi_s_service_browser_new(mc.server, if_index,
1828
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1829
NULL, 0, browse_callback, NULL);
1831
fprintf(stderr, "Failed to create service browser: %s\n",
1832
avahi_strerror(avahi_server_errno(mc.server)));
1833
exitcode = EX_UNAVAILABLE;
1841
/* Run the main loop */
1844
fprintf(stderr, "Starting Avahi loop search\n");
1847
ret = avahi_loop_with_timeout(mc.simple_poll, (int)(retry_interval * 1000));
1849
fprintf(stderr, "avahi_loop_with_timeout exited %s\n",
1850
(ret == 0) ? "successfully" : "with error");
1856
fprintf(stderr, "%s exiting\n", argv[0]);
1859
/* Cleanup things */
1861
avahi_s_service_browser_free(sb);
1863
if(mc.server != NULL)
1864
avahi_server_free(mc.server);
1866
if(mc.simple_poll != NULL)
1867
avahi_simple_poll_free(mc.simple_poll);
1869
if(gnutls_initialized){
1870
gnutls_certificate_free_credentials(mc.cred);
1871
gnutls_global_deinit();
1872
gnutls_dh_params_deinit(mc.dh_params);
1875
if(gpgme_initialized){
1876
gpgme_release(mc.ctx);
1879
/* cleans up the circular linked list of mandos servers the client has seen */
1880
if(mc.current_server != NULL){
1881
mc.current_server->prev->next = NULL;
1882
while(mc.current_server != NULL){
1883
server *next = mc.current_server->next;
1884
free(mc.current_server);
1885
mc.current_server = next;
1889
/* Take down the network interface */
1890
if(take_down_interface){
1891
/* Re-raise priviliges */
1895
perror_plus("seteuid");
1898
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1900
perror_plus("ioctl SIOCGIFFLAGS");
1901
} else if(network.ifr_flags & IFF_UP) {
1902
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1903
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1905
perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
1908
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1910
perror_plus("close");
1912
/* Lower privileges permanently */
1916
perror_plus("setuid");
1921
/* Removes the GPGME temp directory and all files inside */
1922
if(tempdir_created){
1923
struct dirent **direntries = NULL;
1924
struct dirent *direntry = NULL;
1925
ret = scandir(tempdir, &direntries, notdotentries, alphasort);
1927
for(int i = 0; i < ret; i++){
1928
direntry = direntries[i];
1929
char *fullname = NULL;
1930
ret = asprintf(&fullname, "%s/%s", tempdir,
1933
perror_plus("asprintf");
1936
ret = remove(fullname);
1938
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1945
/* need to be cleaned even if ret == 0 because man page dont specify */
1948
perror_plus("scandir");
1950
ret = rmdir(tempdir);
1951
if(ret == -1 and errno != ENOENT){
1952
perror_plus("rmdir");
1957
sigemptyset(&old_sigterm_action.sa_mask);
1958
old_sigterm_action.sa_handler = SIG_DFL;
1959
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1960
&old_sigterm_action,
1963
perror_plus("sigaction");
1966
ret = raise(signal_received);
1967
} while(ret != 0 and errno == EINTR);
1969
perror_plus("raise");
1972
TEMP_FAILURE_RETRY(pause());