100
47
#include <avahi-common/malloc.h>
101
48
#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,
51
#include <sys/types.h> /* socket(), inet_pton() */
52
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
53
struct in6_addr, inet_pton() */
54
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
55
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
57
#include <unistd.h> /* close() */
58
#include <netinet/in.h>
59
#include <stdbool.h> /* true */
60
#include <string.h> /* memset */
61
#include <arpa/inet.h> /* inet_pton() */
62
#include <iso646.h> /* not */
65
#include <errno.h> /* perror() */
120
71
#define BUFFER_SIZE 256
122
#define PATHDIR "/conf/conf.d/mandos"
123
#define SECKEY "seckey.txt"
124
#define PUBKEY "pubkey.txt"
74
const char *certdir = "/conf/conf.d/cryptkeyreq/";
75
const char *certfile = "openpgp-client.txt";
76
const char *certkey = "openpgp-client-key.txt";
126
78
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;
81
gnutls_session_t session;
148
82
gnutls_certificate_credentials_t cred;
149
unsigned int dh_bits;
150
83
gnutls_dh_params_t dh_params;
151
const char *priority;
87
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
char **new_packet, const char *homedir){
89
gpgme_data_t dh_crypto, dh_plain;
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){
93
ssize_t new_packet_capacity = 0;
94
ssize_t new_packet_length = 0;
230
95
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");
98
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
274
102
gpgme_check_version(NULL);
275
103
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
276
if(rc != GPG_ERR_NO_ERROR){
104
if (rc != GPG_ERR_NO_ERROR){
277
105
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
278
106
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){
110
/* Set GPGME home directory */
111
rc = gpgme_get_engine_info (&engine_info);
112
if (rc != GPG_ERR_NO_ERROR){
285
113
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
286
114
gpgme_strsource(rc), gpgme_strerror(rc));
289
117
while(engine_info != NULL){
290
118
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
291
119
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
292
engine_info->file_name, tempdir);
120
engine_info->file_name, homedir);
295
123
engine_info = engine_info->next;
297
125
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){
126
fprintf(stderr, "Could not set home dir to %s\n", homedir);
130
/* Create new GPGME data buffer from packet buffer */
131
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
132
if (rc != GPG_ERR_NO_ERROR){
338
133
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
339
134
gpgme_strsource(rc), gpgme_strerror(rc));
389
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
196
/* Delete the GPGME FILE pointer cryptotext data buffer */
197
gpgme_data_release(dh_crypto);
392
199
/* 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;
200
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
201
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;
206
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
207
*new_packet = realloc(*new_packet,
208
(unsigned int)new_packet_capacity
210
if (*new_packet == NULL){
214
new_packet_capacity += BUFFER_SIZE;
410
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
217
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
412
219
/* 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);
224
perror("gpgme_data_read");
227
new_packet_length += ret;
230
/* FIXME: check characters before printing to screen so to not print
231
terminal control characters */
233
/* fprintf(stderr, "decrypted password is: "); */
234
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
235
/* fprintf(stderr, "\n"); */
438
238
/* Delete the GPGME plaintext data buffer */
439
239
gpgme_data_release(dh_plain);
440
return plaintext_length;
240
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 */
243
static const char * safer_gnutls_strerror (int value) {
244
const char *ret = gnutls_strerror (value);
447
246
ret = "(unknown)";
451
/* GnuTLS log function callback */
452
static void debuggnutls(__attribute__((unused)) int level,
454
fprintf(stderr, "GnuTLS: %s", string);
250
void debuggnutls(__attribute__((unused)) int level,
252
fprintf(stderr, "%s", string);
457
static int init_gnutls_global(const char *pubkeyfilename,
458
const char *seckeyfilename){
255
int initgnutls(encrypted_session *es){
462
260
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));
263
if ((ret = gnutls_global_init ())
264
!= GNUTLS_E_SUCCESS) {
265
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
473
/* "Use a log level over 10 to enable all debugging options."
476
270
gnutls_global_set_log_level(11);
477
271
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();
274
/* openpgp credentials */
275
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
276
!= GNUTLS_E_SUCCESS) {
277
fprintf (stderr, "memory error: %s\n",
278
safer_gnutls_strerror(ret));
493
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
494
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
283
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
284
" and keyfile %s as GnuTLS credentials\n", certfile,
498
288
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){
289
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
290
if (ret != GNUTLS_E_SUCCESS) {
292
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
294
ret, certfile, certkey);
295
fprintf(stdout, "The Error is: %s\n",
296
safer_gnutls_strerror(ret));
300
//GnuTLS server initialization
301
if ((ret = gnutls_dh_params_init (&es->dh_params))
302
!= GNUTLS_E_SUCCESS) {
303
fprintf (stderr, "Error in dh parameter initialization: %s\n",
304
safer_gnutls_strerror(ret));
308
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
309
!= GNUTLS_E_SUCCESS) {
310
fprintf (stderr, "Error in prime generation: %s\n",
311
safer_gnutls_strerror(ret));
315
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
317
// GnuTLS session creation
318
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
319
!= GNUTLS_E_SUCCESS){
546
320
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
547
321
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);
324
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
325
!= GNUTLS_E_SUCCESS) {
326
fprintf(stderr, "Syntax error at: %s\n", err);
327
fprintf(stderr, "GnuTLS error: %s\n",
328
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",
332
if ((ret = gnutls_credentials_set
333
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
334
!= GNUTLS_E_SUCCESS) {
335
fprintf(stderr, "Error setting a credentials set: %s\n",
578
336
safer_gnutls_strerror(ret));
579
gnutls_deinit(*session);
583
340
/* ignore client certificate if any. */
584
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
341
gnutls_certificate_server_set_request (es->session,
586
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
344
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){}
349
void empty_log(__attribute__((unused)) AvahiLogLevel level,
350
__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;
352
int start_mandos_communication(const char *ip, uint16_t port,
353
unsigned int if_index){
355
struct sockaddr_in6 to;
356
encrypted_session es;
605
357
char *buffer = NULL;
606
char *decrypted_buffer = NULL;
358
char *decrypted_buffer;
607
359
size_t buffer_length = 0;
608
360
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");
361
ssize_t decrypted_buffer_size;
364
char interface[IF_NAMESIZE];
367
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
370
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
376
if(if_indextoname(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);
673
395
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 */
398
to.sin6_port = htons(port); /* Spurious warning */
400
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){
403
fprintf(stderr, "Connection to: %s\n", ip);
406
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
412
ret = initgnutls (&es);
418
gnutls_transport_set_ptr (es.session,
419
(gnutls_transport_ptr_t) tcp_sd);
792
422
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){
425
ret = gnutls_handshake (es.session);
427
if (ret != GNUTLS_E_SUCCESS){
818
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
429
fprintf(stderr, "\n*** Handshake failed ***\n");
825
/* Read OpenPGP packet that contains the wanted password */
436
//Retrieve OpenPGP packet that contains the wanted password
828
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
439
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,
444
if (buffer_length + BUFFER_SIZE > buffer_capacity){
445
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
450
buffer_capacity += BUFFER_SIZE;
453
ret = gnutls_record_recv
454
(es.session, buffer+buffer_length, BUFFER_SIZE);
860
460
case GNUTLS_E_INTERRUPTED:
861
461
case GNUTLS_E_AGAIN:
863
463
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");
464
ret = gnutls_handshake (es.session);
466
fprintf(stderr, "\n*** Handshake failed ***\n");
880
473
fprintf(stderr, "Unknown error while reading data from"
881
" encrypted session with Mandos server\n");
882
gnutls_bye(session, GNUTLS_SHUT_RDWR);
474
" encrypted session with mandos server\n");
476
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;
480
buffer_length += (size_t) ret;
484
if (buffer_length > 0){
910
485
decrypted_buffer_size = pgp_packet_decrypt(buffer,
913
if(decrypted_buffer_size >= 0){
916
while(written < (size_t) decrypted_buffer_size){
922
ret = (int)fwrite(decrypted_buffer + written, 1,
923
(size_t)decrypted_buffer_size - written,
489
if (decrypted_buffer_size >= 0){
490
while(written < decrypted_buffer_size){
491
ret = (int)fwrite (decrypted_buffer + written, 1,
492
(size_t)decrypted_buffer_size - written,
925
494
if(ret == 0 and ferror(stdout)){
928
496
fprintf(stderr, "Error writing encrypted data: %s\n",
929
497
strerror(errno));
934
502
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);
504
free(decrypted_buffer);
513
fprintf(stderr, "Closing TLS session\n");
517
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
520
gnutls_deinit (es.session);
521
gnutls_certificate_free_credentials (es.cred);
522
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){
526
static AvahiSimplePoll *simple_poll = NULL;
527
static AvahiServer *server = NULL;
529
static void resolve_callback(
530
AvahiSServiceResolver *r,
531
AvahiIfIndex interface,
532
AVAHI_GCC_UNUSED AvahiProtocol protocol,
533
AvahiResolverEvent event,
537
const char *host_name,
538
const AvahiAddress *address,
540
AVAHI_GCC_UNUSED AvahiStringList *txt,
541
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
542
AVAHI_GCC_UNUSED void* userdata) {
544
assert(r); /* Spurious warning */
982
546
/* Called whenever a service has been resolved successfully or
991
551
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)));
552
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
553
" type '%s' in domain '%s': %s\n", name, type, domain,
554
avahi_strerror(avahi_server_errno(server)));
997
557
case AVAHI_RESOLVER_FOUND:
999
559
char ip[AVAHI_ADDRESS_STR_MAX];
1000
560
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);
562
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
563
" 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));
565
int ret = start_mandos_communication(ip, port,
566
(unsigned int) interface);
1016
572
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);
575
static void browse_callback(
576
AvahiSServiceBrowser *b,
577
AvahiIfIndex interface,
578
AvahiProtocol protocol,
579
AvahiBrowserEvent event,
583
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
586
AvahiServer *s = userdata;
587
assert(b); /* Spurious warning */
589
/* Called whenever a new services becomes available on the LAN or
590
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;
594
case AVAHI_BROWSER_FAILURE:
596
fprintf(stderr, "(Browser) %s\n",
597
avahi_strerror(avahi_server_errno(server)));
598
avahi_simple_poll_quit(simple_poll);
601
case AVAHI_BROWSER_NEW:
602
/* We ignore the returned resolver object. In the callback
603
function we free it. If the server is terminated before
604
the callback function is called the server will free
605
the resolver for us. */
607
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
609
AVAHI_PROTO_INET6, 0,
610
resolve_callback, s)))
611
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
612
avahi_strerror(avahi_server_errno(s)));
615
case AVAHI_BROWSER_REMOVE:
618
case AVAHI_BROWSER_ALL_FOR_NOW:
619
case AVAHI_BROWSER_CACHE_EXHAUSTED:
624
/* combinds file name and path and returns the malloced new string. som sane checks could/should be added */
625
const char *combinepath(const char *first, const char *second){
627
tmp = malloc(strlen(first) + strlen(second) + 2);
633
if (first[0] != '\0' and first[strlen(first) - 1] != '/'){
641
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1797
642
AvahiServerConfig config;
1798
/* Do not publish any local Zeroconf records */
643
AvahiSServiceBrowser *sb = NULL;
646
int returncode = EXIT_SUCCESS;
647
const char *interface = "eth0";
650
static struct option long_options[] = {
651
{"debug", no_argument, (int *)&debug, 1},
652
{"interface", required_argument, 0, 'i'},
653
{"certdir", required_argument, 0, 'd'},
654
{"certkey", required_argument, 0, 'c'},
655
{"certfile", required_argument, 0, 'k'},
658
int option_index = 0;
659
ret = getopt_long (argc, argv, "i:", long_options,
686
certfile = combinepath(certdir, certfile);
687
if (certfile == NULL){
691
certkey = combinepath(certdir, certkey);
692
if (certkey == NULL){
697
avahi_set_log_function(empty_log);
700
/* Initialize the psuedo-RNG */
701
srand((unsigned int) time(NULL));
703
/* Allocate main loop object */
704
if (!(simple_poll = avahi_simple_poll_new())) {
705
fprintf(stderr, "Failed to create simple poll object.\n");
710
/* Do not publish any local records */
1799
711
avahi_server_config_init(&config);
1800
712
config.publish_hinfo = 0;
1801
713
config.publish_addresses = 0;
1802
714
config.publish_workstation = 0;
1803
715
config.publish_domain = 0;
1805
717
/* 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 */
718
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
719
&config, NULL, NULL, &error);
721
/* Free the configuration data */
1811
722
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());
724
/* Check if creating the server object succeeded */
726
fprintf(stderr, "Failed to create server: %s\n",
727
avahi_strerror(error));
728
returncode = EXIT_FAILURE;
732
/* Create the service browser */
733
sb = avahi_s_service_browser_new(server,
735
if_nametoindex(interface),
737
"_mandos._tcp", NULL, 0,
738
browse_callback, server);
740
fprintf(stderr, "Failed to create service browser: %s\n",
741
avahi_strerror(avahi_server_errno(server)));
742
returncode = EXIT_FAILURE;
746
/* Run the main loop */
749
fprintf(stderr, "Starting avahi loop search\n");
752
avahi_simple_poll_loop(simple_poll);
757
fprintf(stderr, "%s exiting\n", argv[0]);
762
avahi_s_service_browser_free(sb);
765
avahi_server_free(server);
768
avahi_simple_poll_free(simple_poll);