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"
71
static int dh_bits = 1024;
73
static const char *keydir = "/conf/conf.d/mandos";
74
static const char *pubkeyfile = "pubkey.txt";
75
static const char *seckeyfile = "seckey.txt";
126
77
bool debug = false;
127
static const char mandos_protocol_version[] = "1";
128
const char *argp_program_version = "mandos-client " VERSION;
129
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
130
static const char sys_class_net[] = "/sys/class/net";
131
char *connect_to = NULL;
133
/* Used for passing in values through the Avahi callback functions */
135
AvahiSimplePoll *simple_poll;
81
gnutls_session_t session;
137
82
gnutls_certificate_credentials_t cred;
138
unsigned int dh_bits;
139
83
gnutls_dh_params_t dh_params;
140
const char *priority;
87
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
90
gpgme_data_t dh_crypto, dh_plain;
144
/* global context so signal handler can reach it*/
145
mandos_context mc = { .simple_poll = NULL, .server = NULL,
146
.dh_bits = 1024, .priority = "SECURE256"
147
":!CTYPE-X.509:+CTYPE-OPENPGP" };
149
sig_atomic_t quit_now = 0;
150
int signal_received = 0;
153
* Make additional room in "buffer" for at least BUFFER_SIZE more
154
* bytes. "buffer_capacity" is how much is currently allocated,
155
* "buffer_length" is how much is already used.
157
size_t incbuffer(char **buffer, size_t buffer_length,
158
size_t buffer_capacity){
159
if(buffer_length + BUFFER_SIZE > buffer_capacity){
160
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
164
buffer_capacity += BUFFER_SIZE;
166
return buffer_capacity;
172
static bool init_gpgme(const char *seckey,
173
const char *pubkey, const char *tempdir){
94
ssize_t new_packet_capacity = 0;
95
ssize_t new_packet_length = 0;
175
96
gpgme_engine_info_t engine_info;
179
* Helper function to insert pub and seckey to the engine keyring.
181
bool import_key(const char *filename){
184
gpgme_data_t pgp_data;
186
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
192
rc = gpgme_data_new_from_fd(&pgp_data, fd);
193
if(rc != GPG_ERR_NO_ERROR){
194
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
195
gpgme_strsource(rc), gpgme_strerror(rc));
199
rc = gpgme_op_import(mc.ctx, pgp_data);
200
if(rc != GPG_ERR_NO_ERROR){
201
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
202
gpgme_strsource(rc), gpgme_strerror(rc));
206
ret = (int)TEMP_FAILURE_RETRY(close(fd));
210
gpgme_data_release(pgp_data);
215
fprintf(stderr, "Initializing GPGME\n");
99
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
219
103
gpgme_check_version(NULL);
220
104
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
221
if(rc != GPG_ERR_NO_ERROR){
105
if (rc != GPG_ERR_NO_ERROR){
222
106
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
223
107
gpgme_strsource(rc), gpgme_strerror(rc));
227
/* Set GPGME home directory for the OpenPGP engine only */
228
rc = gpgme_get_engine_info(&engine_info);
229
if(rc != GPG_ERR_NO_ERROR){
111
/* Set GPGME home directory */
112
rc = gpgme_get_engine_info (&engine_info);
113
if (rc != GPG_ERR_NO_ERROR){
230
114
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
231
115
gpgme_strsource(rc), gpgme_strerror(rc));
234
118
while(engine_info != NULL){
235
119
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
236
120
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
237
engine_info->file_name, tempdir);
121
engine_info->file_name, homedir);
240
124
engine_info = engine_info->next;
242
126
if(engine_info == NULL){
243
fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
247
/* Create new GPGME "context" */
248
rc = gpgme_new(&(mc.ctx));
249
if(rc != GPG_ERR_NO_ERROR){
250
fprintf(stderr, "bad gpgme_new: %s: %s\n",
251
gpgme_strsource(rc), gpgme_strerror(rc));
255
if(not import_key(pubkey) or not import_key(seckey)){
263
* Decrypt OpenPGP data.
264
* Returns -1 on error
266
static ssize_t pgp_packet_decrypt(const char *cryptotext,
269
gpgme_data_t dh_crypto, dh_plain;
272
size_t plaintext_capacity = 0;
273
ssize_t plaintext_length = 0;
276
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
279
/* Create new GPGME data buffer from memory cryptotext */
280
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
282
if(rc != GPG_ERR_NO_ERROR){
127
fprintf(stderr, "Could not set home dir to %s\n", homedir);
131
/* Create new GPGME data buffer from packet buffer */
132
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
133
if (rc != GPG_ERR_NO_ERROR){
283
134
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
284
135
gpgme_strsource(rc), gpgme_strerror(rc));
334
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
197
/* Delete the GPGME FILE pointer cryptotext data buffer */
198
gpgme_data_release(dh_crypto);
337
200
/* Seek back to the beginning of the GPGME plaintext data buffer */
338
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
339
perror("gpgme_data_seek");
340
plaintext_length = -1;
201
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
202
perror("pgpme_data_seek");
346
plaintext_capacity = incbuffer(plaintext,
347
(size_t)plaintext_length,
349
if(plaintext_capacity == 0){
351
plaintext_length = -1;
207
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
208
*new_packet = realloc(*new_packet,
209
(unsigned int)new_packet_capacity
211
if (*new_packet == NULL){
215
new_packet_capacity += BUFFER_SIZE;
355
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
218
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
357
220
/* Print the data, if any */
363
225
perror("gpgme_data_read");
364
plaintext_length = -1;
367
plaintext_length += ret;
371
fprintf(stderr, "Decrypted password is: ");
372
for(ssize_t i = 0; i < plaintext_length; i++){
373
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
375
fprintf(stderr, "\n");
380
/* Delete the GPGME cryptotext data buffer */
381
gpgme_data_release(dh_crypto);
228
new_packet_length += ret;
231
/* FIXME: check characters before printing to screen so to not print
232
terminal control characters */
234
/* fprintf(stderr, "decrypted password is: "); */
235
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
236
/* fprintf(stderr, "\n"); */
383
239
/* Delete the GPGME plaintext data buffer */
384
240
gpgme_data_release(dh_plain);
385
return plaintext_length;
241
return new_packet_length;
388
static const char * safer_gnutls_strerror(int value){
389
const char *ret = gnutls_strerror(value); /* Spurious warning from
390
-Wunreachable-code */
244
static const char * safer_gnutls_strerror (int value) {
245
const char *ret = gnutls_strerror (value);
392
247
ret = "(unknown)";
396
/* GnuTLS log function callback */
397
251
static void debuggnutls(__attribute__((unused)) int level,
398
252
const char* string){
399
fprintf(stderr, "GnuTLS: %s", string);
253
fprintf(stderr, "%s", string);
402
static int init_gnutls_global(const char *pubkeyfilename,
403
const char *seckeyfilename){
256
static int initgnutls(encrypted_session *es){
407
261
fprintf(stderr, "Initializing GnuTLS\n");
410
ret = gnutls_global_init();
411
if(ret != GNUTLS_E_SUCCESS){
412
fprintf(stderr, "GnuTLS global_init: %s\n",
413
safer_gnutls_strerror(ret));
264
if ((ret = gnutls_global_init ())
265
!= GNUTLS_E_SUCCESS) {
266
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
418
/* "Use a log level over 10 to enable all debugging options."
421
271
gnutls_global_set_log_level(11);
422
272
gnutls_global_set_log_function(debuggnutls);
425
/* OpenPGP credentials */
426
gnutls_certificate_allocate_credentials(&mc.cred);
427
if(ret != GNUTLS_E_SUCCESS){
428
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
432
safer_gnutls_strerror(ret));
433
gnutls_global_deinit();
275
/* openpgp credentials */
276
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
277
!= GNUTLS_E_SUCCESS) {
278
fprintf (stderr, "memory error: %s\n",
279
safer_gnutls_strerror(ret));
438
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
439
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
284
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
285
" and keyfile %s as GnuTLS credentials\n", pubkeyfile,
443
289
ret = gnutls_certificate_set_openpgp_key_file
444
(mc.cred, pubkeyfilename, seckeyfilename,
445
GNUTLS_OPENPGP_FMT_BASE64);
446
if(ret != GNUTLS_E_SUCCESS){
448
"Error[%d] while reading the OpenPGP key pair ('%s',"
449
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
450
fprintf(stderr, "The GnuTLS error is: %s\n",
451
safer_gnutls_strerror(ret));
455
/* GnuTLS server initialization */
456
ret = gnutls_dh_params_init(&mc.dh_params);
457
if(ret != GNUTLS_E_SUCCESS){
458
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
459
" %s\n", safer_gnutls_strerror(ret));
462
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
463
if(ret != GNUTLS_E_SUCCESS){
464
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
465
safer_gnutls_strerror(ret));
469
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
475
gnutls_certificate_free_credentials(mc.cred);
476
gnutls_global_deinit();
477
gnutls_dh_params_deinit(mc.dh_params);
481
static int init_gnutls_session(gnutls_session_t *session){
483
/* GnuTLS session creation */
485
ret = gnutls_init(session, GNUTLS_SERVER);
489
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
490
if(ret != GNUTLS_E_SUCCESS){
290
(es->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
291
if (ret != GNUTLS_E_SUCCESS) {
293
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
295
ret, pubkeyfile, seckeyfile);
296
fprintf(stdout, "The Error is: %s\n",
297
safer_gnutls_strerror(ret));
301
//GnuTLS server initialization
302
if ((ret = gnutls_dh_params_init (&es->dh_params))
303
!= GNUTLS_E_SUCCESS) {
304
fprintf (stderr, "Error in dh parameter initialization: %s\n",
305
safer_gnutls_strerror(ret));
309
if ((ret = gnutls_dh_params_generate2 (es->dh_params, dh_bits))
310
!= GNUTLS_E_SUCCESS) {
311
fprintf (stderr, "Error in prime generation: %s\n",
312
safer_gnutls_strerror(ret));
316
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
318
// GnuTLS session creation
319
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
320
!= GNUTLS_E_SUCCESS){
491
321
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
492
322
safer_gnutls_strerror(ret));
498
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
500
gnutls_deinit(*session);
503
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
504
if(ret != GNUTLS_E_SUCCESS){
505
fprintf(stderr, "Syntax error at: %s\n", err);
506
fprintf(stderr, "GnuTLS error: %s\n",
507
safer_gnutls_strerror(ret));
508
gnutls_deinit(*session);
325
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
326
!= GNUTLS_E_SUCCESS) {
327
fprintf(stderr, "Syntax error at: %s\n", err);
328
fprintf(stderr, "GnuTLS error: %s\n",
329
safer_gnutls_strerror(ret));
514
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
517
gnutls_deinit(*session);
520
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
521
if(ret != GNUTLS_E_SUCCESS){
522
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
333
if ((ret = gnutls_credentials_set
334
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
335
!= GNUTLS_E_SUCCESS) {
336
fprintf(stderr, "Error setting a credentials set: %s\n",
523
337
safer_gnutls_strerror(ret));
524
gnutls_deinit(*session);
528
341
/* ignore client certificate if any. */
529
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
342
gnutls_certificate_server_set_request (es->session,
531
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
345
gnutls_dh_set_prime_bits (es->session, dh_bits);
536
/* Avahi log function callback */
537
350
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
538
351
__attribute__((unused)) const char *txt){}
540
/* Called when a Mandos server is found */
541
353
static int start_mandos_communication(const char *ip, uint16_t port,
542
AvahiIfIndex if_index,
544
int ret, tcp_sd = -1;
547
struct sockaddr_in in;
548
struct sockaddr_in6 in6;
354
AvahiIfIndex if_index){
356
struct sockaddr_in6 to;
357
encrypted_session es;
550
358
char *buffer = NULL;
551
char *decrypted_buffer = NULL;
359
char *decrypted_buffer;
552
360
size_t buffer_length = 0;
553
361
size_t buffer_capacity = 0;
556
gnutls_session_t session;
557
int pf; /* Protocol family */
574
fprintf(stderr, "Bad address family: %d\n", af);
579
ret = init_gnutls_session(&session);
362
ssize_t decrypted_buffer_size;
365
char interface[IF_NAMESIZE];
585
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
368
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
589
tcp_sd = socket(pf, SOCK_STREAM, 0);
372
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
592
374
perror("socket");
602
memset(&to, 0, sizeof(to));
604
to.in6.sin6_family = (sa_family_t)af;
605
ret = inet_pton(af, ip, &to.in6.sin6_addr);
607
to.in.sin_family = (sa_family_t)af;
608
ret = inet_pton(af, ip, &to.in.sin_addr);
378
if(if_indextoname((unsigned int)if_index, interface) == NULL){
380
perror("if_indextoname");
386
fprintf(stderr, "Binding to interface %s\n", interface);
389
memset(&to,0,sizeof(to)); /* Spurious warning */
390
to.sin6_family = AF_INET6;
391
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
612
393
perror("inet_pton");
618
397
fprintf(stderr, "Bad address: %s\n", ip);
623
to.in6.sin6_port = htons(port); /* Spurious warnings from
625
-Wunreachable-code */
627
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
628
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
630
if(if_index == AVAHI_IF_UNSPEC){
631
fprintf(stderr, "An IPv6 link-local address is incomplete"
632
" without a network interface\n");
636
/* Set the network interface number as scope */
637
to.in6.sin6_scope_id = (uint32_t)if_index;
640
to.in.sin_port = htons(port); /* Spurious warnings from
642
-Wunreachable-code */
400
to.sin6_port = htons(port); /* Spurious warning */
402
to.sin6_scope_id = (uint32_t)if_index;
651
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
652
char interface[IF_NAMESIZE];
653
if(if_indextoname((unsigned int)if_index, interface) == NULL){
654
perror("if_indextoname");
656
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
657
ip, interface, port);
660
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
663
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
664
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
667
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
670
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
405
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
406
char addrstr[INET6_ADDRSTRLEN] = "";
407
if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr,
408
sizeof(addrstr)) == NULL){
674
409
perror("inet_ntop");
676
411
if(strcmp(addrstr, ip) != 0){
677
fprintf(stderr, "Canonical address form: %s\n", addrstr);
688
ret = connect(tcp_sd, &to.in6, sizeof(to));
690
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
693
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
706
const char *out = mandos_protocol_version;
709
size_t out_size = strlen(out);
710
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
711
out_size - written));
718
written += (size_t)ret;
719
if(written < out_size){
722
if(out == mandos_protocol_version){
412
fprintf(stderr, "Canonical address form: %s\n",
413
addrstr, ntohs(to.sin6_port));
418
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
424
ret = initgnutls (&es);
430
gnutls_transport_set_ptr (es.session,
431
(gnutls_transport_ptr_t) tcp_sd);
737
434
fprintf(stderr, "Establishing TLS session with %s\n", ip);
745
/* Spurious warnings from -Wint-to-pointer-cast */
746
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
754
ret = gnutls_handshake(session);
759
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
761
if(ret != GNUTLS_E_SUCCESS){
437
ret = gnutls_handshake (es.session);
439
if (ret != GNUTLS_E_SUCCESS){
763
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
441
fprintf(stderr, "\n*** Handshake failed ***\n");
770
/* Read OpenPGP packet that contains the wanted password */
448
//Retrieve OpenPGP packet that contains the wanted password
773
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
451
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
784
buffer_capacity = incbuffer(&buffer, buffer_length,
786
if(buffer_capacity == 0){
798
sret = gnutls_record_recv(session, buffer+buffer_length,
456
if (buffer_length + BUFFER_SIZE > buffer_capacity){
457
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
462
buffer_capacity += BUFFER_SIZE;
465
ret = gnutls_record_recv
466
(es.session, buffer+buffer_length, BUFFER_SIZE);
805
472
case GNUTLS_E_INTERRUPTED:
806
473
case GNUTLS_E_AGAIN:
808
475
case GNUTLS_E_REHANDSHAKE:
810
ret = gnutls_handshake(session);
816
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
818
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
476
ret = gnutls_handshake (es.session);
478
fprintf(stderr, "\n*** Handshake failed ***\n");
825
485
fprintf(stderr, "Unknown error while reading data from"
826
" encrypted session with Mandos server\n");
827
gnutls_bye(session, GNUTLS_SHUT_RDWR);
486
" encrypted session with mandos server\n");
488
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
832
buffer_length += (size_t) sret;
837
fprintf(stderr, "Closing TLS session\n");
846
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
851
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
853
if(buffer_length > 0){
854
ssize_t decrypted_buffer_size;
492
buffer_length += (size_t) ret;
496
if (buffer_length > 0){
855
497
decrypted_buffer_size = pgp_packet_decrypt(buffer,
858
if(decrypted_buffer_size >= 0){
501
if (decrypted_buffer_size >= 0){
861
502
while(written < (size_t) decrypted_buffer_size){
867
ret = (int)fwrite(decrypted_buffer + written, 1,
868
(size_t)decrypted_buffer_size - written,
503
ret = (int)fwrite (decrypted_buffer + written, 1,
504
(size_t)decrypted_buffer_size - written,
870
506
if(ret == 0 and ferror(stdout)){
873
508
fprintf(stderr, "Error writing encrypted data: %s\n",
874
509
strerror(errno));
879
514
written += (size_t)ret;
885
/* Shutdown procedure */
890
free(decrypted_buffer);
893
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
901
gnutls_deinit(session);
516
free(decrypted_buffer);
525
fprintf(stderr, "Closing TLS session\n");
529
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
532
gnutls_deinit (es.session);
533
gnutls_certificate_free_credentials (es.cred);
534
gnutls_global_deinit ();
911
static void resolve_callback(AvahiSServiceResolver *r,
912
AvahiIfIndex interface,
914
AvahiResolverEvent event,
918
const char *host_name,
919
const AvahiAddress *address,
921
AVAHI_GCC_UNUSED AvahiStringList *txt,
922
AVAHI_GCC_UNUSED AvahiLookupResultFlags
924
AVAHI_GCC_UNUSED void* userdata){
538
static AvahiSimplePoll *simple_poll = NULL;
539
static AvahiServer *server = NULL;
541
static void resolve_callback(
542
AvahiSServiceResolver *r,
543
AvahiIfIndex interface,
544
AVAHI_GCC_UNUSED AvahiProtocol protocol,
545
AvahiResolverEvent event,
549
const char *host_name,
550
const AvahiAddress *address,
552
AVAHI_GCC_UNUSED AvahiStringList *txt,
553
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
554
AVAHI_GCC_UNUSED void* userdata) {
556
assert(r); /* Spurious warning */
927
558
/* Called whenever a service has been resolved successfully or
936
563
case AVAHI_RESOLVER_FAILURE:
937
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
938
" of type '%s' in domain '%s': %s\n", name, type, domain,
939
avahi_strerror(avahi_server_errno(mc.server)));
564
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
565
" type '%s' in domain '%s': %s\n", name, type, domain,
566
avahi_strerror(avahi_server_errno(server)));
942
569
case AVAHI_RESOLVER_FOUND:
944
571
char ip[AVAHI_ADDRESS_STR_MAX];
945
572
avahi_address_snprint(ip, sizeof(ip), address);
947
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
948
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
949
ip, (intmax_t)interface, port);
574
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
575
" port %d\n", name, host_name, ip, port);
951
int ret = start_mandos_communication(ip, port, interface,
952
avahi_proto_to_af(proto));
954
avahi_simple_poll_quit(mc.simple_poll);
577
int ret = start_mandos_communication(ip, port, interface);
958
583
avahi_s_service_resolver_free(r);
961
static void browse_callback(AvahiSServiceBrowser *b,
962
AvahiIfIndex interface,
963
AvahiProtocol protocol,
964
AvahiBrowserEvent event,
968
AVAHI_GCC_UNUSED AvahiLookupResultFlags
970
AVAHI_GCC_UNUSED void* userdata){
973
/* Called whenever a new services becomes available on the LAN or
974
is removed from the LAN */
982
case AVAHI_BROWSER_FAILURE:
984
fprintf(stderr, "(Avahi browser) %s\n",
985
avahi_strerror(avahi_server_errno(mc.server)));
986
avahi_simple_poll_quit(mc.simple_poll);
989
case AVAHI_BROWSER_NEW:
990
/* We ignore the returned Avahi resolver object. In the callback
991
function we free it. If the Avahi server is terminated before
992
the callback function is called the Avahi server will free the
995
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
996
name, type, domain, protocol, 0,
997
resolve_callback, NULL) == NULL)
998
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
999
name, avahi_strerror(avahi_server_errno(mc.server)));
1002
case AVAHI_BROWSER_REMOVE:
1005
case AVAHI_BROWSER_ALL_FOR_NOW:
1006
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1008
fprintf(stderr, "No Mandos server found, still searching...\n");
1014
/* stop main loop after sigterm has been called */
1015
static void handle_sigterm(int sig){
1020
signal_received = sig;
1021
int old_errno = errno;
1022
if(mc.simple_poll != NULL){
1023
avahi_simple_poll_quit(mc.simple_poll);
1029
* This function determines if a directory entry in /sys/class/net
1030
* corresponds to an acceptable network device.
1031
* (This function is passed to scandir(3) as a filter function.)
1033
int good_interface(const struct dirent *if_entry){
1035
char *flagname = NULL;
1036
if(if_entry->d_name[0] == '.'){
1039
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1045
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1052
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1053
/* read line from flags_fd */
1054
ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1055
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1056
flagstring[(size_t)to_read] = '\0';
1057
if(flagstring == NULL){
1063
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1080
tmpmax = strtoimax(flagstring, &tmp, 0);
1081
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1082
and not (isspace(*tmp)))
1083
or tmpmax != (ifreq_flags)tmpmax){
1085
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1086
flagstring, if_entry->d_name);
1092
ifreq_flags flags = (ifreq_flags)tmpmax;
1093
/* Reject the loopback device */
1094
if(flags & IFF_LOOPBACK){
1096
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1101
/* Accept point-to-point devices only if connect_to is specified */
1102
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1104
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1109
/* Otherwise, reject non-broadcast-capable devices */
1110
if(not (flags & IFF_BROADCAST)){
1112
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1117
/* Reject non-ARP interfaces (including dummy interfaces) */
1118
if(flags & IFF_NOARP){
1120
fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n",
1125
/* Accept this device */
1127
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1133
int notdotentries(const struct dirent *direntry){
1134
/* Skip "." and ".." */
1135
if(direntry->d_name[0] == '.'
1136
and (direntry->d_name[1] == '\0'
1137
or (direntry->d_name[1] == '.'
1138
and direntry->d_name[2] == '\0'))){
1144
int main(int argc, char *argv[]){
1145
AvahiSServiceBrowser *sb = NULL;
1150
int exitcode = EXIT_SUCCESS;
1151
const char *interface = "";
1152
struct ifreq network;
1154
bool take_down_interface = false;
1157
char tempdir[] = "/tmp/mandosXXXXXX";
1158
bool tempdir_created = false;
1159
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1160
const char *seckey = PATHDIR "/" SECKEY;
1161
const char *pubkey = PATHDIR "/" PUBKEY;
1163
bool gnutls_initialized = false;
1164
bool gpgme_initialized = false;
1167
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1168
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1173
/* Lower any group privileges we might have, just to be safe */
1180
/* Lower user privileges (temporarily) */
1192
struct argp_option options[] = {
1193
{ .name = "debug", .key = 128,
1194
.doc = "Debug mode", .group = 3 },
1195
{ .name = "connect", .key = 'c',
1196
.arg = "ADDRESS:PORT",
1197
.doc = "Connect directly to a specific Mandos server",
1199
{ .name = "interface", .key = 'i',
1201
.doc = "Network interface that will be used to search for"
1204
{ .name = "seckey", .key = 's',
1206
.doc = "OpenPGP secret key file base name",
1208
{ .name = "pubkey", .key = 'p',
1210
.doc = "OpenPGP public key file base name",
1212
{ .name = "dh-bits", .key = 129,
1214
.doc = "Bit length of the prime number used in the"
1215
" Diffie-Hellman key exchange",
1217
{ .name = "priority", .key = 130,
1219
.doc = "GnuTLS priority string for the TLS handshake",
1221
{ .name = "delay", .key = 131,
1223
.doc = "Maximum delay to wait for interface startup",
1226
* These reproduce what we would get without ARGP_NO_HELP
1228
{ .name = "help", .key = '?',
1229
.doc = "Give this help list", .group = -1 },
1230
{ .name = "usage", .key = -3,
1231
.doc = "Give a short usage message", .group = -1 },
1232
{ .name = "version", .key = 'V',
1233
.doc = "Print program version", .group = -1 },
1237
error_t parse_opt(int key, char *arg,
1238
struct argp_state *state){
1241
case 128: /* --debug */
1244
case 'c': /* --connect */
1247
case 'i': /* --interface */
1250
case 's': /* --seckey */
1253
case 'p': /* --pubkey */
1256
case 129: /* --dh-bits */
1258
tmpmax = strtoimax(arg, &tmp, 10);
1259
if(errno != 0 or tmp == arg or *tmp != '\0'
1260
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1261
argp_error(state, "Bad number of DH bits");
1263
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1265
case 130: /* --priority */
1268
case 131: /* --delay */
1270
delay = strtof(arg, &tmp);
1271
if(errno != 0 or tmp == arg or *tmp != '\0'){
1272
argp_error(state, "Bad delay");
1276
* These reproduce what we would get without ARGP_NO_HELP
1278
case '?': /* --help */
1279
argp_state_help(state, state->out_stream,
1280
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1281
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1282
case -3: /* --usage */
1283
argp_state_help(state, state->out_stream,
1284
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1285
case 'V': /* --version */
1286
fprintf(state->out_stream, "%s\n", argp_program_version);
1287
exit(argp_err_exit_status);
1290
return ARGP_ERR_UNKNOWN;
1295
struct argp argp = { .options = options, .parser = parse_opt,
1297
.doc = "Mandos client -- Get and decrypt"
1298
" passwords from a Mandos server" };
1299
ret = argp_parse(&argp, argc, argv,
1300
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
586
static void browse_callback(
587
AvahiSServiceBrowser *b,
588
AvahiIfIndex interface,
589
AvahiProtocol protocol,
590
AvahiBrowserEvent event,
594
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
597
AvahiServer *s = userdata;
598
assert(b); /* Spurious warning */
600
/* Called whenever a new services becomes available on the LAN or
601
is removed from the LAN */
1307
perror("argp_parse");
1308
exitcode = EX_OSERR;
1311
exitcode = EX_USAGE;
1317
avahi_set_log_function(empty_log);
1320
if(interface[0] == '\0'){
1321
struct dirent **direntries;
1322
ret = scandir(sys_class_net, &direntries, good_interface,
1325
/* Pick the first good interface */
1326
interface = strdup(direntries[0]->d_name);
1328
fprintf(stderr, "Using interface \"%s\"\n", interface);
1330
if(interface == NULL){
1333
exitcode = EXIT_FAILURE;
1339
fprintf(stderr, "Could not find a network interface\n");
1340
exitcode = EXIT_FAILURE;
1345
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1346
from the signal handler */
1347
/* Initialize the pseudo-RNG for Avahi */
1348
srand((unsigned int) time(NULL));
1349
mc.simple_poll = avahi_simple_poll_new();
1350
if(mc.simple_poll == NULL){
1351
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1352
exitcode = EX_UNAVAILABLE;
1356
sigemptyset(&sigterm_action.sa_mask);
1357
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1359
perror("sigaddset");
1360
exitcode = EX_OSERR;
1363
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1365
perror("sigaddset");
1366
exitcode = EX_OSERR;
1369
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1371
perror("sigaddset");
1372
exitcode = EX_OSERR;
1375
/* Need to check if the handler is SIG_IGN before handling:
1376
| [[info:libc:Initial Signal Actions]] |
1377
| [[info:libc:Basic Signal Handling]] |
1379
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1381
perror("sigaction");
1384
if(old_sigterm_action.sa_handler != SIG_IGN){
1385
ret = sigaction(SIGINT, &sigterm_action, NULL);
1387
perror("sigaction");
1388
exitcode = EX_OSERR;
1392
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1394
perror("sigaction");
1397
if(old_sigterm_action.sa_handler != SIG_IGN){
1398
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1400
perror("sigaction");
1401
exitcode = EX_OSERR;
1405
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1407
perror("sigaction");
1410
if(old_sigterm_action.sa_handler != SIG_IGN){
1411
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1413
perror("sigaction");
1414
exitcode = EX_OSERR;
1419
/* If the interface is down, bring it up */
1420
if(strcmp(interface, "none") != 0){
1421
if_index = (AvahiIfIndex) if_nametoindex(interface);
1423
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1424
exitcode = EX_UNAVAILABLE;
1432
/* Re-raise priviliges */
1440
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1441
messages about the network interface to mess up the prompt */
1442
ret = klogctl(8, NULL, 5);
1443
bool restore_loglevel = true;
1445
restore_loglevel = false;
1448
#endif /* __linux__ */
1450
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1453
exitcode = EX_OSERR;
1455
if(restore_loglevel){
1456
ret = klogctl(7, NULL, 0);
1461
#endif /* __linux__ */
1462
/* Lower privileges */
1470
strcpy(network.ifr_name, interface);
1471
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1473
perror("ioctl SIOCGIFFLAGS");
1475
if(restore_loglevel){
1476
ret = klogctl(7, NULL, 0);
1481
#endif /* __linux__ */
1482
exitcode = EX_OSERR;
1483
/* Lower privileges */
1491
if((network.ifr_flags & IFF_UP) == 0){
1492
network.ifr_flags |= IFF_UP;
1493
take_down_interface = true;
1494
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1496
take_down_interface = false;
1497
perror("ioctl SIOCSIFFLAGS +IFF_UP");
1498
exitcode = EX_OSERR;
1500
if(restore_loglevel){
1501
ret = klogctl(7, NULL, 0);
1506
#endif /* __linux__ */
1507
/* Lower privileges */
1516
/* sleep checking until interface is running */
1517
for(int i=0; i < delay * 4; i++){
1518
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1520
perror("ioctl SIOCGIFFLAGS");
1521
} else if(network.ifr_flags & IFF_RUNNING){
1524
struct timespec sleeptime = { .tv_nsec = 250000000 };
1525
ret = nanosleep(&sleeptime, NULL);
1526
if(ret == -1 and errno != EINTR){
1527
perror("nanosleep");
1530
if(not take_down_interface){
1531
/* We won't need the socket anymore */
1532
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1538
if(restore_loglevel){
1539
/* Restores kernel loglevel to default */
1540
ret = klogctl(7, NULL, 0);
1545
#endif /* __linux__ */
1546
/* Lower privileges */
1548
if(take_down_interface){
1549
/* Lower privileges */
1555
/* Lower privileges permanently */
1567
ret = init_gnutls_global(pubkey, seckey);
1569
fprintf(stderr, "init_gnutls_global failed\n");
1570
exitcode = EX_UNAVAILABLE;
1573
gnutls_initialized = true;
1580
if(mkdtemp(tempdir) == NULL){
1584
tempdir_created = true;
1590
if(not init_gpgme(pubkey, seckey, tempdir)){
1591
fprintf(stderr, "init_gpgme failed\n");
1592
exitcode = EX_UNAVAILABLE;
1595
gpgme_initialized = true;
1602
if(connect_to != NULL){
1603
/* Connect directly, do not use Zeroconf */
1604
/* (Mainly meant for debugging) */
1605
char *address = strrchr(connect_to, ':');
1606
if(address == NULL){
1607
fprintf(stderr, "No colon in address\n");
1608
exitcode = EX_USAGE;
1618
tmpmax = strtoimax(address+1, &tmp, 10);
1619
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1620
or tmpmax != (uint16_t)tmpmax){
1621
fprintf(stderr, "Bad port number\n");
1622
exitcode = EX_USAGE;
1630
port = (uint16_t)tmpmax;
1632
address = connect_to;
1633
/* Colon in address indicates IPv6 */
1635
if(strchr(address, ':') != NULL){
1645
while(not quit_now){
1646
ret = start_mandos_communication(address, port, if_index, af);
1647
if(quit_now or ret == 0){
1654
exitcode = EXIT_SUCCESS;
605
case AVAHI_BROWSER_FAILURE:
607
fprintf(stderr, "(Browser) %s\n",
608
avahi_strerror(avahi_server_errno(server)));
609
avahi_simple_poll_quit(simple_poll);
612
case AVAHI_BROWSER_NEW:
613
/* We ignore the returned resolver object. In the callback
614
function we free it. If the server is terminated before
615
the callback function is called the server will free
616
the resolver for us. */
618
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
620
AVAHI_PROTO_INET6, 0,
621
resolve_callback, s)))
622
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
623
avahi_strerror(avahi_server_errno(s)));
626
case AVAHI_BROWSER_REMOVE:
629
case AVAHI_BROWSER_ALL_FOR_NOW:
630
case AVAHI_BROWSER_CACHE_EXHAUSTED:
635
/* Combines file name and path and returns the malloced new
636
string. some sane checks could/should be added */
637
static const char *combinepath(const char *first, const char *second){
638
size_t f_len = strlen(first);
639
size_t s_len = strlen(second);
640
char *tmp = malloc(f_len + s_len + 2);
645
memcpy(tmp, first, f_len);
649
memcpy(tmp + f_len + 1, second, s_len);
651
tmp[f_len + 1 + s_len] = '\0';
656
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1665
657
AvahiServerConfig config;
1666
/* Do not publish any local Zeroconf records */
658
AvahiSServiceBrowser *sb = NULL;
662
int returncode = EXIT_SUCCESS;
663
const char *interface = NULL;
664
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
665
char *connect_to = NULL;
667
debug_int = debug ? 1 : 0;
669
static struct option long_options[] = {
670
{"debug", no_argument, &debug_int, 1},
671
{"connect", required_argument, NULL, 'C'},
672
{"interface", required_argument, NULL, 'i'},
673
{"keydir", required_argument, NULL, 'd'},
674
{"seckey", required_argument, NULL, 'c'},
675
{"pubkey", required_argument, NULL, 'k'},
676
{"dh-bits", required_argument, NULL, 'D'},
679
int option_index = 0;
680
ret = getopt_long (argc, argv, "i:", long_options,
706
dh_bits = atoi(optarg);
714
debug = debug_int ? true : false;
716
pubkeyfile = combinepath(keydir, pubkeyfile);
717
if (pubkeyfile == NULL){
718
perror("combinepath");
722
if(interface != NULL){
723
if_index = (AvahiIfIndex) if_nametoindex(interface);
725
fprintf(stderr, "No such interface: \"%s\"\n", interface);
730
if(connect_to != NULL){
731
/* Connect directly, do not use Zeroconf */
732
/* (Mainly meant for debugging) */
733
char *address = strrchr(connect_to, ':');
735
fprintf(stderr, "No colon in address\n");
739
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
741
perror("Bad port number");
745
address = connect_to;
746
ret = start_mandos_communication(address, port, if_index);
754
seckeyfile = combinepath(keydir, seckeyfile);
755
if (seckeyfile == NULL){
756
perror("combinepath");
761
avahi_set_log_function(empty_log);
764
/* Initialize the psuedo-RNG */
765
srand((unsigned int) time(NULL));
767
/* Allocate main loop object */
768
if (!(simple_poll = avahi_simple_poll_new())) {
769
fprintf(stderr, "Failed to create simple poll object.\n");
774
/* Do not publish any local records */
1667
775
avahi_server_config_init(&config);
1668
776
config.publish_hinfo = 0;
1669
777
config.publish_addresses = 0;
1670
778
config.publish_workstation = 0;
1671
779
config.publish_domain = 0;
1673
781
/* Allocate a new server */
1674
mc.server = avahi_server_new(avahi_simple_poll_get
1675
(mc.simple_poll), &config, NULL,
1678
/* Free the Avahi configuration data */
782
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
783
&config, NULL, NULL, &error);
785
/* Free the configuration data */
1679
786
avahi_server_config_free(&config);
1682
/* Check if creating the Avahi server object succeeded */
1683
if(mc.server == NULL){
1684
fprintf(stderr, "Failed to create Avahi server: %s\n",
1685
avahi_strerror(error));
1686
exitcode = EX_UNAVAILABLE;
1694
/* Create the Avahi service browser */
1695
sb = avahi_s_service_browser_new(mc.server, if_index,
1696
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1697
NULL, 0, browse_callback, NULL);
1699
fprintf(stderr, "Failed to create service browser: %s\n",
1700
avahi_strerror(avahi_server_errno(mc.server)));
1701
exitcode = EX_UNAVAILABLE;
1709
/* Run the main loop */
1712
fprintf(stderr, "Starting Avahi loop search\n");
1715
avahi_simple_poll_loop(mc.simple_poll);
1720
fprintf(stderr, "%s exiting\n", argv[0]);
1723
/* Cleanup things */
1725
avahi_s_service_browser_free(sb);
1727
if(mc.server != NULL)
1728
avahi_server_free(mc.server);
1730
if(mc.simple_poll != NULL)
1731
avahi_simple_poll_free(mc.simple_poll);
1733
if(gnutls_initialized){
1734
gnutls_certificate_free_credentials(mc.cred);
1735
gnutls_global_deinit();
1736
gnutls_dh_params_deinit(mc.dh_params);
1739
if(gpgme_initialized){
1740
gpgme_release(mc.ctx);
1743
/* Take down the network interface */
1744
if(take_down_interface){
1745
/* Re-raise priviliges */
1752
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1754
perror("ioctl SIOCGIFFLAGS");
1755
} else if(network.ifr_flags & IFF_UP) {
1756
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1757
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1759
perror("ioctl SIOCSIFFLAGS -IFF_UP");
1762
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1766
/* Lower privileges permanently */
1775
/* Removes the GPGME temp directory and all files inside */
1776
if(tempdir_created){
1777
struct dirent **direntries = NULL;
1778
struct dirent *direntry = NULL;
1779
ret = scandir(tempdir, &direntries, notdotentries, alphasort);
1781
for(int i = 0; i < ret; i++){
1782
direntry = direntries[i];
1783
char *fullname = NULL;
1784
ret = asprintf(&fullname, "%s/%s", tempdir,
1790
ret = remove(fullname);
1792
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1799
/* need to be cleaned even if ret == 0 because man page dont specify */
1804
ret = rmdir(tempdir);
1805
if(ret == -1 and errno != ENOENT){
1811
sigemptyset(&old_sigterm_action.sa_mask);
1812
old_sigterm_action.sa_handler = SIG_DFL;
1813
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1814
&old_sigterm_action,
1817
perror("sigaction");
1820
ret = raise(signal_received);
1821
} while(ret != 0 and errno == EINTR);
1826
TEMP_FAILURE_RETRY(pause());
788
/* Check if creating the server object succeeded */
790
fprintf(stderr, "Failed to create server: %s\n",
791
avahi_strerror(error));
792
returncode = EXIT_FAILURE;
796
/* Create the service browser */
797
sb = avahi_s_service_browser_new(server, if_index,
799
"_mandos._tcp", NULL, 0,
800
browse_callback, server);
802
fprintf(stderr, "Failed to create service browser: %s\n",
803
avahi_strerror(avahi_server_errno(server)));
804
returncode = EXIT_FAILURE;
808
/* Run the main loop */
811
fprintf(stderr, "Starting avahi loop search\n");
814
avahi_simple_poll_loop(simple_poll);
819
fprintf(stderr, "%s exiting\n", argv[0]);
824
avahi_s_service_browser_free(sb);
827
avahi_server_free(server);
830
avahi_simple_poll_free(simple_poll);