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, srand(),
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,
85
#include <sysexits.h> /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
86
EX_NOHOST, EX_IOERR, EX_PROTOCOL */
89
#include <sys/klog.h> /* klogctl() */
90
#endif /* __linux__ */
93
/* All Avahi types, constants and functions
41
#include <net/if.h> /* if_nametoindex */
96
43
#include <avahi-core/core.h>
97
44
#include <avahi-core/lookup.h>
98
45
#include <avahi-core/log.h>
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>";
131
/* Used for passing in values through the Avahi callback functions */
133
AvahiSimplePoll *simple_poll;
81
gnutls_session_t session;
135
82
gnutls_certificate_credentials_t cred;
136
unsigned int dh_bits;
137
83
gnutls_dh_params_t dh_params;
138
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;
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){
93
ssize_t new_packet_capacity = 0;
94
ssize_t new_packet_length = 0;
173
95
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");
98
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
217
102
gpgme_check_version(NULL);
218
103
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
219
if(rc != GPG_ERR_NO_ERROR){
104
if (rc != GPG_ERR_NO_ERROR){
220
105
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
221
106
gpgme_strsource(rc), gpgme_strerror(rc));
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){
110
/* Set GPGME home directory */
111
rc = gpgme_get_engine_info (&engine_info);
112
if (rc != GPG_ERR_NO_ERROR){
228
113
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
229
114
gpgme_strsource(rc), gpgme_strerror(rc));
232
117
while(engine_info != NULL){
233
118
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
234
119
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
235
engine_info->file_name, tempdir);
120
engine_info->file_name, homedir);
238
123
engine_info = engine_info->next;
240
125
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){
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){
281
133
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
282
134
gpgme_strsource(rc), gpgme_strerror(rc));
332
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
196
/* Delete the GPGME FILE pointer cryptotext data buffer */
197
gpgme_data_release(dh_crypto);
335
199
/* 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;
200
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
201
perror("pgpme_data_seek");
344
plaintext_capacity = incbuffer(plaintext,
345
(size_t)plaintext_length,
347
if(plaintext_capacity == 0){
349
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;
353
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
217
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
355
219
/* Print the data, if any */
361
224
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);
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"); */
381
238
/* Delete the GPGME plaintext data buffer */
382
239
gpgme_data_release(dh_plain);
383
return plaintext_length;
240
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 */
243
static const char * safer_gnutls_strerror (int value) {
244
const char *ret = gnutls_strerror (value);
390
246
ret = "(unknown)";
394
/* GnuTLS log function callback */
395
static void debuggnutls(__attribute__((unused)) int level,
397
fprintf(stderr, "GnuTLS: %s", string);
250
void debuggnutls(__attribute__((unused)) int level,
252
fprintf(stderr, "%s", string);
400
static int init_gnutls_global(const char *pubkeyfilename,
401
const char *seckeyfilename){
255
int initgnutls(encrypted_session *es){
405
260
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));
263
if ((ret = gnutls_global_init ())
264
!= GNUTLS_E_SUCCESS) {
265
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
416
/* "Use a log level over 10 to enable all debugging options."
419
270
gnutls_global_set_log_level(11);
420
271
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();
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));
436
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
437
" 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,
441
288
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){
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){
489
320
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
490
321
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);
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));
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",
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",
521
336
safer_gnutls_strerror(ret));
522
gnutls_deinit(*session);
526
340
/* ignore client certificate if any. */
527
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
341
gnutls_certificate_server_set_request (es->session,
529
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
344
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){}
349
void empty_log(__attribute__((unused)) AvahiLogLevel level,
350
__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;
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;
548
357
char *buffer = NULL;
549
char *decrypted_buffer = NULL;
358
char *decrypted_buffer;
550
359
size_t buffer_length = 0;
551
360
size_t buffer_capacity = 0;
554
gnutls_session_t session;
555
int pf; /* Protocol family */
572
fprintf(stderr, "Bad address family: %d\n", af);
577
ret = init_gnutls_session(&session);
361
ssize_t decrypted_buffer_size;
364
char interface[IF_NAMESIZE];
583
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
367
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
587
tcp_sd = socket(pf, SOCK_STREAM, 0);
370
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
590
372
perror("socket");
600
memset(&to, 0, sizeof(to));
602
to.in6.sin6_family = (sa_family_t)af;
603
ret = inet_pton(af, ip, &to.in6.sin6_addr);
605
to.in.sin_family = (sa_family_t)af;
606
ret = inet_pton(af, ip, &to.in.sin_addr);
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);
610
391
perror("inet_pton");
616
395
fprintf(stderr, "Bad address: %s\n", ip);
621
to.in6.sin6_port = htons(port); /* Spurious warnings from
623
-Wunreachable-code */
625
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
626
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
628
if(if_index == AVAHI_IF_UNSPEC){
629
fprintf(stderr, "An IPv6 link-local address is incomplete"
630
" without a network interface\n");
634
/* Set the network interface number as scope */
635
to.in6.sin6_scope_id = (uint32_t)if_index;
638
to.in.sin_port = htons(port); /* Spurious warnings from
640
-Wunreachable-code */
398
to.sin6_port = htons(port); /* Spurious warning */
400
to.sin6_scope_id = (uint32_t)if_index;
649
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
650
char interface[IF_NAMESIZE];
651
if(if_indextoname((unsigned int)if_index, interface) == NULL){
652
perror("if_indextoname");
654
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
655
ip, interface, port);
658
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
661
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
662
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
665
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
668
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
674
if(strcmp(addrstr, ip) != 0){
675
fprintf(stderr, "Canonical address form: %s\n", addrstr);
686
ret = connect(tcp_sd, &to.in6, sizeof(to));
688
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
403
fprintf(stderr, "Connection to: %s\n", ip);
406
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
692
408
perror("connect");
702
const char *out = mandos_protocol_version;
705
size_t out_size = strlen(out);
706
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
707
out_size - written));
714
written += (size_t)ret;
715
if(written < out_size){
718
if(out == mandos_protocol_version){
412
ret = initgnutls (&es);
418
gnutls_transport_set_ptr (es.session,
419
(gnutls_transport_ptr_t) tcp_sd);
733
422
fprintf(stderr, "Establishing TLS session with %s\n", ip);
741
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
749
ret = gnutls_handshake(session);
754
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
756
if(ret != GNUTLS_E_SUCCESS){
425
ret = gnutls_handshake (es.session);
427
if (ret != GNUTLS_E_SUCCESS){
758
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
429
fprintf(stderr, "\n*** Handshake failed ***\n");
765
/* Read OpenPGP packet that contains the wanted password */
436
//Retrieve OpenPGP packet that contains the wanted password
768
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
439
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
779
buffer_capacity = incbuffer(&buffer, buffer_length,
781
if(buffer_capacity == 0){
793
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);
800
460
case GNUTLS_E_INTERRUPTED:
801
461
case GNUTLS_E_AGAIN:
803
463
case GNUTLS_E_REHANDSHAKE:
805
ret = gnutls_handshake(session);
811
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
813
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
464
ret = gnutls_handshake (es.session);
466
fprintf(stderr, "\n*** Handshake failed ***\n");
820
473
fprintf(stderr, "Unknown error while reading data from"
821
" encrypted session with Mandos server\n");
822
gnutls_bye(session, GNUTLS_SHUT_RDWR);
474
" encrypted session with mandos server\n");
476
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
827
buffer_length += (size_t) sret;
832
fprintf(stderr, "Closing TLS session\n");
841
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
846
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
848
if(buffer_length > 0){
849
ssize_t decrypted_buffer_size;
480
buffer_length += (size_t) ret;
484
if (buffer_length > 0){
850
485
decrypted_buffer_size = pgp_packet_decrypt(buffer,
853
if(decrypted_buffer_size >= 0){
856
while(written < (size_t) decrypted_buffer_size){
862
ret = (int)fwrite(decrypted_buffer + written, 1,
863
(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,
865
494
if(ret == 0 and ferror(stdout)){
868
496
fprintf(stderr, "Error writing encrypted data: %s\n",
869
497
strerror(errno));
874
502
written += (size_t)ret;
880
/* Shutdown procedure */
885
free(decrypted_buffer);
888
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
896
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 ();
906
static void resolve_callback(AvahiSServiceResolver *r,
907
AvahiIfIndex interface,
909
AvahiResolverEvent event,
913
const char *host_name,
914
const AvahiAddress *address,
916
AVAHI_GCC_UNUSED AvahiStringList *txt,
917
AVAHI_GCC_UNUSED AvahiLookupResultFlags
919
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 */
922
546
/* Called whenever a service has been resolved successfully or
931
551
case AVAHI_RESOLVER_FAILURE:
932
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
933
" of type '%s' in domain '%s': %s\n", name, type, domain,
934
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)));
937
557
case AVAHI_RESOLVER_FOUND:
939
559
char ip[AVAHI_ADDRESS_STR_MAX];
940
560
avahi_address_snprint(ip, sizeof(ip), address);
942
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
943
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
944
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);
946
int ret = start_mandos_communication(ip, port, interface,
947
avahi_proto_to_af(proto));
949
avahi_simple_poll_quit(mc.simple_poll);
565
int ret = start_mandos_communication(ip, port,
566
(unsigned int) interface);
953
572
avahi_s_service_resolver_free(r);
956
static void browse_callback(AvahiSServiceBrowser *b,
957
AvahiIfIndex interface,
958
AvahiProtocol protocol,
959
AvahiBrowserEvent event,
963
AVAHI_GCC_UNUSED AvahiLookupResultFlags
965
AVAHI_GCC_UNUSED void* userdata){
968
/* Called whenever a new services becomes available on the LAN or
969
is removed from the LAN */
977
case AVAHI_BROWSER_FAILURE:
979
fprintf(stderr, "(Avahi browser) %s\n",
980
avahi_strerror(avahi_server_errno(mc.server)));
981
avahi_simple_poll_quit(mc.simple_poll);
984
case AVAHI_BROWSER_NEW:
985
/* We ignore the returned Avahi resolver object. In the callback
986
function we free it. If the Avahi server is terminated before
987
the callback function is called the Avahi server will free the
990
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
991
name, type, domain, protocol, 0,
992
resolve_callback, NULL) == NULL)
993
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
994
name, avahi_strerror(avahi_server_errno(mc.server)));
997
case AVAHI_BROWSER_REMOVE:
1000
case AVAHI_BROWSER_ALL_FOR_NOW:
1001
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1003
fprintf(stderr, "No Mandos server found, still searching...\n");
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 */
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:
1009
/* stop main loop after sigterm has been called */
1010
static void handle_sigterm(int sig){
1015
signal_received = sig;
1016
int old_errno = errno;
1017
if(mc.simple_poll != NULL){
1018
avahi_simple_poll_quit(mc.simple_poll);
1023
int main(int argc, char *argv[]){
1024
AvahiSServiceBrowser *sb = NULL;
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){
1029
int exitcode = EXIT_SUCCESS;
1030
const char *interface = "eth0";
1031
struct ifreq network;
1033
bool take_down_interface = false;
1036
char *connect_to = NULL;
1037
char tempdir[] = "/tmp/mandosXXXXXX";
1038
bool tempdir_created = false;
1039
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1040
const char *seckey = PATHDIR "/" SECKEY;
1041
const char *pubkey = PATHDIR "/" PUBKEY;
1043
bool gnutls_initialized = false;
1044
bool gpgme_initialized = false;
1047
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1048
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1053
/* Lower any group privileges we might have, just to be safe */
1060
/* Lower user privileges (temporarily) */
1072
struct argp_option options[] = {
1073
{ .name = "debug", .key = 128,
1074
.doc = "Debug mode", .group = 3 },
1075
{ .name = "connect", .key = 'c',
1076
.arg = "ADDRESS:PORT",
1077
.doc = "Connect directly to a specific Mandos server",
1079
{ .name = "interface", .key = 'i',
1081
.doc = "Network interface that will be used to search for"
1084
{ .name = "seckey", .key = 's',
1086
.doc = "OpenPGP secret key file base name",
1088
{ .name = "pubkey", .key = 'p',
1090
.doc = "OpenPGP public key file base name",
1092
{ .name = "dh-bits", .key = 129,
1094
.doc = "Bit length of the prime number used in the"
1095
" Diffie-Hellman key exchange",
1097
{ .name = "priority", .key = 130,
1099
.doc = "GnuTLS priority string for the TLS handshake",
1101
{ .name = "delay", .key = 131,
1103
.doc = "Maximum delay to wait for interface startup",
1106
* These reproduce what we would get without ARGP_NO_HELP
1108
{ .name = "help", .key = '?',
1109
.doc = "Give this help list", .group = -1 },
1110
{ .name = "usage", .key = -3,
1111
.doc = "Give a short usage message", .group = -1 },
1112
{ .name = "version", .key = 'V',
1113
.doc = "Print program version", .group = -1 },
1117
error_t parse_opt(int key, char *arg,
1118
struct argp_state *state){
1121
case 128: /* --debug */
1124
case 'c': /* --connect */
1127
case 'i': /* --interface */
1130
case 's': /* --seckey */
1133
case 'p': /* --pubkey */
1136
case 129: /* --dh-bits */
1138
tmpmax = strtoimax(arg, &tmp, 10);
1139
if(errno != 0 or tmp == arg or *tmp != '\0'
1140
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1141
argp_error(state, "Bad number of DH bits");
1143
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1145
case 130: /* --priority */
1148
case 131: /* --delay */
1150
delay = strtof(arg, &tmp);
1151
if(errno != 0 or tmp == arg or *tmp != '\0'){
1152
argp_error(state, "Bad delay");
1156
* These reproduce what we would get without ARGP_NO_HELP
1158
case '?': /* --help */
1159
argp_state_help(state, state->out_stream,
1160
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1161
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1162
case -3: /* --usage */
1163
argp_state_help(state, state->out_stream,
1164
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1165
case 'V': /* --version */
1166
fprintf(state->out_stream, "%s\n", argp_program_version);
1167
exit(argp_err_exit_status);
1170
return ARGP_ERR_UNKNOWN;
1175
struct argp argp = { .options = options, .parser = parse_opt,
1177
.doc = "Mandos client -- Get and decrypt"
1178
" passwords from a Mandos server" };
1179
ret = argp_parse(&argp, argc, argv,
1180
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
1187
perror("argp_parse");
1188
exitcode = EX_OSERR;
1191
exitcode = EX_USAGE;
1197
avahi_set_log_function(empty_log);
1200
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1201
from the signal handler */
1202
/* Initialize the pseudo-RNG for Avahi */
1203
srand((unsigned int) time(NULL));
1204
mc.simple_poll = avahi_simple_poll_new();
1205
if(mc.simple_poll == NULL){
1206
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1207
exitcode = EX_UNAVAILABLE;
1211
sigemptyset(&sigterm_action.sa_mask);
1212
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1214
perror("sigaddset");
1215
exitcode = EX_OSERR;
1218
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1220
perror("sigaddset");
1221
exitcode = EX_OSERR;
1224
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1226
perror("sigaddset");
1227
exitcode = EX_OSERR;
1230
/* Need to check if the handler is SIG_IGN before handling:
1231
| [[info:libc:Initial Signal Actions]] |
1232
| [[info:libc:Basic Signal Handling]] |
1234
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1236
perror("sigaction");
1239
if(old_sigterm_action.sa_handler != SIG_IGN){
1240
ret = sigaction(SIGINT, &sigterm_action, NULL);
1242
perror("sigaction");
1243
exitcode = EX_OSERR;
1247
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1249
perror("sigaction");
1252
if(old_sigterm_action.sa_handler != SIG_IGN){
1253
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1255
perror("sigaction");
1256
exitcode = EX_OSERR;
1260
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1262
perror("sigaction");
1265
if(old_sigterm_action.sa_handler != SIG_IGN){
1266
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1268
perror("sigaction");
1269
exitcode = EX_OSERR;
1274
/* If the interface is down, bring it up */
1275
if(interface[0] != '\0'){
1276
if_index = (AvahiIfIndex) if_nametoindex(interface);
1278
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1279
exitcode = EX_UNAVAILABLE;
1287
/* Re-raise priviliges */
1295
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1296
messages about the network interface to mess up the prompt */
1297
ret = klogctl(8, NULL, 5);
1298
bool restore_loglevel = true;
1300
restore_loglevel = false;
1303
#endif /* __linux__ */
1305
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1308
exitcode = EX_OSERR;
1310
if(restore_loglevel){
1311
ret = klogctl(7, NULL, 0);
1316
#endif /* __linux__ */
1317
/* Lower privileges */
1325
strcpy(network.ifr_name, interface);
1326
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1328
perror("ioctl SIOCGIFFLAGS");
1330
if(restore_loglevel){
1331
ret = klogctl(7, NULL, 0);
1336
#endif /* __linux__ */
1337
exitcode = EX_OSERR;
1338
/* Lower privileges */
1346
if((network.ifr_flags & IFF_UP) == 0){
1347
network.ifr_flags |= IFF_UP;
1348
take_down_interface = true;
1349
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1351
take_down_interface = false;
1352
perror("ioctl SIOCSIFFLAGS");
1353
exitcode = EX_OSERR;
1355
if(restore_loglevel){
1356
ret = klogctl(7, NULL, 0);
1361
#endif /* __linux__ */
1362
/* Lower privileges */
1371
/* sleep checking until interface is running */
1372
for(int i=0; i < delay * 4; i++){
1373
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1375
perror("ioctl SIOCGIFFLAGS");
1376
} else if(network.ifr_flags & IFF_RUNNING){
1379
struct timespec sleeptime = { .tv_nsec = 250000000 };
1380
ret = nanosleep(&sleeptime, NULL);
1381
if(ret == -1 and errno != EINTR){
1382
perror("nanosleep");
1385
if(not take_down_interface){
1386
/* We won't need the socket anymore */
1387
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1393
if(restore_loglevel){
1394
/* Restores kernel loglevel to default */
1395
ret = klogctl(7, NULL, 0);
1400
#endif /* __linux__ */
1401
/* Lower privileges */
1403
if(take_down_interface){
1404
/* Lower privileges */
1410
/* Lower privileges permanently */
1422
ret = init_gnutls_global(pubkey, seckey);
1424
fprintf(stderr, "init_gnutls_global failed\n");
1425
exitcode = EX_UNAVAILABLE;
1428
gnutls_initialized = true;
1435
tempdir_created = true;
1436
if(mkdtemp(tempdir) == NULL){
1437
tempdir_created = false;
1446
if(not init_gpgme(pubkey, seckey, tempdir)){
1447
fprintf(stderr, "init_gpgme failed\n");
1448
exitcode = EX_UNAVAILABLE;
1451
gpgme_initialized = true;
1458
if(connect_to != NULL){
1459
/* Connect directly, do not use Zeroconf */
1460
/* (Mainly meant for debugging) */
1461
char *address = strrchr(connect_to, ':');
1462
if(address == NULL){
1463
fprintf(stderr, "No colon in address\n");
1464
exitcode = EX_USAGE;
1474
tmpmax = strtoimax(address+1, &tmp, 10);
1475
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1476
or tmpmax != (uint16_t)tmpmax){
1477
fprintf(stderr, "Bad port number\n");
1478
exitcode = EX_USAGE;
1486
port = (uint16_t)tmpmax;
1488
address = connect_to;
1489
/* Colon in address indicates IPv6 */
1491
if(strchr(address, ':') != NULL){
1501
ret = start_mandos_communication(address, port, if_index, af);
1507
exitcode = EX_NOHOST;
1510
exitcode = EX_USAGE;
1513
exitcode = EX_IOERR;
1516
exitcode = EX_PROTOCOL;
1519
exitcode = EX_OSERR;
1523
exitcode = EXIT_SUCCESS;
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[]) {
1533
642
AvahiServerConfig config;
1534
/* 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 */
1535
711
avahi_server_config_init(&config);
1536
712
config.publish_hinfo = 0;
1537
713
config.publish_addresses = 0;
1538
714
config.publish_workstation = 0;
1539
715
config.publish_domain = 0;
1541
717
/* Allocate a new server */
1542
mc.server = avahi_server_new(avahi_simple_poll_get
1543
(mc.simple_poll), &config, NULL,
1546
/* 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 */
1547
722
avahi_server_config_free(&config);
1550
/* Check if creating the Avahi server object succeeded */
1551
if(mc.server == NULL){
1552
fprintf(stderr, "Failed to create Avahi server: %s\n",
1553
avahi_strerror(error));
1554
exitcode = EX_UNAVAILABLE;
1562
/* Create the Avahi service browser */
1563
sb = avahi_s_service_browser_new(mc.server, if_index,
1564
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1565
NULL, 0, browse_callback, NULL);
1567
fprintf(stderr, "Failed to create service browser: %s\n",
1568
avahi_strerror(avahi_server_errno(mc.server)));
1569
exitcode = EX_UNAVAILABLE;
1577
/* Run the main loop */
1580
fprintf(stderr, "Starting Avahi loop search\n");
1583
avahi_simple_poll_loop(mc.simple_poll);
1588
fprintf(stderr, "%s exiting\n", argv[0]);
1591
/* Cleanup things */
1593
avahi_s_service_browser_free(sb);
1595
if(mc.server != NULL)
1596
avahi_server_free(mc.server);
1598
if(mc.simple_poll != NULL)
1599
avahi_simple_poll_free(mc.simple_poll);
1601
if(gnutls_initialized){
1602
gnutls_certificate_free_credentials(mc.cred);
1603
gnutls_global_deinit();
1604
gnutls_dh_params_deinit(mc.dh_params);
1607
if(gpgme_initialized){
1608
gpgme_release(mc.ctx);
1611
/* Take down the network interface */
1612
if(take_down_interface){
1613
/* Re-raise priviliges */
1620
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1622
perror("ioctl SIOCGIFFLAGS");
1623
} else if(network.ifr_flags & IFF_UP) {
1624
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1625
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1627
perror("ioctl SIOCSIFFLAGS");
1630
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1634
/* Lower privileges permanently */
1643
/* Removes the temp directory used by GPGME */
1644
if(tempdir_created){
1646
struct dirent *direntry;
1647
d = opendir(tempdir);
1649
if(errno != ENOENT){
1654
direntry = readdir(d);
1655
if(direntry == NULL){
1658
/* Skip "." and ".." */
1659
if(direntry->d_name[0] == '.'
1660
and (direntry->d_name[1] == '\0'
1661
or (direntry->d_name[1] == '.'
1662
and direntry->d_name[2] == '\0'))){
1665
char *fullname = NULL;
1666
ret = asprintf(&fullname, "%s/%s", tempdir,
1672
ret = remove(fullname);
1674
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1681
ret = rmdir(tempdir);
1682
if(ret == -1 and errno != ENOENT){
1688
sigemptyset(&old_sigterm_action.sa_mask);
1689
old_sigterm_action.sa_handler = SIG_DFL;
1690
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1691
&old_sigterm_action,
1694
perror("sigaction");
1697
ret = raise(signal_received);
1698
} while(ret != 0 and errno == EINTR);
1703
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);