26
25
* along with this program. If not, see
27
26
* <http://www.gnu.org/licenses/>.
29
* Contact the authors at <mandos@fukt.bsnet.se>.
28
* Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
29
* <https://www.fukt.bsnet.se/~teddy/>.
32
/* Needed by GPGME, specifically gpgme_data_seek() */
33
#ifndef _LARGEFILE_SOURCE
32
#define _FORTIFY_SOURCE 2
34
34
#define _LARGEFILE_SOURCE
36
#ifndef _FILE_OFFSET_BITS
37
35
#define _FILE_OFFSET_BITS 64
40
#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), asprintf() */
42
#include <stdio.h> /* fprintf(), stderr, fwrite(),
43
stdout, ferror(), remove() */
44
#include <stdint.h> /* uint16_t, uint32_t */
45
#include <stddef.h> /* NULL, size_t, ssize_t */
46
#include <stdlib.h> /* free(), EXIT_SUCCESS, EXIT_FAILURE,
47
srand(), strtof(), abort() */
48
#include <stdbool.h> /* bool, false, true */
49
#include <string.h> /* memset(), strcmp(), strlen(),
50
strerror(), asprintf(), strcpy() */
51
#include <sys/ioctl.h> /* ioctl */
52
#include <sys/types.h> /* socket(), inet_pton(), sockaddr,
53
sockaddr_in6, PF_INET6,
54
SOCK_STREAM, uid_t, gid_t, open(),
56
#include <sys/stat.h> /* open() */
57
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
58
inet_pton(), connect() */
59
#include <fcntl.h> /* open() */
60
#include <dirent.h> /* opendir(), struct dirent, readdir()
62
#include <inttypes.h> /* PRIu16, PRIdMAX, intmax_t,
64
#include <assert.h> /* assert() */
65
#include <errno.h> /* perror(), errno */
66
#include <time.h> /* nanosleep(), time() */
67
#include <net/if.h> /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
68
SIOCSIFFLAGS, if_indextoname(),
69
if_nametoindex(), IF_NAMESIZE */
70
#include <netinet/in.h> /* IN6_IS_ADDR_LINKLOCAL,
71
INET_ADDRSTRLEN, INET6_ADDRSTRLEN
73
#include <unistd.h> /* close(), SEEK_SET, off_t, write(),
74
getuid(), getgid(), seteuid(),
76
#include <arpa/inet.h> /* inet_pton(), htons */
77
#include <iso646.h> /* not, or, and */
78
#include <argp.h> /* struct argp_option, error_t, struct
79
argp_state, struct argp,
80
argp_parse(), ARGP_KEY_ARG,
81
ARGP_KEY_END, ARGP_ERR_UNKNOWN */
82
#include <signal.h> /* sigemptyset(), sigaddset(),
83
sigaction(), SIGTERM, sig_atomic_t,
87
#include <sys/klog.h> /* klogctl() */
88
#endif /* __linux__ */
91
/* All Avahi types, constants and functions
41
#include <net/if.h> /* if_nametoindex */
94
43
#include <avahi-core/core.h>
95
44
#include <avahi-core/lookup.h>
96
45
#include <avahi-core/log.h>
98
47
#include <avahi-common/malloc.h>
99
48
#include <avahi-common/error.h>
102
#include <gnutls/gnutls.h> /* All GnuTLS types, constants and
105
init_gnutls_session(),
107
#include <gnutls/openpgp.h>
108
/* gnutls_certificate_set_openpgp_key_file(),
109
GNUTLS_OPENPGP_FMT_BASE64 */
112
#include <gpgme.h> /* All GPGME types, constants and
115
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() */
72
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
74
#define CERTFILE CERT_ROOT "openpgp-client.txt"
75
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
118
76
#define BUFFER_SIZE 256
120
#define PATHDIR "/conf/conf.d/mandos"
121
#define SECKEY "seckey.txt"
122
#define PUBKEY "pubkey.txt"
124
79
bool debug = false;
125
static const char mandos_protocol_version[] = "1";
126
const char *argp_program_version = "mandos-client " VERSION;
127
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
128
static const char sys_class_net[] = "/sys/class/net";
129
char *connect_to = NULL;
131
/* Used for passing in values through the Avahi callback functions */
133
AvahiSimplePoll *simple_poll;
82
gnutls_session_t session;
135
83
gnutls_certificate_credentials_t cred;
136
unsigned int dh_bits;
137
84
gnutls_dh_params_t dh_params;
138
const char *priority;
88
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
89
char **new_packet, const char *homedir){
90
gpgme_data_t dh_crypto, dh_plain;
142
/* global context so signal handler can reach it*/
143
mandos_context mc = { .simple_poll = NULL, .server = NULL,
144
.dh_bits = 1024, .priority = "SECURE256"
145
":!CTYPE-X.509:+CTYPE-OPENPGP" };
147
sig_atomic_t quit_now = 0;
148
int signal_received = 0;
151
* Make additional room in "buffer" for at least BUFFER_SIZE more
152
* bytes. "buffer_capacity" is how much is currently allocated,
153
* "buffer_length" is how much is already used.
155
size_t incbuffer(char **buffer, size_t buffer_length,
156
size_t buffer_capacity){
157
if(buffer_length + BUFFER_SIZE > buffer_capacity){
158
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
162
buffer_capacity += BUFFER_SIZE;
164
return buffer_capacity;
170
static bool init_gpgme(const char *seckey,
171
const char *pubkey, const char *tempdir){
94
ssize_t new_packet_capacity = 0;
95
ssize_t new_packet_length = 0;
173
96
gpgme_engine_info_t engine_info;
177
* Helper function to insert pub and seckey to the engine keyring.
179
bool import_key(const char *filename){
182
gpgme_data_t pgp_data;
184
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
190
rc = gpgme_data_new_from_fd(&pgp_data, fd);
191
if(rc != GPG_ERR_NO_ERROR){
192
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
193
gpgme_strsource(rc), gpgme_strerror(rc));
197
rc = gpgme_op_import(mc.ctx, pgp_data);
198
if(rc != GPG_ERR_NO_ERROR){
199
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
200
gpgme_strsource(rc), gpgme_strerror(rc));
204
ret = (int)TEMP_FAILURE_RETRY(close(fd));
208
gpgme_data_release(pgp_data);
213
fprintf(stderr, "Initializing GPGME\n");
99
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
217
103
gpgme_check_version(NULL);
218
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
219
if(rc != GPG_ERR_NO_ERROR){
220
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
221
gpgme_strsource(rc), gpgme_strerror(rc));
104
gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
225
/* Set GPGME home directory for the OpenPGP engine only */
226
rc = gpgme_get_engine_info(&engine_info);
227
if(rc != GPG_ERR_NO_ERROR){
106
/* Set GPGME home directory */
107
rc = gpgme_get_engine_info (&engine_info);
108
if (rc != GPG_ERR_NO_ERROR){
228
109
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
229
110
gpgme_strsource(rc), gpgme_strerror(rc));
232
113
while(engine_info != NULL){
233
114
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
234
115
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
235
engine_info->file_name, tempdir);
116
engine_info->file_name, homedir);
238
119
engine_info = engine_info->next;
240
121
if(engine_info == NULL){
241
fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
245
/* Create new GPGME "context" */
246
rc = gpgme_new(&(mc.ctx));
247
if(rc != GPG_ERR_NO_ERROR){
248
fprintf(stderr, "bad gpgme_new: %s: %s\n",
249
gpgme_strsource(rc), gpgme_strerror(rc));
253
if(not import_key(pubkey) or not import_key(seckey)){
261
* Decrypt OpenPGP data.
262
* Returns -1 on error
264
static ssize_t pgp_packet_decrypt(const char *cryptotext,
267
gpgme_data_t dh_crypto, dh_plain;
270
size_t plaintext_capacity = 0;
271
ssize_t plaintext_length = 0;
274
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
277
/* Create new GPGME data buffer from memory cryptotext */
278
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
280
if(rc != GPG_ERR_NO_ERROR){
122
fprintf(stderr, "Could not set home dir to %s\n", homedir);
126
/* Create new GPGME data buffer from packet buffer */
127
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
128
if (rc != GPG_ERR_NO_ERROR){
281
129
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
282
130
gpgme_strsource(rc), gpgme_strerror(rc));
332
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
192
/* Delete the GPGME FILE pointer cryptotext data buffer */
193
gpgme_data_release(dh_crypto);
335
195
/* Seek back to the beginning of the GPGME plaintext data buffer */
336
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
337
perror("gpgme_data_seek");
338
plaintext_length = -1;
196
gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
344
plaintext_capacity = incbuffer(plaintext,
345
(size_t)plaintext_length,
347
if(plaintext_capacity == 0){
349
plaintext_length = -1;
200
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
201
*new_packet = realloc(*new_packet,
202
(unsigned int)new_packet_capacity
204
if (*new_packet == NULL){
208
new_packet_capacity += BUFFER_SIZE;
353
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
211
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
355
213
/* Print the data, if any */
361
218
perror("gpgme_data_read");
362
plaintext_length = -1;
365
plaintext_length += ret;
369
fprintf(stderr, "Decrypted password is: ");
370
for(ssize_t i = 0; i < plaintext_length; i++){
371
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
373
fprintf(stderr, "\n");
378
/* Delete the GPGME cryptotext data buffer */
379
gpgme_data_release(dh_crypto);
221
new_packet_length += ret;
224
/* FIXME: check characters before printing to screen so to not print
225
terminal control characters */
227
/* fprintf(stderr, "decrypted password is: "); */
228
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
229
/* fprintf(stderr, "\n"); */
381
232
/* Delete the GPGME plaintext data buffer */
382
233
gpgme_data_release(dh_plain);
383
return plaintext_length;
234
return new_packet_length;
386
static const char * safer_gnutls_strerror(int value){
387
const char *ret = gnutls_strerror(value); /* Spurious warning from
388
-Wunreachable-code */
237
static const char * safer_gnutls_strerror (int value) {
238
const char *ret = gnutls_strerror (value);
390
240
ret = "(unknown)";
394
/* GnuTLS log function callback */
395
static void debuggnutls(__attribute__((unused)) int level,
397
fprintf(stderr, "GnuTLS: %s", string);
244
void debuggnutls(__attribute__((unused)) int level,
246
fprintf(stderr, "%s", string);
400
static int init_gnutls_global(const char *pubkeyfilename,
401
const char *seckeyfilename){
249
int initgnutls(encrypted_session *es){
405
254
fprintf(stderr, "Initializing GnuTLS\n");
408
ret = gnutls_global_init();
409
if(ret != GNUTLS_E_SUCCESS){
410
fprintf(stderr, "GnuTLS global_init: %s\n",
411
safer_gnutls_strerror(ret));
257
if ((ret = gnutls_global_init ())
258
!= GNUTLS_E_SUCCESS) {
259
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
416
/* "Use a log level over 10 to enable all debugging options."
419
264
gnutls_global_set_log_level(11);
420
265
gnutls_global_set_log_function(debuggnutls);
423
/* OpenPGP credentials */
424
gnutls_certificate_allocate_credentials(&mc.cred);
425
if(ret != GNUTLS_E_SUCCESS){
426
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
430
safer_gnutls_strerror(ret));
431
gnutls_global_deinit();
268
/* openpgp credentials */
269
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
270
!= GNUTLS_E_SUCCESS) {
271
fprintf (stderr, "memory error: %s\n",
272
safer_gnutls_strerror(ret));
436
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
437
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
277
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
278
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
441
282
ret = gnutls_certificate_set_openpgp_key_file
442
(mc.cred, pubkeyfilename, seckeyfilename,
443
GNUTLS_OPENPGP_FMT_BASE64);
444
if(ret != GNUTLS_E_SUCCESS){
446
"Error[%d] while reading the OpenPGP key pair ('%s',"
447
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
448
fprintf(stderr, "The GnuTLS error is: %s\n",
449
safer_gnutls_strerror(ret));
453
/* GnuTLS server initialization */
454
ret = gnutls_dh_params_init(&mc.dh_params);
455
if(ret != GNUTLS_E_SUCCESS){
456
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
457
" %s\n", safer_gnutls_strerror(ret));
460
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
461
if(ret != GNUTLS_E_SUCCESS){
462
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
463
safer_gnutls_strerror(ret));
467
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
473
gnutls_certificate_free_credentials(mc.cred);
474
gnutls_global_deinit();
475
gnutls_dh_params_deinit(mc.dh_params);
479
static int init_gnutls_session(gnutls_session_t *session){
481
/* GnuTLS session creation */
483
ret = gnutls_init(session, GNUTLS_SERVER);
487
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
488
if(ret != GNUTLS_E_SUCCESS){
283
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
284
if (ret != GNUTLS_E_SUCCESS) {
286
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
288
ret, CERTFILE, KEYFILE);
289
fprintf(stdout, "The Error is: %s\n",
290
safer_gnutls_strerror(ret));
294
//GnuTLS server initialization
295
if ((ret = gnutls_dh_params_init (&es->dh_params))
296
!= GNUTLS_E_SUCCESS) {
297
fprintf (stderr, "Error in dh parameter initialization: %s\n",
298
safer_gnutls_strerror(ret));
302
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
303
!= GNUTLS_E_SUCCESS) {
304
fprintf (stderr, "Error in prime generation: %s\n",
305
safer_gnutls_strerror(ret));
309
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
311
// GnuTLS session creation
312
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
313
!= GNUTLS_E_SUCCESS){
489
314
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
490
315
safer_gnutls_strerror(ret));
496
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
498
gnutls_deinit(*session);
501
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
502
if(ret != GNUTLS_E_SUCCESS){
503
fprintf(stderr, "Syntax error at: %s\n", err);
504
fprintf(stderr, "GnuTLS error: %s\n",
505
safer_gnutls_strerror(ret));
506
gnutls_deinit(*session);
318
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
319
!= GNUTLS_E_SUCCESS) {
320
fprintf(stderr, "Syntax error at: %s\n", err);
321
fprintf(stderr, "GnuTLS error: %s\n",
322
safer_gnutls_strerror(ret));
512
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
515
gnutls_deinit(*session);
518
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
519
if(ret != GNUTLS_E_SUCCESS){
520
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
326
if ((ret = gnutls_credentials_set
327
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
328
!= GNUTLS_E_SUCCESS) {
329
fprintf(stderr, "Error setting a credentials set: %s\n",
521
330
safer_gnutls_strerror(ret));
522
gnutls_deinit(*session);
526
334
/* ignore client certificate if any. */
527
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
335
gnutls_certificate_server_set_request (es->session,
529
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
338
gnutls_dh_set_prime_bits (es->session, DH_BITS);
534
/* Avahi log function callback */
535
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
536
__attribute__((unused)) const char *txt){}
343
void empty_log(__attribute__((unused)) AvahiLogLevel level,
344
__attribute__((unused)) const char *txt){}
538
/* Called when a Mandos server is found */
539
static int start_mandos_communication(const char *ip, uint16_t port,
540
AvahiIfIndex if_index,
542
int ret, tcp_sd = -1;
545
struct sockaddr_in in;
546
struct sockaddr_in6 in6;
346
int start_mandos_communication(const char *ip, uint16_t port,
347
unsigned int if_index){
349
struct sockaddr_in6 to;
350
encrypted_session es;
548
351
char *buffer = NULL;
549
char *decrypted_buffer = NULL;
352
char *decrypted_buffer;
550
353
size_t buffer_length = 0;
551
354
size_t buffer_capacity = 0;
554
gnutls_session_t session;
555
int pf; /* Protocol family */
569
fprintf(stderr, "Bad address family: %d\n", af);
573
ret = init_gnutls_session(&session);
355
ssize_t decrypted_buffer_size;
358
char interface[IF_NAMESIZE];
579
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
361
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
583
tcp_sd = socket(pf, SOCK_STREAM, 0);
364
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
585
366
perror("socket");
593
memset(&to, 0, sizeof(to));
595
to.in6.sin6_family = (sa_family_t)af;
596
ret = inet_pton(af, ip, &to.in6.sin6_addr);
598
to.in.sin_family = (sa_family_t)af;
599
ret = inet_pton(af, ip, &to.in.sin_addr);
370
if(if_indextoname(if_index, interface) == NULL){
372
perror("if_indextoname");
378
fprintf(stderr, "Binding to interface %s\n", interface);
381
memset(&to,0,sizeof(to)); /* Spurious warning */
382
to.sin6_family = AF_INET6;
383
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
602
385
perror("inet_pton");
606
389
fprintf(stderr, "Bad address: %s\n", ip);
610
to.in6.sin6_port = htons(port); /* Spurious warnings from
612
-Wunreachable-code */
614
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
615
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
617
if(if_index == AVAHI_IF_UNSPEC){
618
fprintf(stderr, "An IPv6 link-local address is incomplete"
619
" without a network interface\n");
622
/* Set the network interface number as scope */
623
to.in6.sin6_scope_id = (uint32_t)if_index;
626
to.in.sin_port = htons(port); /* Spurious warnings from
628
-Wunreachable-code */
392
to.sin6_port = htons(port); /* Spurious warning */
394
to.sin6_scope_id = (uint32_t)if_index;
636
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
637
char interface[IF_NAMESIZE];
638
if(if_indextoname((unsigned int)if_index, interface) == NULL){
639
perror("if_indextoname");
641
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
642
ip, interface, port);
645
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
648
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
649
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
652
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
655
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
661
if(strcmp(addrstr, ip) != 0){
662
fprintf(stderr, "Canonical address form: %s\n", addrstr);
672
ret = connect(tcp_sd, &to.in6, sizeof(to));
674
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
397
fprintf(stderr, "Connection to: %s\n", ip);
400
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
677
402
perror("connect");
685
const char *out = mandos_protocol_version;
688
size_t out_size = strlen(out);
689
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
690
out_size - written));
695
written += (size_t)ret;
696
if(written < out_size){
699
if(out == mandos_protocol_version){
406
ret = initgnutls (&es);
412
gnutls_transport_set_ptr (es.session,
413
(gnutls_transport_ptr_t) tcp_sd);
713
416
fprintf(stderr, "Establishing TLS session with %s\n", ip);
720
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
727
ret = gnutls_handshake(session);
731
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
733
if(ret != GNUTLS_E_SUCCESS){
735
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
741
/* Read OpenPGP packet that contains the wanted password */
419
ret = gnutls_handshake (es.session);
421
if (ret != GNUTLS_E_SUCCESS){
422
fprintf(stderr, "\n*** Handshake failed ***\n");
428
//Retrieve OpenPGP packet that contains the wanted password
744
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
431
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
754
buffer_capacity = incbuffer(&buffer, buffer_length,
756
if(buffer_capacity == 0){
765
sret = gnutls_record_recv(session, buffer+buffer_length,
436
if (buffer_length + BUFFER_SIZE > buffer_capacity){
437
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
442
buffer_capacity += BUFFER_SIZE;
445
ret = gnutls_record_recv
446
(es.session, buffer+buffer_length, BUFFER_SIZE);
772
452
case GNUTLS_E_INTERRUPTED:
773
453
case GNUTLS_E_AGAIN:
775
455
case GNUTLS_E_REHANDSHAKE:
777
ret = gnutls_handshake(session);
782
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
784
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
456
ret = gnutls_handshake (es.session);
458
fprintf(stderr, "\n*** Handshake failed ***\n");
790
465
fprintf(stderr, "Unknown error while reading data from"
791
" encrypted session with Mandos server\n");
792
gnutls_bye(session, GNUTLS_SHUT_RDWR);
466
" encrypted session with mandos server\n");
468
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
796
buffer_length += (size_t) sret;
801
fprintf(stderr, "Closing TLS session\n");
809
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
813
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
815
if(buffer_length > 0){
816
ssize_t decrypted_buffer_size;
472
buffer_length += (size_t) ret;
476
if (buffer_length > 0){
817
477
decrypted_buffer_size = pgp_packet_decrypt(buffer,
820
if(decrypted_buffer_size >= 0){
823
while(written < (size_t) decrypted_buffer_size){
828
ret = (int)fwrite(decrypted_buffer + written, 1,
829
(size_t)decrypted_buffer_size - written,
481
if (decrypted_buffer_size >= 0){
482
while(written < decrypted_buffer_size){
483
ret = (int)fwrite (decrypted_buffer + written, 1,
484
(size_t)decrypted_buffer_size - written,
831
486
if(ret == 0 and ferror(stdout)){
833
488
fprintf(stderr, "Error writing encrypted data: %s\n",
834
489
strerror(errno));
838
494
written += (size_t)ret;
496
free(decrypted_buffer);
844
/* Shutdown procedure */
847
free(decrypted_buffer);
505
fprintf(stderr, "Closing TLS session\n");
850
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
855
gnutls_deinit(session);
509
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
512
gnutls_deinit (es.session);
513
gnutls_certificate_free_credentials (es.cred);
514
gnutls_global_deinit ();
862
static void resolve_callback(AvahiSServiceResolver *r,
863
AvahiIfIndex interface,
865
AvahiResolverEvent event,
869
const char *host_name,
870
const AvahiAddress *address,
872
AVAHI_GCC_UNUSED AvahiStringList *txt,
873
AVAHI_GCC_UNUSED AvahiLookupResultFlags
875
AVAHI_GCC_UNUSED void* userdata){
518
static AvahiSimplePoll *simple_poll = NULL;
519
static AvahiServer *server = NULL;
521
static void resolve_callback(
522
AvahiSServiceResolver *r,
523
AvahiIfIndex interface,
524
AVAHI_GCC_UNUSED AvahiProtocol protocol,
525
AvahiResolverEvent event,
529
const char *host_name,
530
const AvahiAddress *address,
532
AVAHI_GCC_UNUSED AvahiStringList *txt,
533
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
534
AVAHI_GCC_UNUSED void* userdata) {
536
assert(r); /* Spurious warning */
878
538
/* Called whenever a service has been resolved successfully or
887
543
case AVAHI_RESOLVER_FAILURE:
888
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
889
" of type '%s' in domain '%s': %s\n", name, type, domain,
890
avahi_strerror(avahi_server_errno(mc.server)));
544
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
545
" type '%s' in domain '%s': %s\n", name, type, domain,
546
avahi_strerror(avahi_server_errno(server)));
893
549
case AVAHI_RESOLVER_FOUND:
895
551
char ip[AVAHI_ADDRESS_STR_MAX];
896
552
avahi_address_snprint(ip, sizeof(ip), address);
898
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
899
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
900
ip, (intmax_t)interface, port);
554
fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
555
host_name, ip, port);
902
int ret = start_mandos_communication(ip, port, interface,
903
avahi_proto_to_af(proto));
905
avahi_simple_poll_quit(mc.simple_poll);
557
int ret = start_mandos_communication(ip, port,
558
(unsigned int) interface);
909
566
avahi_s_service_resolver_free(r);
912
static void browse_callback(AvahiSServiceBrowser *b,
913
AvahiIfIndex interface,
914
AvahiProtocol protocol,
915
AvahiBrowserEvent event,
919
AVAHI_GCC_UNUSED AvahiLookupResultFlags
921
AVAHI_GCC_UNUSED void* userdata){
924
/* Called whenever a new services becomes available on the LAN or
925
is removed from the LAN */
933
case AVAHI_BROWSER_FAILURE:
935
fprintf(stderr, "(Avahi browser) %s\n",
936
avahi_strerror(avahi_server_errno(mc.server)));
937
avahi_simple_poll_quit(mc.simple_poll);
940
case AVAHI_BROWSER_NEW:
941
/* We ignore the returned Avahi resolver object. In the callback
942
function we free it. If the Avahi server is terminated before
943
the callback function is called the Avahi server will free the
946
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
947
name, type, domain, protocol, 0,
948
resolve_callback, NULL) == NULL)
949
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
950
name, avahi_strerror(avahi_server_errno(mc.server)));
953
case AVAHI_BROWSER_REMOVE:
956
case AVAHI_BROWSER_ALL_FOR_NOW:
957
case AVAHI_BROWSER_CACHE_EXHAUSTED:
959
fprintf(stderr, "No Mandos server found, still searching...\n");
965
/* stop main loop after sigterm has been called */
966
static void handle_sigterm(int sig){
971
signal_received = sig;
972
int old_errno = errno;
973
if(mc.simple_poll != NULL){
974
avahi_simple_poll_quit(mc.simple_poll);
980
* This function determines if a directory entry in /sys/class/net
981
* corresponds to an acceptable network device.
982
* (This function is passed to scandir(3) as a filter function.)
984
int good_interface(const struct dirent *if_entry){
986
char *flagname = NULL;
987
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
993
if(if_entry->d_name[0] == '.'){
996
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1001
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1002
/* read line from flags_fd */
1003
ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1004
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1005
flagstring[(size_t)to_read] = '\0';
1006
if(flagstring == NULL){
1012
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1029
tmpmax = strtoimax(flagstring, &tmp, 0);
1030
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1031
and not (isspace(*tmp)))
1032
or tmpmax != (ifreq_flags)tmpmax){
1034
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1035
flagstring, if_entry->d_name);
1041
ifreq_flags flags = (ifreq_flags)tmpmax;
1042
/* Reject the loopback device */
1043
if(flags & IFF_LOOPBACK){
1045
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1050
/* Accept point-to-point devices only if connect_to is specified */
1051
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1053
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1058
/* Otherwise, reject non-broadcast-capable devices */
1059
if(not (flags & IFF_BROADCAST)){
1061
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1066
/* Accept this device */
1068
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1074
int main(int argc, char *argv[]){
1075
AvahiSServiceBrowser *sb = NULL;
1080
int exitcode = EXIT_SUCCESS;
1081
const char *interface = "";
1082
struct ifreq network;
1084
bool take_down_interface = false;
1087
char tempdir[] = "/tmp/mandosXXXXXX";
1088
bool tempdir_created = false;
1089
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1090
const char *seckey = PATHDIR "/" SECKEY;
1091
const char *pubkey = PATHDIR "/" PUBKEY;
1093
bool gnutls_initialized = false;
1094
bool gpgme_initialized = false;
1097
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1098
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1103
/* Lower any group privileges we might have, just to be safe */
1110
/* Lower user privileges (temporarily) */
1122
struct argp_option options[] = {
1123
{ .name = "debug", .key = 128,
1124
.doc = "Debug mode", .group = 3 },
1125
{ .name = "connect", .key = 'c',
1126
.arg = "ADDRESS:PORT",
1127
.doc = "Connect directly to a specific Mandos server",
1129
{ .name = "interface", .key = 'i',
1131
.doc = "Network interface that will be used to search for"
1134
{ .name = "seckey", .key = 's',
1136
.doc = "OpenPGP secret key file base name",
1138
{ .name = "pubkey", .key = 'p',
1140
.doc = "OpenPGP public key file base name",
1142
{ .name = "dh-bits", .key = 129,
1144
.doc = "Bit length of the prime number used in the"
1145
" Diffie-Hellman key exchange",
1147
{ .name = "priority", .key = 130,
1149
.doc = "GnuTLS priority string for the TLS handshake",
1151
{ .name = "delay", .key = 131,
1153
.doc = "Maximum delay to wait for interface startup",
1158
error_t parse_opt(int key, char *arg,
1159
struct argp_state *state){
1161
case 128: /* --debug */
1164
case 'c': /* --connect */
1167
case 'i': /* --interface */
1170
case 's': /* --seckey */
1173
case 'p': /* --pubkey */
1176
case 129: /* --dh-bits */
1178
tmpmax = strtoimax(arg, &tmp, 10);
1179
if(errno != 0 or tmp == arg or *tmp != '\0'
1180
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1181
fprintf(stderr, "Bad number of DH bits\n");
1184
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1186
case 130: /* --priority */
1189
case 131: /* --delay */
1191
delay = strtof(arg, &tmp);
1192
if(errno != 0 or tmp == arg or *tmp != '\0'){
1193
fprintf(stderr, "Bad delay\n");
1202
return ARGP_ERR_UNKNOWN;
1207
struct argp argp = { .options = options, .parser = parse_opt,
1209
.doc = "Mandos client -- Get and decrypt"
1210
" passwords from a Mandos server" };
1211
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
1212
if(ret == ARGP_ERR_UNKNOWN){
1213
fprintf(stderr, "Unknown error while parsing arguments\n");
1214
exitcode = EXIT_FAILURE;
1220
avahi_set_log_function(empty_log);
1223
if(interface[0] == '\0'){
1224
struct dirent **direntries;
1225
ret = scandir(sys_class_net, &direntries, good_interface,
1228
/* Pick the first good interface */
1229
interface = strdup(direntries[0]->d_name);
1231
fprintf(stderr, "Using interface \"%s\"\n", interface);
1233
if(interface == NULL){
1236
exitcode = EXIT_FAILURE;
1242
fprintf(stderr, "Could not find a network interface\n");
1243
exitcode = EXIT_FAILURE;
1248
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1249
from the signal handler */
1250
/* Initialize the pseudo-RNG for Avahi */
1251
srand((unsigned int) time(NULL));
1252
mc.simple_poll = avahi_simple_poll_new();
1253
if(mc.simple_poll == NULL){
1254
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1255
exitcode = EXIT_FAILURE;
1259
sigemptyset(&sigterm_action.sa_mask);
1260
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1262
perror("sigaddset");
1263
exitcode = EXIT_FAILURE;
1266
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1268
perror("sigaddset");
1269
exitcode = EXIT_FAILURE;
1272
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1274
perror("sigaddset");
1275
exitcode = EXIT_FAILURE;
1278
/* Need to check if the handler is SIG_IGN before handling:
1279
| [[info:libc:Initial Signal Actions]] |
1280
| [[info:libc:Basic Signal Handling]] |
1282
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1284
perror("sigaction");
1285
return EXIT_FAILURE;
1287
if(old_sigterm_action.sa_handler != SIG_IGN){
1288
ret = sigaction(SIGINT, &sigterm_action, NULL);
1290
perror("sigaction");
1291
exitcode = EXIT_FAILURE;
1295
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1297
perror("sigaction");
1298
return EXIT_FAILURE;
1300
if(old_sigterm_action.sa_handler != SIG_IGN){
1301
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1303
perror("sigaction");
1304
exitcode = EXIT_FAILURE;
1308
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1310
perror("sigaction");
1311
return EXIT_FAILURE;
1313
if(old_sigterm_action.sa_handler != SIG_IGN){
1314
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1316
perror("sigaction");
1317
exitcode = EXIT_FAILURE;
1322
/* If the interface is down, bring it up */
1323
if(strcmp(interface, "none") != 0){
1324
if_index = (AvahiIfIndex) if_nametoindex(interface);
1326
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1327
exitcode = EXIT_FAILURE;
1335
/* Re-raise priviliges */
1343
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1344
messages to mess up the prompt */
1345
ret = klogctl(8, NULL, 5);
1346
bool restore_loglevel = true;
1348
restore_loglevel = false;
1351
#endif /* __linux__ */
1353
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1356
exitcode = EXIT_FAILURE;
1358
if(restore_loglevel){
1359
ret = klogctl(7, NULL, 0);
1364
#endif /* __linux__ */
1365
/* Lower privileges */
1373
strcpy(network.ifr_name, interface);
1374
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1376
perror("ioctl SIOCGIFFLAGS");
1378
if(restore_loglevel){
1379
ret = klogctl(7, NULL, 0);
1384
#endif /* __linux__ */
1385
exitcode = EXIT_FAILURE;
1386
/* Lower privileges */
1394
if((network.ifr_flags & IFF_UP) == 0){
1395
network.ifr_flags |= IFF_UP;
1396
take_down_interface = true;
1397
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1399
take_down_interface = false;
1400
perror("ioctl SIOCSIFFLAGS +IFF_UP");
1401
exitcode = EXIT_FAILURE;
1403
if(restore_loglevel){
1404
ret = klogctl(7, NULL, 0);
1409
#endif /* __linux__ */
1410
/* Lower privileges */
1419
/* sleep checking until interface is running */
1420
for(int i=0; i < delay * 4; i++){
1421
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1423
perror("ioctl SIOCGIFFLAGS");
1424
} else if(network.ifr_flags & IFF_RUNNING){
1427
struct timespec sleeptime = { .tv_nsec = 250000000 };
1428
ret = nanosleep(&sleeptime, NULL);
1429
if(ret == -1 and errno != EINTR){
1430
perror("nanosleep");
1433
if(not take_down_interface){
1434
/* We won't need the socket anymore */
1435
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1441
if(restore_loglevel){
1442
/* Restores kernel loglevel to default */
1443
ret = klogctl(7, NULL, 0);
1448
#endif /* __linux__ */
1449
/* Lower privileges */
1451
if(take_down_interface){
1452
/* Lower privileges */
1458
/* Lower privileges permanently */
1470
ret = init_gnutls_global(pubkey, seckey);
1472
fprintf(stderr, "init_gnutls_global failed\n");
1473
exitcode = EXIT_FAILURE;
1476
gnutls_initialized = true;
1483
tempdir_created = true;
1484
if(mkdtemp(tempdir) == NULL){
1485
tempdir_created = false;
1494
if(not init_gpgme(pubkey, seckey, tempdir)){
1495
fprintf(stderr, "init_gpgme failed\n");
1496
exitcode = EXIT_FAILURE;
1499
gpgme_initialized = true;
1506
if(connect_to != NULL){
1507
/* Connect directly, do not use Zeroconf */
1508
/* (Mainly meant for debugging) */
1509
char *address = strrchr(connect_to, ':');
1510
if(address == NULL){
1511
fprintf(stderr, "No colon in address\n");
1512
exitcode = EXIT_FAILURE;
1522
tmpmax = strtoimax(address+1, &tmp, 10);
1523
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1524
or tmpmax != (uint16_t)tmpmax){
1525
fprintf(stderr, "Bad port number\n");
1526
exitcode = EXIT_FAILURE;
1534
port = (uint16_t)tmpmax;
1536
address = connect_to;
1537
/* Colon in address indicates IPv6 */
1539
if(strchr(address, ':') != NULL){
1549
ret = start_mandos_communication(address, port, if_index, af);
1551
exitcode = EXIT_FAILURE;
1553
exitcode = EXIT_SUCCESS;
569
static void browse_callback(
570
AvahiSServiceBrowser *b,
571
AvahiIfIndex interface,
572
AvahiProtocol protocol,
573
AvahiBrowserEvent event,
577
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
580
AvahiServer *s = userdata;
581
assert(b); /* Spurious warning */
583
/* Called whenever a new services becomes available on the LAN or
584
is removed from the LAN */
588
case AVAHI_BROWSER_FAILURE:
590
fprintf(stderr, "(Browser) %s\n",
591
avahi_strerror(avahi_server_errno(server)));
592
avahi_simple_poll_quit(simple_poll);
595
case AVAHI_BROWSER_NEW:
596
/* We ignore the returned resolver object. In the callback
597
function we free it. If the server is terminated before
598
the callback function is called the server will free
599
the resolver for us. */
601
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
603
AVAHI_PROTO_INET6, 0,
604
resolve_callback, s)))
605
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
606
avahi_strerror(avahi_server_errno(s)));
609
case AVAHI_BROWSER_REMOVE:
612
case AVAHI_BROWSER_ALL_FOR_NOW:
613
case AVAHI_BROWSER_CACHE_EXHAUSTED:
618
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1563
619
AvahiServerConfig config;
1564
/* Do not publish any local Zeroconf records */
620
AvahiSServiceBrowser *sb = NULL;
623
int returncode = EXIT_SUCCESS;
624
const char *interface = "eth0";
627
static struct option long_options[] = {
628
{"debug", no_argument, (int *)&debug, 1},
629
{"interface", required_argument, 0, 'i'},
632
int option_index = 0;
633
ret = getopt_long (argc, argv, "i:", long_options,
652
avahi_set_log_function(empty_log);
655
/* Initialize the psuedo-RNG */
656
srand((unsigned int) time(NULL));
658
/* Allocate main loop object */
659
if (!(simple_poll = avahi_simple_poll_new())) {
660
fprintf(stderr, "Failed to create simple poll object.\n");
665
/* Do not publish any local records */
1565
666
avahi_server_config_init(&config);
1566
667
config.publish_hinfo = 0;
1567
668
config.publish_addresses = 0;
1568
669
config.publish_workstation = 0;
1569
670
config.publish_domain = 0;
1571
672
/* Allocate a new server */
1572
mc.server = avahi_server_new(avahi_simple_poll_get
1573
(mc.simple_poll), &config, NULL,
1576
/* Free the Avahi configuration data */
673
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
674
&config, NULL, NULL, &error);
676
/* Free the configuration data */
1577
677
avahi_server_config_free(&config);
1580
/* Check if creating the Avahi server object succeeded */
1581
if(mc.server == NULL){
1582
fprintf(stderr, "Failed to create Avahi server: %s\n",
1583
avahi_strerror(error));
1584
exitcode = EXIT_FAILURE;
1592
/* Create the Avahi service browser */
1593
sb = avahi_s_service_browser_new(mc.server, if_index,
1594
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1595
NULL, 0, browse_callback, NULL);
1597
fprintf(stderr, "Failed to create service browser: %s\n",
1598
avahi_strerror(avahi_server_errno(mc.server)));
1599
exitcode = EXIT_FAILURE;
1607
/* Run the main loop */
1610
fprintf(stderr, "Starting Avahi loop search\n");
1613
avahi_simple_poll_loop(mc.simple_poll);
1618
fprintf(stderr, "%s exiting\n", argv[0]);
1621
/* Cleanup things */
1623
avahi_s_service_browser_free(sb);
1625
if(mc.server != NULL)
1626
avahi_server_free(mc.server);
1628
if(mc.simple_poll != NULL)
1629
avahi_simple_poll_free(mc.simple_poll);
1631
if(gnutls_initialized){
1632
gnutls_certificate_free_credentials(mc.cred);
1633
gnutls_global_deinit();
1634
gnutls_dh_params_deinit(mc.dh_params);
1637
if(gpgme_initialized){
1638
gpgme_release(mc.ctx);
1641
/* Take down the network interface */
1642
if(take_down_interface){
1643
/* Re-raise priviliges */
1650
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1652
perror("ioctl SIOCGIFFLAGS");
1653
} else if(network.ifr_flags & IFF_UP) {
1654
network.ifr_flags &= ~IFF_UP; /* clear flag */
1655
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1657
perror("ioctl SIOCSIFFLAGS -IFF_UP");
1660
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1664
/* Lower privileges permanently */
1673
/* Removes the temp directory used by GPGME */
1674
if(tempdir_created){
1676
struct dirent *direntry;
1677
d = opendir(tempdir);
1679
if(errno != ENOENT){
1684
direntry = readdir(d);
1685
if(direntry == NULL){
1688
/* Skip "." and ".." */
1689
if(direntry->d_name[0] == '.'
1690
and (direntry->d_name[1] == '\0'
1691
or (direntry->d_name[1] == '.'
1692
and direntry->d_name[2] == '\0'))){
1695
char *fullname = NULL;
1696
ret = asprintf(&fullname, "%s/%s", tempdir,
1702
ret = remove(fullname);
1704
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1711
ret = rmdir(tempdir);
1712
if(ret == -1 and errno != ENOENT){
1718
sigemptyset(&old_sigterm_action.sa_mask);
1719
old_sigterm_action.sa_handler = SIG_DFL;
1720
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1721
&old_sigterm_action,
1724
perror("sigaction");
1727
ret = raise(signal_received);
1728
} while(ret != 0 and errno == EINTR);
1733
TEMP_FAILURE_RETRY(pause());
679
/* Check if creating the server object succeeded */
681
fprintf(stderr, "Failed to create server: %s\n",
682
avahi_strerror(error));
683
returncode = EXIT_FAILURE;
687
/* Create the service browser */
688
sb = avahi_s_service_browser_new(server,
690
if_nametoindex(interface),
692
"_mandos._tcp", NULL, 0,
693
browse_callback, server);
695
fprintf(stderr, "Failed to create service browser: %s\n",
696
avahi_strerror(avahi_server_errno(server)));
697
returncode = EXIT_FAILURE;
701
/* Run the main loop */
704
fprintf(stderr, "Starting avahi loop search\n");
707
avahi_simple_poll_loop(simple_poll);
712
fprintf(stderr, "%s exiting\n", argv[0]);
717
avahi_s_service_browser_free(sb);
720
avahi_server_free(server);
723
avahi_simple_poll_free(simple_poll);