100
45
#include <avahi-common/malloc.h>
101
46
#include <avahi-common/error.h>
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,
49
#include <sys/types.h> /* socket(), inet_pton() */
50
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
51
struct in6_addr, inet_pton() */
52
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
53
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
55
#include <unistd.h> /* close() */
56
#include <netinet/in.h>
57
#include <stdbool.h> /* true */
58
#include <string.h> /* memset */
59
#include <arpa/inet.h> /* inet_pton() */
60
#include <iso646.h> /* not */
63
#include <errno.h> /* perror() */
120
69
#define BUFFER_SIZE 256
122
#define PATHDIR "/conf/conf.d/mandos"
123
#define SECKEY "seckey.txt"
124
#define PUBKEY "pubkey.txt"
72
const char *certdir = "/conf/conf.d/cryptkeyreq/";
73
const char *certfile = "openpgp-client.txt";
74
const char *certkey = "openpgp-client-key.txt";
126
76
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 */
146
AvahiSimplePoll *simple_poll;
79
gnutls_session_t session;
148
80
gnutls_certificate_credentials_t cred;
149
unsigned int dh_bits;
150
81
gnutls_dh_params_t dh_params;
151
const char *priority;
85
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
86
char **new_packet, const char *homedir){
87
gpgme_data_t dh_crypto, dh_plain;
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){
91
ssize_t new_packet_capacity = 0;
92
ssize_t new_packet_length = 0;
230
93
gpgme_engine_info_t engine_info;
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");
96
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
274
100
gpgme_check_version(NULL);
275
101
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
276
if(rc != GPG_ERR_NO_ERROR){
102
if (rc != GPG_ERR_NO_ERROR){
277
103
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
278
104
gpgme_strsource(rc), gpgme_strerror(rc));
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){
108
/* Set GPGME home directory */
109
rc = gpgme_get_engine_info (&engine_info);
110
if (rc != GPG_ERR_NO_ERROR){
285
111
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
286
112
gpgme_strsource(rc), gpgme_strerror(rc));
289
115
while(engine_info != NULL){
290
116
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
291
117
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
292
engine_info->file_name, tempdir);
118
engine_info->file_name, homedir);
295
121
engine_info = engine_info->next;
297
123
if(engine_info == NULL){
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){
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){
338
131
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
339
132
gpgme_strsource(rc), gpgme_strerror(rc));
389
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
194
/* Delete the GPGME FILE pointer cryptotext data buffer */
195
gpgme_data_release(dh_crypto);
392
197
/* Seek back to the beginning of the GPGME plaintext data buffer */
393
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
394
perror_plus("gpgme_data_seek");
395
plaintext_length = -1;
198
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
199
perror("pgpme_data_seek");
401
plaintext_capacity = incbuffer(plaintext,
402
(size_t)plaintext_length,
404
if(plaintext_capacity == 0){
405
perror_plus("incbuffer");
406
plaintext_length = -1;
204
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
205
*new_packet = realloc(*new_packet,
206
(unsigned int)new_packet_capacity
208
if (*new_packet == NULL){
212
new_packet_capacity += BUFFER_SIZE;
410
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
215
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
412
217
/* Print the data, if any */
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);
222
perror("gpgme_data_read");
225
new_packet_length += ret;
228
/* FIXME: check characters before printing to screen so to not print
229
terminal control characters */
231
/* fprintf(stderr, "decrypted password is: "); */
232
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
233
/* fprintf(stderr, "\n"); */
438
236
/* Delete the GPGME plaintext data buffer */
439
237
gpgme_data_release(dh_plain);
440
return plaintext_length;
238
return new_packet_length;
443
static const char * safer_gnutls_strerror(int value){
444
const char *ret = gnutls_strerror(value); /* Spurious warning from
445
-Wunreachable-code */
241
static const char * safer_gnutls_strerror (int value) {
242
const char *ret = gnutls_strerror (value);
447
244
ret = "(unknown)";
451
/* GnuTLS log function callback */
452
static void debuggnutls(__attribute__((unused)) int level,
454
fprintf(stderr, "GnuTLS: %s", string);
248
void debuggnutls(__attribute__((unused)) int level,
250
fprintf(stderr, "%s", string);
457
static int init_gnutls_global(const char *pubkeyfilename,
458
const char *seckeyfilename){
253
int initgnutls(encrypted_session *es){
462
258
fprintf(stderr, "Initializing GnuTLS\n");
465
ret = gnutls_global_init();
466
if(ret != GNUTLS_E_SUCCESS){
467
fprintf(stderr, "GnuTLS global_init: %s\n",
468
safer_gnutls_strerror(ret));
261
if ((ret = gnutls_global_init ())
262
!= GNUTLS_E_SUCCESS) {
263
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
473
/* "Use a log level over 10 to enable all debugging options."
476
268
gnutls_global_set_log_level(11);
477
269
gnutls_global_set_log_function(debuggnutls);
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();
272
/* openpgp credentials */
273
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
274
!= GNUTLS_E_SUCCESS) {
275
fprintf (stderr, "memory error: %s\n",
276
safer_gnutls_strerror(ret));
493
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
494
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
281
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
282
" and keyfile %s as GnuTLS credentials\n", certfile,
498
286
ret = gnutls_certificate_set_openpgp_key_file
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){
287
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
288
if (ret != GNUTLS_E_SUCCESS) {
290
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
292
ret, certfile, certkey);
293
fprintf(stdout, "The Error is: %s\n",
294
safer_gnutls_strerror(ret));
298
//GnuTLS server initialization
299
if ((ret = gnutls_dh_params_init (&es->dh_params))
300
!= GNUTLS_E_SUCCESS) {
301
fprintf (stderr, "Error in dh parameter initialization: %s\n",
302
safer_gnutls_strerror(ret));
306
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
307
!= GNUTLS_E_SUCCESS) {
308
fprintf (stderr, "Error in prime generation: %s\n",
309
safer_gnutls_strerror(ret));
313
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
315
// GnuTLS session creation
316
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
317
!= GNUTLS_E_SUCCESS){
546
318
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
547
319
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);
322
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
323
!= GNUTLS_E_SUCCESS) {
324
fprintf(stderr, "Syntax error at: %s\n", err);
325
fprintf(stderr, "GnuTLS error: %s\n",
326
safer_gnutls_strerror(ret));
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",
330
if ((ret = gnutls_credentials_set
331
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
332
!= GNUTLS_E_SUCCESS) {
333
fprintf(stderr, "Error setting a credentials set: %s\n",
578
334
safer_gnutls_strerror(ret));
579
gnutls_deinit(*session);
583
338
/* ignore client certificate if any. */
584
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
339
gnutls_certificate_server_set_request (es->session,
586
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
342
gnutls_dh_set_prime_bits (es->session, DH_BITS);
591
/* Avahi log function callback */
592
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
593
__attribute__((unused)) const char *txt){}
347
void empty_log(__attribute__((unused)) AvahiLogLevel level,
348
__attribute__((unused)) const char *txt){}
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;
350
int start_mandos_communication(const char *ip, uint16_t port,
351
AvahiIfIndex if_index){
353
struct sockaddr_in6 to;
354
encrypted_session es;
605
355
char *buffer = NULL;
606
char *decrypted_buffer = NULL;
356
char *decrypted_buffer;
607
357
size_t buffer_length = 0;
608
358
size_t buffer_capacity = 0;
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");
359
ssize_t decrypted_buffer_size;
362
char interface[IF_NAMESIZE];
365
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
369
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
375
if(if_indextoname((unsigned int)if_index, interface) == NULL){
377
perror("if_indextoname");
383
fprintf(stderr, "Binding to interface %s\n", interface);
386
memset(&to,0,sizeof(to)); /* Spurious warning */
387
to.sin6_family = AF_INET6;
388
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
673
394
fprintf(stderr, "Bad address: %s\n", ip);
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 */
397
to.sin6_port = htons(port); /* Spurious warning */
399
to.sin6_scope_id = (uint32_t)if_index;
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){
402
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
403
/* char addrstr[INET6_ADDRSTRLEN]; */
404
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
405
/* sizeof(addrstr)) == NULL){ */
406
/* perror("inet_ntop"); */
408
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
409
/* addrstr, ntohs(to.sin6_port)); */
413
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
419
ret = initgnutls (&es);
425
gnutls_transport_set_ptr (es.session,
426
(gnutls_transport_ptr_t) tcp_sd);
792
429
fprintf(stderr, "Establishing TLS session with %s\n", ip);
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){
432
ret = gnutls_handshake (es.session);
434
if (ret != GNUTLS_E_SUCCESS){
818
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
436
fprintf(stderr, "\n*** Handshake failed ***\n");
825
/* Read OpenPGP packet that contains the wanted password */
443
//Retrieve OpenPGP packet that contains the wanted password
828
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
446
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
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,
451
if (buffer_length + BUFFER_SIZE > buffer_capacity){
452
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
457
buffer_capacity += BUFFER_SIZE;
460
ret = gnutls_record_recv
461
(es.session, buffer+buffer_length, BUFFER_SIZE);
860
467
case GNUTLS_E_INTERRUPTED:
861
468
case GNUTLS_E_AGAIN:
863
470
case GNUTLS_E_REHANDSHAKE:
865
ret = gnutls_handshake(session);
871
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
873
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
471
ret = gnutls_handshake (es.session);
473
fprintf(stderr, "\n*** Handshake failed ***\n");
880
480
fprintf(stderr, "Unknown error while reading data from"
881
" encrypted session with Mandos server\n");
882
gnutls_bye(session, GNUTLS_SHUT_RDWR);
481
" encrypted session with mandos server\n");
483
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
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;
487
buffer_length += (size_t) ret;
491
if (buffer_length > 0){
910
492
decrypted_buffer_size = pgp_packet_decrypt(buffer,
913
if(decrypted_buffer_size >= 0){
496
if (decrypted_buffer_size >= 0){
916
497
while(written < (size_t) decrypted_buffer_size){
922
ret = (int)fwrite(decrypted_buffer + written, 1,
923
(size_t)decrypted_buffer_size - written,
498
ret = (int)fwrite (decrypted_buffer + written, 1,
499
(size_t)decrypted_buffer_size - written,
925
501
if(ret == 0 and ferror(stdout)){
928
503
fprintf(stderr, "Error writing encrypted data: %s\n",
929
504
strerror(errno));
934
509
written += (size_t)ret;
940
/* Shutdown procedure */
945
free(decrypted_buffer);
948
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
954
perror_plus("close");
956
gnutls_deinit(session);
511
free(decrypted_buffer);
520
fprintf(stderr, "Closing TLS session\n");
524
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
527
gnutls_deinit (es.session);
528
gnutls_certificate_free_credentials (es.cred);
529
gnutls_global_deinit ();
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){
533
static AvahiSimplePoll *simple_poll = NULL;
534
static AvahiServer *server = NULL;
536
static void resolve_callback(
537
AvahiSServiceResolver *r,
538
AvahiIfIndex interface,
539
AVAHI_GCC_UNUSED AvahiProtocol protocol,
540
AvahiResolverEvent event,
544
const char *host_name,
545
const AvahiAddress *address,
547
AVAHI_GCC_UNUSED AvahiStringList *txt,
548
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
549
AVAHI_GCC_UNUSED void* userdata) {
551
assert(r); /* Spurious warning */
982
553
/* Called whenever a service has been resolved successfully or
991
558
case AVAHI_RESOLVER_FAILURE:
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)));
559
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
560
" type '%s' in domain '%s': %s\n", name, type, domain,
561
avahi_strerror(avahi_server_errno(server)));
997
564
case AVAHI_RESOLVER_FOUND:
999
566
char ip[AVAHI_ADDRESS_STR_MAX];
1000
567
avahi_address_snprint(ip, sizeof(ip), address);
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);
569
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
570
" port %d\n", name, host_name, ip, port);
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));
572
int ret = start_mandos_communication(ip, port, interface);
1016
578
avahi_s_service_resolver_free(r);
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);
581
static void browse_callback(
582
AvahiSServiceBrowser *b,
583
AvahiIfIndex interface,
584
AvahiProtocol protocol,
585
AvahiBrowserEvent event,
589
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
592
AvahiServer *s = userdata;
593
assert(b); /* Spurious warning */
595
/* Called whenever a new services becomes available on the LAN or
596
is removed from the LAN */
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;
600
case AVAHI_BROWSER_FAILURE:
602
fprintf(stderr, "(Browser) %s\n",
603
avahi_strerror(avahi_server_errno(server)));
604
avahi_simple_poll_quit(simple_poll);
607
case AVAHI_BROWSER_NEW:
608
/* We ignore the returned resolver object. In the callback
609
function we free it. If the server is terminated before
610
the callback function is called the server will free
611
the resolver for us. */
613
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
615
AVAHI_PROTO_INET6, 0,
616
resolve_callback, s)))
617
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
618
avahi_strerror(avahi_server_errno(s)));
621
case AVAHI_BROWSER_REMOVE:
624
case AVAHI_BROWSER_ALL_FOR_NOW:
625
case AVAHI_BROWSER_CACHE_EXHAUSTED:
630
/* combinds file name and path and returns the malloced new string. som sane checks could/should be added */
631
const char *combinepath(const char *first, const char *second){
633
tmp = malloc(strlen(first) + strlen(second) + 2);
639
if (first[0] != '\0' and first[strlen(first) - 1] != '/'){
647
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1797
648
AvahiServerConfig config;
1798
/* Do not publish any local Zeroconf records */
649
AvahiSServiceBrowser *sb = NULL;
652
int returncode = EXIT_SUCCESS;
653
const char *interface = NULL;
654
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
655
char *connect_to = NULL;
658
static struct option long_options[] = {
659
{"debug", no_argument, (int *)&debug, 1},
660
{"connect", required_argument, 0, 'C'},
661
{"interface", required_argument, 0, 'i'},
662
{"certdir", required_argument, 0, 'd'},
663
{"certkey", required_argument, 0, 'c'},
664
{"certfile", required_argument, 0, 'k'},
667
int option_index = 0;
668
ret = getopt_long (argc, argv, "i:", long_options,
698
certfile = combinepath(certdir, certfile);
699
if (certfile == NULL){
703
if(interface != NULL){
704
if_index = (AvahiIfIndex) if_nametoindex(interface);
706
fprintf(stderr, "No such interface: \"%s\"\n", interface);
711
if(connect_to != NULL){
712
/* Connect directly, do not use Zeroconf */
713
/* (Mainly meant for debugging) */
714
char *address = strrchr(connect_to, ':');
716
fprintf(stderr, "No colon in address\n");
720
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
722
perror("Bad port number");
726
address = connect_to;
727
ret = start_mandos_communication(address, port, if_index);
735
certkey = combinepath(certdir, certkey);
736
if (certkey == NULL){
741
avahi_set_log_function(empty_log);
744
/* Initialize the psuedo-RNG */
745
srand((unsigned int) time(NULL));
747
/* Allocate main loop object */
748
if (!(simple_poll = avahi_simple_poll_new())) {
749
fprintf(stderr, "Failed to create simple poll object.\n");
754
/* Do not publish any local records */
1799
755
avahi_server_config_init(&config);
1800
756
config.publish_hinfo = 0;
1801
757
config.publish_addresses = 0;
1802
758
config.publish_workstation = 0;
1803
759
config.publish_domain = 0;
1805
761
/* Allocate a new server */
1806
mc.server = avahi_server_new(avahi_simple_poll_get
1807
(mc.simple_poll), &config, NULL,
1810
/* Free the Avahi configuration data */
762
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
763
&config, NULL, NULL, &error);
765
/* Free the configuration data */
1811
766
avahi_server_config_free(&config);
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());
768
/* Check if creating the server object succeeded */
770
fprintf(stderr, "Failed to create server: %s\n",
771
avahi_strerror(error));
772
returncode = EXIT_FAILURE;
776
/* Create the service browser */
777
sb = avahi_s_service_browser_new(server, if_index,
779
"_mandos._tcp", NULL, 0,
780
browse_callback, server);
782
fprintf(stderr, "Failed to create service browser: %s\n",
783
avahi_strerror(avahi_server_errno(server)));
784
returncode = EXIT_FAILURE;
788
/* Run the main loop */
791
fprintf(stderr, "Starting avahi loop search\n");
794
avahi_simple_poll_loop(simple_poll);
799
fprintf(stderr, "%s exiting\n", argv[0]);
804
avahi_s_service_browser_free(sb);
807
avahi_server_free(server);
810
avahi_simple_poll_free(simple_poll);