392
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
214
/* Delete the GPGME FILE pointer cryptotext data buffer */
215
gpgme_data_release(dh_crypto);
395
217
/* Seek back to the beginning of the GPGME plaintext data buffer */
396
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
397
perror_plus("gpgme_data_seek");
398
plaintext_length = -1;
218
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
219
perror("pgpme_data_seek");
404
plaintext_capacity = incbuffer(plaintext,
405
(size_t)plaintext_length,
407
if(plaintext_capacity == 0){
408
perror_plus("incbuffer");
409
plaintext_length = -1;
224
new_packet_capacity = adjustbuffer(*new_packet, new_packet_length,
225
new_packet_capacity);
226
if (new_packet_capacity == 0){
227
perror("adjustbuffer");
230
new_packet_capacity += BUFFER_SIZE;
413
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
233
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
415
235
/* Print the data, if any */
421
perror_plus("gpgme_data_read");
422
plaintext_length = -1;
425
plaintext_length += ret;
429
fprintf(stderr, "Decrypted password is: ");
430
for(ssize_t i = 0; i < plaintext_length; i++){
431
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
433
fprintf(stderr, "\n");
438
/* Delete the GPGME cryptotext data buffer */
439
gpgme_data_release(dh_crypto);
240
perror("gpgme_data_read");
243
new_packet_length += ret;
246
/* FIXME: check characters before printing to screen so to not print
247
terminal control characters */
249
/* fprintf(stderr, "decrypted password is: "); */
250
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
251
/* fprintf(stderr, "\n"); */
441
254
/* Delete the GPGME plaintext data buffer */
442
255
gpgme_data_release(dh_plain);
443
return plaintext_length;
256
return new_packet_length;
446
static const char * safer_gnutls_strerror(int value){
447
const char *ret = gnutls_strerror(value); /* Spurious warning from
448
-Wunreachable-code */
259
static const char * safer_gnutls_strerror (int value) {
260
const char *ret = gnutls_strerror (value);
450
262
ret = "(unknown)";
454
/* GnuTLS log function callback */
455
266
static void debuggnutls(__attribute__((unused)) int level,
456
267
const char* string){
457
fprintf(stderr, "GnuTLS: %s", string);
268
fprintf(stderr, "%s", string);
460
static int init_gnutls_global(const char *pubkeyfilename,
461
const char *seckeyfilename){
271
static int initgnutls(mandos_context *mc){
465
276
fprintf(stderr, "Initializing GnuTLS\n");
468
ret = gnutls_global_init();
469
if(ret != GNUTLS_E_SUCCESS){
470
fprintf(stderr, "GnuTLS global_init: %s\n",
471
safer_gnutls_strerror(ret));
279
if ((ret = gnutls_global_init ())
280
!= GNUTLS_E_SUCCESS) {
281
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
476
/* "Use a log level over 10 to enable all debugging options."
479
286
gnutls_global_set_log_level(11);
480
287
gnutls_global_set_log_function(debuggnutls);
483
/* OpenPGP credentials */
484
ret = gnutls_certificate_allocate_credentials(&mc.cred);
485
if(ret != GNUTLS_E_SUCCESS){
486
fprintf(stderr, "GnuTLS memory error: %s\n",
487
safer_gnutls_strerror(ret));
488
gnutls_global_deinit();
290
/* openpgp credentials */
291
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
292
!= GNUTLS_E_SUCCESS) {
293
fprintf (stderr, "memory error: %s\n",
294
safer_gnutls_strerror(ret));
493
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
494
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
299
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
300
" and keyfile %s as GnuTLS credentials\n", certfile,
498
304
ret = gnutls_certificate_set_openpgp_key_file
499
(mc.cred, pubkeyfilename, seckeyfilename,
500
GNUTLS_OPENPGP_FMT_BASE64);
501
if(ret != GNUTLS_E_SUCCESS){
503
"Error[%d] while reading the OpenPGP key pair ('%s',"
504
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
505
fprintf(stderr, "The GnuTLS error is: %s\n",
506
safer_gnutls_strerror(ret));
510
/* GnuTLS server initialization */
511
ret = gnutls_dh_params_init(&mc.dh_params);
512
if(ret != GNUTLS_E_SUCCESS){
513
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
514
" %s\n", safer_gnutls_strerror(ret));
517
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
518
if(ret != GNUTLS_E_SUCCESS){
519
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
520
safer_gnutls_strerror(ret));
524
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
530
gnutls_certificate_free_credentials(mc.cred);
531
gnutls_global_deinit();
532
gnutls_dh_params_deinit(mc.dh_params);
536
static int init_gnutls_session(gnutls_session_t *session){
538
/* GnuTLS session creation */
540
ret = gnutls_init(session, GNUTLS_SERVER);
544
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
545
if(ret != GNUTLS_E_SUCCESS){
305
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
306
if (ret != GNUTLS_E_SUCCESS) {
308
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
310
ret, certfile, certkey);
311
fprintf(stdout, "The Error is: %s\n",
312
safer_gnutls_strerror(ret));
316
//GnuTLS server initialization
317
if ((ret = gnutls_dh_params_init (&es->dh_params))
318
!= GNUTLS_E_SUCCESS) {
319
fprintf (stderr, "Error in dh parameter initialization: %s\n",
320
safer_gnutls_strerror(ret));
324
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
325
!= GNUTLS_E_SUCCESS) {
326
fprintf (stderr, "Error in prime generation: %s\n",
327
safer_gnutls_strerror(ret));
331
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
333
// GnuTLS session creation
334
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
335
!= GNUTLS_E_SUCCESS){
546
336
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
547
337
safer_gnutls_strerror(ret));
553
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
555
gnutls_deinit(*session);
558
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
559
if(ret != GNUTLS_E_SUCCESS){
560
fprintf(stderr, "Syntax error at: %s\n", err);
561
fprintf(stderr, "GnuTLS error: %s\n",
562
safer_gnutls_strerror(ret));
563
gnutls_deinit(*session);
340
if ((ret = gnutls_priority_set_direct (es->session, mc->priority, &err))
341
!= GNUTLS_E_SUCCESS) {
342
fprintf(stderr, "Syntax error at: %s\n", err);
343
fprintf(stderr, "GnuTLS error: %s\n",
344
safer_gnutls_strerror(ret));
569
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
572
gnutls_deinit(*session);
575
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
576
if(ret != GNUTLS_E_SUCCESS){
577
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
348
if ((ret = gnutls_credentials_set
349
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
350
!= GNUTLS_E_SUCCESS) {
351
fprintf(stderr, "Error setting a credentials set: %s\n",
578
352
safer_gnutls_strerror(ret));
579
gnutls_deinit(*session);
583
356
/* ignore client certificate if any. */
584
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
357
gnutls_certificate_server_set_request (es->session,
586
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
360
gnutls_dh_set_prime_bits (es->session, DH_BITS);
591
/* Avahi log function callback */
592
365
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
593
366
__attribute__((unused)) const char *txt){}
595
/* Called when a Mandos server is found */
596
368
static int start_mandos_communication(const char *ip, uint16_t port,
597
369
AvahiIfIndex if_index,
599
int ret, tcp_sd = -1;
602
struct sockaddr_in in;
603
struct sockaddr_in6 in6;
372
struct sockaddr_in6 to;
373
encrypted_session es;
605
374
char *buffer = NULL;
606
char *decrypted_buffer = NULL;
375
char *decrypted_buffer;
607
376
size_t buffer_length = 0;
608
377
size_t buffer_capacity = 0;
378
ssize_t decrypted_buffer_size;
611
gnutls_session_t session;
612
int pf; /* Protocol family */
629
fprintf(stderr, "Bad address family: %d\n", af);
634
ret = init_gnutls_session(&session);
640
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
644
tcp_sd = socket(pf, SOCK_STREAM, 0);
647
perror_plus("socket");
657
memset(&to, 0, sizeof(to));
659
to.in6.sin6_family = (sa_family_t)af;
660
ret = inet_pton(af, ip, &to.in6.sin6_addr);
662
to.in.sin_family = (sa_family_t)af;
663
ret = inet_pton(af, ip, &to.in.sin_addr);
667
perror_plus("inet_pton");
381
char interface[IF_NAMESIZE];
384
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
388
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
395
if(if_indextoname((unsigned int)if_index, interface) == NULL){
397
perror("if_indextoname");
402
fprintf(stderr, "Binding to interface %s\n", interface);
405
memset(&to,0,sizeof(to)); /* Spurious warning */
406
to.sin6_family = AF_INET6;
407
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
673
413
fprintf(stderr, "Bad address: %s\n", ip);
678
to.in6.sin6_port = htons(port); /* Spurious warnings from
680
-Wunreachable-code */
682
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
683
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
685
if(if_index == AVAHI_IF_UNSPEC){
686
fprintf(stderr, "An IPv6 link-local address is incomplete"
687
" without a network interface\n");
691
/* Set the network interface number as scope */
692
to.in6.sin6_scope_id = (uint32_t)if_index;
695
to.in.sin_port = htons(port); /* Spurious warnings from
697
-Wunreachable-code */
416
to.sin6_port = htons(port); /* Spurious warning */
418
to.sin6_scope_id = (uint32_t)if_index;
706
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
707
char interface[IF_NAMESIZE];
708
if(if_indextoname((unsigned int)if_index, interface) == NULL){
709
perror_plus("if_indextoname");
711
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
712
ip, interface, port);
715
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
718
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
719
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
722
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
725
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
729
perror_plus("inet_ntop");
731
if(strcmp(addrstr, ip) != 0){
732
fprintf(stderr, "Canonical address form: %s\n", addrstr);
743
ret = connect(tcp_sd, &to.in6, sizeof(to));
745
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
748
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
750
perror_plus("connect");
761
const char *out = mandos_protocol_version;
421
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
422
/* char addrstr[INET6_ADDRSTRLEN]; */
423
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
424
/* sizeof(addrstr)) == NULL){ */
425
/* perror("inet_ntop"); */
427
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
428
/* addrstr, ntohs(to.sin6_port)); */
432
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
438
char *out = mandos_protocol_version;
764
441
size_t out_size = strlen(out);
765
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
442
ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
766
443
out_size - written));
769
perror_plus("write");
773
written += (size_t)ret;
774
450
if(written < out_size){
777
if(out == mandos_protocol_version){
453
if (out == mandos_protocol_version){
462
ret = initgnutls (&es);
468
gnutls_transport_set_ptr (es.session,
469
(gnutls_transport_ptr_t) tcp_sd);
792
472
fprintf(stderr, "Establishing TLS session with %s\n", ip);
800
/* Spurious warning from -Wint-to-pointer-cast */
801
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
809
ret = gnutls_handshake(session);
814
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
816
if(ret != GNUTLS_E_SUCCESS){
475
ret = gnutls_handshake (es.session);
477
if (ret != GNUTLS_E_SUCCESS){
818
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
479
fprintf(stderr, "\n*** Handshake failed ***\n");
825
/* Read OpenPGP packet that contains the wanted password */
486
//Retrieve OpenPGP packet that contains the wanted password
828
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
489
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
839
buffer_capacity = incbuffer(&buffer, buffer_length,
841
if(buffer_capacity == 0){
843
perror_plus("incbuffer");
853
sret = gnutls_record_recv(session, buffer+buffer_length,
494
buffer_capacity = adjustbuffer(buffer, buffer_length, buffer_capacity);
495
if (buffer_capacity == 0){
496
perror("adjustbuffer");
501
ret = gnutls_record_recv
502
(es.session, buffer+buffer_length, BUFFER_SIZE);
860
508
case GNUTLS_E_INTERRUPTED:
861
509
case GNUTLS_E_AGAIN:
863
511
case GNUTLS_E_REHANDSHAKE:
865
ret = gnutls_handshake(session);
871
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
873
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
512
ret = gnutls_handshake (es.session);
514
fprintf(stderr, "\n*** Handshake failed ***\n");
880
521
fprintf(stderr, "Unknown error while reading data from"
881
" encrypted session with Mandos server\n");
882
gnutls_bye(session, GNUTLS_SHUT_RDWR);
522
" encrypted session with mandos server\n");
524
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
887
buffer_length += (size_t) sret;
892
fprintf(stderr, "Closing TLS session\n");
901
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
906
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
908
if(buffer_length > 0){
909
ssize_t decrypted_buffer_size;
528
buffer_length += (size_t) ret;
532
if (buffer_length > 0){
910
533
decrypted_buffer_size = pgp_packet_decrypt(buffer,
913
if(decrypted_buffer_size >= 0){
537
if (decrypted_buffer_size >= 0){
916
539
while(written < (size_t) decrypted_buffer_size){
922
ret = (int)fwrite(decrypted_buffer + written, 1,
923
(size_t)decrypted_buffer_size - written,
540
ret = (int)fwrite (decrypted_buffer + written, 1,
541
(size_t)decrypted_buffer_size - written,
925
543
if(ret == 0 and ferror(stdout)){
928
545
fprintf(stderr, "Error writing encrypted data: %s\n",
929
546
strerror(errno));
934
551
written += (size_t)ret;
940
/* Shutdown procedure */
945
free(decrypted_buffer);
948
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
954
perror_plus("close");
956
gnutls_deinit(session);
553
free(decrypted_buffer);
562
fprintf(stderr, "Closing TLS session\n");
566
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
569
gnutls_deinit (es.session);
570
gnutls_certificate_free_credentials (es.cred);
571
gnutls_global_deinit ();
966
static void resolve_callback(AvahiSServiceResolver *r,
967
AvahiIfIndex interface,
969
AvahiResolverEvent event,
973
const char *host_name,
974
const AvahiAddress *address,
976
AVAHI_GCC_UNUSED AvahiStringList *txt,
977
AVAHI_GCC_UNUSED AvahiLookupResultFlags
979
AVAHI_GCC_UNUSED void* userdata){
575
static void resolve_callback( AvahiSServiceResolver *r,
576
AvahiIfIndex interface,
577
AVAHI_GCC_UNUSED AvahiProtocol protocol,
578
AvahiResolverEvent event,
582
const char *host_name,
583
const AvahiAddress *address,
585
AVAHI_GCC_UNUSED AvahiStringList *txt,
586
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
587
AVAHI_GCC_UNUSED void* userdata) {
588
mandos_context *mc = userdata;
589
assert(r); /* Spurious warning */
982
591
/* Called whenever a service has been resolved successfully or
991
596
case AVAHI_RESOLVER_FAILURE:
992
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
993
" of type '%s' in domain '%s': %s\n", name, type, domain,
994
avahi_strerror(avahi_server_errno(mc.server)));
597
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
598
" type '%s' in domain '%s': %s\n", name, type, domain,
599
avahi_strerror(avahi_server_errno(mc->server)));
997
602
case AVAHI_RESOLVER_FOUND:
999
604
char ip[AVAHI_ADDRESS_STR_MAX];
1000
605
avahi_address_snprint(ip, sizeof(ip), address);
1002
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
1003
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
1004
ip, (intmax_t)interface, port);
607
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
608
" port %d\n", name, host_name, ip, port);
1006
int ret = start_mandos_communication(ip, port, interface,
1007
avahi_proto_to_af(proto));
1009
avahi_simple_poll_quit(mc.simple_poll);
1011
ret = add_server(ip, port, interface,
1012
avahi_proto_to_af(proto));
610
int ret = start_mandos_communication(ip, port, interface, mc);
1016
616
avahi_s_service_resolver_free(r);
1019
static void browse_callback(AvahiSServiceBrowser *b,
1020
AvahiIfIndex interface,
1021
AvahiProtocol protocol,
1022
AvahiBrowserEvent event,
1026
AVAHI_GCC_UNUSED AvahiLookupResultFlags
1028
AVAHI_GCC_UNUSED void* userdata){
619
static void browse_callback( AvahiSServiceBrowser *b,
620
AvahiIfIndex interface,
621
AvahiProtocol protocol,
622
AvahiBrowserEvent event,
626
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
628
mandos_context *mc = userdata;
629
assert(b); /* Spurious warning */
1031
631
/* Called whenever a new services becomes available on the LAN or
1032
632
is removed from the LAN */
1040
636
case AVAHI_BROWSER_FAILURE:
1042
fprintf(stderr, "(Avahi browser) %s\n",
1043
avahi_strerror(avahi_server_errno(mc.server)));
1044
avahi_simple_poll_quit(mc.simple_poll);
638
fprintf(stderr, "(Browser) %s\n",
639
avahi_strerror(avahi_server_errno(mc->server)));
640
avahi_simple_poll_quit(mc->simple_poll);
1047
643
case AVAHI_BROWSER_NEW:
1048
/* We ignore the returned Avahi resolver object. In the callback
1049
function we free it. If the Avahi server is terminated before
1050
the callback function is called the Avahi server will free the
1053
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
1054
name, type, domain, protocol, 0,
1055
resolve_callback, NULL) == NULL)
1056
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
1057
name, avahi_strerror(avahi_server_errno(mc.server)));
644
/* We ignore the returned resolver object. In the callback
645
function we free it. If the server is terminated before
646
the callback function is called the server will free
647
the resolver for us. */
649
if (!(avahi_s_service_resolver_new(mc->server, interface, protocol, name,
651
AVAHI_PROTO_INET6, 0,
652
resolve_callback, mc)))
653
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
654
avahi_strerror(avahi_server_errno(s)));
1060
657
case AVAHI_BROWSER_REMOVE:
1063
660
case AVAHI_BROWSER_ALL_FOR_NOW:
1064
661
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1066
fprintf(stderr, "No Mandos server found, still searching...\n");
1072
/* Signal handler that stops main loop after SIGTERM */
1073
static void handle_sigterm(int sig){
1078
signal_received = sig;
1079
int old_errno = errno;
1080
/* set main loop to exit */
1081
if(mc.simple_poll != NULL){
1082
avahi_simple_poll_quit(mc.simple_poll);
1088
* This function determines if a directory entry in /sys/class/net
1089
* corresponds to an acceptable network device.
1090
* (This function is passed to scandir(3) as a filter function.)
1092
int good_interface(const struct dirent *if_entry){
1094
char *flagname = NULL;
1095
if(if_entry->d_name[0] == '.'){
1098
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1101
perror_plus("asprintf");
1104
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1106
perror_plus("open");
1111
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1112
/* read line from flags_fd */
1113
ssize_t to_read = 2+(sizeof(ifreq_flags)*2)+1; /* "0x1003\n" */
1114
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1115
flagstring[(size_t)to_read] = '\0';
1116
if(flagstring == NULL){
1117
perror_plus("malloc");
1122
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1125
perror_plus("read");
1139
tmpmax = strtoimax(flagstring, &tmp, 0);
1140
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1141
and not (isspace(*tmp)))
1142
or tmpmax != (ifreq_flags)tmpmax){
1144
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1145
flagstring, if_entry->d_name);
1151
ifreq_flags flags = (ifreq_flags)tmpmax;
1152
/* Reject the loopback device */
1153
if(flags & IFF_LOOPBACK){
1155
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1160
/* Accept point-to-point devices only if connect_to is specified */
1161
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1163
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1168
/* Otherwise, reject non-broadcast-capable devices */
1169
if(not (flags & IFF_BROADCAST)){
1171
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1176
/* Reject non-ARP interfaces (including dummy interfaces) */
1177
if(flags & IFF_NOARP){
1179
fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n",
1184
/* Accept this device */
1186
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1192
int notdotentries(const struct dirent *direntry){
1193
/* Skip "." and ".." */
1194
if(direntry->d_name[0] == '.'
1195
and (direntry->d_name[1] == '\0'
1196
or (direntry->d_name[1] == '.'
1197
and direntry->d_name[2] == '\0'))){
1203
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval){
1205
struct timespec now;
1206
struct timespec waited_time;
1207
intmax_t block_time;
1210
if(mc.current_server == NULL){
1213
"Wait until first server is found. No timeout!\n");
1215
ret = avahi_simple_poll_iterate(s, -1);
1218
fprintf(stderr, "Check current_server if we should run it,"
1221
/* the current time */
1222
ret = clock_gettime(CLOCK_MONOTONIC, &now);
1224
perror_plus("clock_gettime");
1227
/* Calculating in ms how long time between now and server
1228
who we visted longest time ago. Now - last seen. */
1229
waited_time.tv_sec = (now.tv_sec
1230
- mc.current_server->last_seen.tv_sec);
1231
waited_time.tv_nsec = (now.tv_nsec
1232
- mc.current_server->last_seen.tv_nsec);
1233
/* total time is 10s/10,000ms.
1234
Converting to s from ms by dividing by 1,000,
1235
and ns to ms by dividing by 1,000,000. */
1236
block_time = ((retry_interval
1237
- ((intmax_t)waited_time.tv_sec * 1000))
1238
- ((intmax_t)waited_time.tv_nsec / 1000000));
1241
fprintf(stderr, "Blocking for %ld ms\n", block_time);
1244
if(block_time <= 0){
1245
ret = start_mandos_communication(mc.current_server->ip,
1246
mc.current_server->port,
1247
mc.current_server->if_index,
1248
mc.current_server->af);
1250
avahi_simple_poll_quit(mc.simple_poll);
1253
ret = clock_gettime(CLOCK_MONOTONIC,
1254
&mc.current_server->last_seen);
1256
perror_plus("clock_gettime");
1259
mc.current_server = mc.current_server->next;
1260
block_time = 0; /* Call avahi to find new Mandos
1261
servers, but don't block */
1264
ret = avahi_simple_poll_iterate(s, (int)block_time);
1267
if (ret > 0 or errno != EINTR) {
1268
return (ret != 1) ? ret : 0;
1274
int main(int argc, char *argv[]){
1275
AvahiSServiceBrowser *sb = NULL;
1280
int exitcode = EXIT_SUCCESS;
1281
const char *interface = "";
1282
struct ifreq network;
1284
bool take_down_interface = false;
1287
char tempdir[] = "/tmp/mandosXXXXXX";
1288
bool tempdir_created = false;
1289
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1290
const char *seckey = PATHDIR "/" SECKEY;
1291
const char *pubkey = PATHDIR "/" PUBKEY;
1293
bool gnutls_initialized = false;
1294
bool gpgme_initialized = false;
1296
double retry_interval = 10; /* 10s between trying a server and
1297
retrying the same server again */
1299
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1300
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1305
/* Lower any group privileges we might have, just to be safe */
1309
perror_plus("setgid");
1312
/* Lower user privileges (temporarily) */
1316
perror_plus("seteuid");
1324
struct argp_option options[] = {
1325
{ .name = "debug", .key = 128,
1326
.doc = "Debug mode", .group = 3 },
1327
{ .name = "connect", .key = 'c',
1328
.arg = "ADDRESS:PORT",
1329
.doc = "Connect directly to a specific Mandos server",
1331
{ .name = "interface", .key = 'i',
1333
.doc = "Network interface that will be used to search for"
1336
{ .name = "seckey", .key = 's',
1338
.doc = "OpenPGP secret key file base name",
1340
{ .name = "pubkey", .key = 'p',
1342
.doc = "OpenPGP public key file base name",
1344
{ .name = "dh-bits", .key = 129,
1346
.doc = "Bit length of the prime number used in the"
1347
" Diffie-Hellman key exchange",
1349
{ .name = "priority", .key = 130,
1351
.doc = "GnuTLS priority string for the TLS handshake",
1353
{ .name = "delay", .key = 131,
1355
.doc = "Maximum delay to wait for interface startup",
1357
{ .name = "retry", .key = 132,
1359
.doc = "Retry interval used when denied by the mandos server",
1362
* These reproduce what we would get without ARGP_NO_HELP
1364
{ .name = "help", .key = '?',
1365
.doc = "Give this help list", .group = -1 },
1366
{ .name = "usage", .key = -3,
1367
.doc = "Give a short usage message", .group = -1 },
1368
{ .name = "version", .key = 'V',
1369
.doc = "Print program version", .group = -1 },
666
/* Combines file name and path and returns the malloced new
667
string. some sane checks could/should be added */
668
static const char *combinepath(const char *first, const char *second){
669
size_t f_len = strlen(first);
670
size_t s_len = strlen(second);
671
char *tmp = malloc(f_len + s_len + 2);
676
memcpy(tmp, first, f_len);
680
memcpy(tmp + f_len + 1, second, s_len);
682
tmp[f_len + 1 + s_len] = '\0';
687
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
688
AvahiServerConfig config;
689
AvahiSServiceBrowser *sb = NULL;
692
int returncode = EXIT_SUCCESS;
693
const char *interface = "eth0";
694
struct ifreq network;
696
char *connect_to = NULL;
697
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
698
mandos_context mc = { .simple_poll = NULL, .server = NULL,
699
.dh_bits = 2048, .priority = "SECURE256"};
1373
error_t parse_opt(int key, char *arg,
1374
struct argp_state *state){
1377
case 128: /* --debug */
1380
case 'c': /* --connect */
1383
case 'i': /* --interface */
1386
case 's': /* --seckey */
1389
case 'p': /* --pubkey */
1392
case 129: /* --dh-bits */
1394
tmpmax = strtoimax(arg, &tmp, 10);
1395
if(errno != 0 or tmp == arg or *tmp != '\0'
1396
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1397
argp_error(state, "Bad number of DH bits");
1399
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1401
case 130: /* --priority */
1404
case 131: /* --delay */
1406
delay = strtof(arg, &tmp);
1407
if(errno != 0 or tmp == arg or *tmp != '\0'){
1408
argp_error(state, "Bad delay");
1410
case 132: /* --retry */
1412
retry_interval = strtod(arg, &tmp);
1413
if(errno != 0 or tmp == arg or *tmp != '\0'
1414
or (retry_interval * 1000) > INT_MAX){
1415
argp_error(state, "Bad retry interval");
1419
* These reproduce what we would get without ARGP_NO_HELP
1421
case '?': /* --help */
1422
argp_state_help(state, state->out_stream,
1423
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1424
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1425
case -3: /* --usage */
1426
argp_state_help(state, state->out_stream,
1427
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1428
case 'V': /* --version */
1429
fprintf(state->out_stream, "%s\n", argp_program_version);
1430
exit(argp_err_exit_status);
702
static struct option long_options[] = {
703
{"debug", no_argument, (int *)&debug, 1},
704
{"connect", required_argument, 0, 'C'},
705
{"interface", required_argument, 0, 'i'},
706
{"certdir", required_argument, 0, 'd'},
707
{"certkey", required_argument, 0, 'c'},
708
{"certfile", required_argument, 0, 'k'},
709
{"dh_bits", required_argument, 0, 'D'},
710
{"priority", required_argument, 0, 'p'},
713
int option_index = 0;
714
ret = getopt_long (argc, argv, "i:", long_options,
743
tmp = strtol(optarg, NULL, 10);
744
if (errno == ERANGE){
752
mc.priority = optarg;
1433
return ARGP_ERR_UNKNOWN;
1438
struct argp argp = { .options = options, .parser = parse_opt,
1440
.doc = "Mandos client -- Get and decrypt"
1441
" passwords from a Mandos server" };
1442
ret = argp_parse(&argp, argc, argv,
1443
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
1450
perror_plus("argp_parse");
1451
exitcode = EX_OSERR;
1454
exitcode = EX_USAGE;
1460
/* Work around Debian bug #633582:
1461
<http://bugs.debian.org/633582> */
1464
/* Re-raise priviliges */
1468
perror_plus("seteuid");
1471
int seckey_fd = open(PATHDIR "/" SECKEY, O_RDONLY);
1472
if(seckey_fd == -1){
1473
perror_plus("open");
1475
ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
1477
perror_plus("fstat");
1479
if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
1480
ret = fchown(seckey_fd, uid, gid);
1482
perror_plus("fchown");
1486
TEMP_FAILURE_RETRY(close(seckey_fd));
1489
int pubkey_fd = open(PATHDIR "/" PUBKEY, O_RDONLY);
1490
if(pubkey_fd == -1){
1491
perror_plus("open");
1493
ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
1495
perror_plus("fstat");
1497
if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
1498
ret = fchown(pubkey_fd, uid, gid);
1500
perror_plus("fchown");
1504
TEMP_FAILURE_RETRY(close(pubkey_fd));
1507
/* Lower privileges */
1511
perror_plus("seteuid");
1516
avahi_set_log_function(empty_log);
759
certfile = combinepath(certdir, certfile);
760
if (certfile == NULL){
761
perror("combinepath");
762
returncode = EXIT_FAILURE;
1519
if(interface[0] == '\0'){
1520
struct dirent **direntries;
1521
ret = scandir(sys_class_net, &direntries, good_interface,
1524
/* Pick the first good interface */
1525
interface = strdup(direntries[0]->d_name);
1527
fprintf(stderr, "Using interface \"%s\"\n", interface);
1529
if(interface == NULL){
1530
perror_plus("malloc");
1532
exitcode = EXIT_FAILURE;
1538
fprintf(stderr, "Could not find a network interface\n");
1539
exitcode = EXIT_FAILURE;
1544
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1545
from the signal handler */
1546
/* Initialize the pseudo-RNG for Avahi */
1547
srand((unsigned int) time(NULL));
1548
mc.simple_poll = avahi_simple_poll_new();
1549
if(mc.simple_poll == NULL){
1550
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1551
exitcode = EX_UNAVAILABLE;
1555
sigemptyset(&sigterm_action.sa_mask);
1556
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1558
perror_plus("sigaddset");
1559
exitcode = EX_OSERR;
1562
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1564
perror_plus("sigaddset");
1565
exitcode = EX_OSERR;
1568
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1570
perror_plus("sigaddset");
1571
exitcode = EX_OSERR;
1574
/* Need to check if the handler is SIG_IGN before handling:
1575
| [[info:libc:Initial Signal Actions]] |
1576
| [[info:libc:Basic Signal Handling]] |
1578
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1580
perror_plus("sigaction");
1583
if(old_sigterm_action.sa_handler != SIG_IGN){
1584
ret = sigaction(SIGINT, &sigterm_action, NULL);
1586
perror_plus("sigaction");
1587
exitcode = EX_OSERR;
1591
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1593
perror_plus("sigaction");
1596
if(old_sigterm_action.sa_handler != SIG_IGN){
1597
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1599
perror_plus("sigaction");
1600
exitcode = EX_OSERR;
1604
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1606
perror_plus("sigaction");
1609
if(old_sigterm_action.sa_handler != SIG_IGN){
1610
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1612
perror_plus("sigaction");
1613
exitcode = EX_OSERR;
1618
/* If the interface is down, bring it up */
1619
if(strcmp(interface, "none") != 0){
766
certkey = combinepath(certdir, certkey);
767
if (certkey == NULL){
768
perror("combinepath");
769
returncode = EXIT_FAILURE;
1620
773
if_index = (AvahiIfIndex) if_nametoindex(interface);
1621
774
if(if_index == 0){
1622
775
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1623
exitcode = EX_UNAVAILABLE;
1631
/* Re-raise priviliges */
1635
perror_plus("seteuid");
1639
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1640
messages about the network interface to mess up the prompt */
1641
ret = klogctl(8, NULL, 5);
1642
bool restore_loglevel = true;
1644
restore_loglevel = false;
1645
perror_plus("klogctl");
1647
#endif /* __linux__ */
779
if(connect_to != NULL){
780
/* Connect directly, do not use Zeroconf */
781
/* (Mainly meant for debugging) */
782
char *address = strrchr(connect_to, ':');
784
fprintf(stderr, "No colon in address\n");
788
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
790
perror("Bad port number");
794
address = connect_to;
795
ret = start_mandos_communication(address, port, if_index);
1649
803
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1651
perror_plus("socket");
1652
exitcode = EX_OSERR;
1654
if(restore_loglevel){
1655
ret = klogctl(7, NULL, 0);
1657
perror_plus("klogctl");
1660
#endif /* __linux__ */
1661
/* Lower privileges */
1665
perror_plus("seteuid");
806
returncode = EXIT_FAILURE;
1669
strcpy(network.ifr_name, interface);
809
strcpy(network.ifr_name, interface);
1670
810
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1672
perror_plus("ioctl SIOCGIFFLAGS");
1674
if(restore_loglevel){
1675
ret = klogctl(7, NULL, 0);
1677
perror_plus("klogctl");
1680
#endif /* __linux__ */
1681
exitcode = EX_OSERR;
1682
/* Lower privileges */
1686
perror_plus("seteuid");
813
perror("ioctl SIOCGIFFLAGS");
814
returncode = EXIT_FAILURE;
1690
817
if((network.ifr_flags & IFF_UP) == 0){
1691
818
network.ifr_flags |= IFF_UP;
1692
take_down_interface = true;
1693
819
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1695
take_down_interface = false;
1696
perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1697
exitcode = EX_OSERR;
1699
if(restore_loglevel){
1700
ret = klogctl(7, NULL, 0);
1702
perror_plus("klogctl");
1705
#endif /* __linux__ */
1706
/* Lower privileges */
1710
perror_plus("seteuid");
1715
/* Sleep checking until interface is running.
1716
Check every 0.25s, up to total time of delay */
1717
for(int i=0; i < delay * 4; i++){
1718
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1720
perror_plus("ioctl SIOCGIFFLAGS");
1721
} else if(network.ifr_flags & IFF_RUNNING){
1724
struct timespec sleeptime = { .tv_nsec = 250000000 };
1725
ret = nanosleep(&sleeptime, NULL);
1726
if(ret == -1 and errno != EINTR){
1727
perror_plus("nanosleep");
1730
if(not take_down_interface){
1731
/* We won't need the socket anymore */
1732
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1734
perror_plus("close");
1738
if(restore_loglevel){
1739
/* Restores kernel loglevel to default */
1740
ret = klogctl(7, NULL, 0);
1742
perror_plus("klogctl");
1745
#endif /* __linux__ */
1746
/* Lower privileges */
1748
if(take_down_interface){
1749
/* Lower privileges */
1752
perror_plus("seteuid");
1755
/* Lower privileges permanently */
1758
perror_plus("setuid");
1767
ret = init_gnutls_global(pubkey, seckey);
1769
fprintf(stderr, "init_gnutls_global failed\n");
1770
exitcode = EX_UNAVAILABLE;
1773
gnutls_initialized = true;
1780
if(mkdtemp(tempdir) == NULL){
1781
perror_plus("mkdtemp");
1784
tempdir_created = true;
1790
if(not init_gpgme(pubkey, seckey, tempdir)){
1791
fprintf(stderr, "init_gpgme failed\n");
1792
exitcode = EX_UNAVAILABLE;
1795
gpgme_initialized = true;
1802
if(connect_to != NULL){
1803
/* Connect directly, do not use Zeroconf */
1804
/* (Mainly meant for debugging) */
1805
char *address = strrchr(connect_to, ':');
1806
if(address == NULL){
1807
fprintf(stderr, "No colon in address\n");
1808
exitcode = EX_USAGE;
1818
tmpmax = strtoimax(address+1, &tmp, 10);
1819
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1820
or tmpmax != (uint16_t)tmpmax){
1821
fprintf(stderr, "Bad port number\n");
1822
exitcode = EX_USAGE;
1830
port = (uint16_t)tmpmax;
1832
address = connect_to;
1833
/* Colon in address indicates IPv6 */
1835
if(strchr(address, ':') != NULL){
1845
while(not quit_now){
1846
ret = start_mandos_communication(address, port, if_index, af);
1847
if(quit_now or ret == 0){
1850
sleep((int)retry_interval or 1);
1854
exitcode = EXIT_SUCCESS;
1865
AvahiServerConfig config;
1866
/* Do not publish any local Zeroconf records */
821
perror("ioctl SIOCSIFFLAGS");
822
returncode = EXIT_FAILURE;
829
avahi_set_log_function(empty_log);
832
/* Initialize the psuedo-RNG */
833
srand((unsigned int) time(NULL));
835
/* Allocate main loop object */
836
if (!(mc.simple_poll = avahi_simple_poll_new())) {
837
fprintf(stderr, "Failed to create simple poll object.\n");
838
returncode = EXIT_FAILURE;
842
/* Do not publish any local records */
1867
843
avahi_server_config_init(&config);
1868
844
config.publish_hinfo = 0;
1869
845
config.publish_addresses = 0;
1870
846
config.publish_workstation = 0;
1871
847
config.publish_domain = 0;
1873
849
/* Allocate a new server */
1874
mc.server = avahi_server_new(avahi_simple_poll_get
1875
(mc.simple_poll), &config, NULL,
1878
/* Free the Avahi configuration data */
850
mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
851
&config, NULL, NULL, &error);
853
/* Free the configuration data */
1879
854
avahi_server_config_free(&config);
1882
/* Check if creating the Avahi server object succeeded */
1883
if(mc.server == NULL){
1884
fprintf(stderr, "Failed to create Avahi server: %s\n",
1885
avahi_strerror(error));
1886
exitcode = EX_UNAVAILABLE;
1894
/* Create the Avahi service browser */
1895
sb = avahi_s_service_browser_new(mc.server, if_index,
1896
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1897
NULL, 0, browse_callback, NULL);
1899
fprintf(stderr, "Failed to create service browser: %s\n",
1900
avahi_strerror(avahi_server_errno(mc.server)));
1901
exitcode = EX_UNAVAILABLE;
1909
/* Run the main loop */
1912
fprintf(stderr, "Starting Avahi loop search\n");
1915
ret = avahi_loop_with_timeout(mc.simple_poll,
1916
(int)(retry_interval * 1000));
1918
fprintf(stderr, "avahi_loop_with_timeout exited %s\n",
1919
(ret == 0) ? "successfully" : "with error");
1925
fprintf(stderr, "%s exiting\n", argv[0]);
1928
/* Cleanup things */
1930
avahi_s_service_browser_free(sb);
1932
if(mc.server != NULL)
1933
avahi_server_free(mc.server);
1935
if(mc.simple_poll != NULL)
1936
avahi_simple_poll_free(mc.simple_poll);
1938
if(gnutls_initialized){
1939
gnutls_certificate_free_credentials(mc.cred);
1940
gnutls_global_deinit();
1941
gnutls_dh_params_deinit(mc.dh_params);
1944
if(gpgme_initialized){
1945
gpgme_release(mc.ctx);
1948
/* Cleans up the circular linked list of Mandos servers the client
1950
if(mc.current_server != NULL){
1951
mc.current_server->prev->next = NULL;
1952
while(mc.current_server != NULL){
1953
server *next = mc.current_server->next;
1954
free(mc.current_server);
1955
mc.current_server = next;
1959
/* Take down the network interface */
1960
if(take_down_interface){
1961
/* Re-raise priviliges */
1965
perror_plus("seteuid");
1968
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1970
perror_plus("ioctl SIOCGIFFLAGS");
1971
} else if(network.ifr_flags & IFF_UP) {
1972
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1973
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1975
perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
1978
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1980
perror_plus("close");
1982
/* Lower privileges permanently */
1986
perror_plus("setuid");
1991
/* Removes the GPGME temp directory and all files inside */
1992
if(tempdir_created){
1993
struct dirent **direntries = NULL;
1994
struct dirent *direntry = NULL;
1995
ret = scandir(tempdir, &direntries, notdotentries, alphasort);
1997
for(int i = 0; i < ret; i++){
1998
direntry = direntries[i];
1999
char *fullname = NULL;
2000
ret = asprintf(&fullname, "%s/%s", tempdir,
2003
perror_plus("asprintf");
2006
ret = remove(fullname);
2008
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
2015
/* need to be cleaned even if ret == 0 because man page doesn't
2019
perror_plus("scandir");
2021
ret = rmdir(tempdir);
2022
if(ret == -1 and errno != ENOENT){
2023
perror_plus("rmdir");
2028
sigemptyset(&old_sigterm_action.sa_mask);
2029
old_sigterm_action.sa_handler = SIG_DFL;
2030
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
2031
&old_sigterm_action,
2034
perror_plus("sigaction");
2037
ret = raise(signal_received);
2038
} while(ret != 0 and errno == EINTR);
2040
perror_plus("raise");
2043
TEMP_FAILURE_RETRY(pause());
856
/* Check if creating the server object succeeded */
858
fprintf(stderr, "Failed to create server: %s\n",
859
avahi_strerror(error));
860
returncode = EXIT_FAILURE;
864
/* Create the service browser */
865
sb = avahi_s_service_browser_new(mc.server, if_index,
867
"_mandos._tcp", NULL, 0,
868
browse_callback, &mc);
870
fprintf(stderr, "Failed to create service browser: %s\n",
871
avahi_strerror(avahi_server_errno(mc.server)));
872
returncode = EXIT_FAILURE;
876
/* Run the main loop */
879
fprintf(stderr, "Starting avahi loop search\n");
882
avahi_simple_poll_loop(simple_poll);
887
fprintf(stderr, "%s exiting\n", argv[0]);
892
avahi_s_service_browser_free(sb);
895
avahi_server_free(mc.server);
898
avahi_simple_poll_free(simple_poll);