32
32
/* Needed by GPGME, specifically gpgme_data_seek() */
 
 
33
#ifndef _LARGEFILE_SOURCE
 
33
34
#define _LARGEFILE_SOURCE
 
 
36
#ifndef _FILE_OFFSET_BITS
 
34
37
#define _FILE_OFFSET_BITS 64
 
36
40
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
 
 
67
71
                                   INET_ADDRSTRLEN, INET6_ADDRSTRLEN
 
69
73
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
 
70
 
                                   getuid(), getgid(), setuid(),
 
 
74
                                   getuid(), getgid(), seteuid(),
 
72
76
#include <arpa/inet.h>          /* inet_pton(), htons */
 
73
77
#include <iso646.h>             /* not, or, and */
 
 
76
80
                                   argp_parse(), ARGP_KEY_ARG,
 
77
81
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
 
78
82
#include <signal.h>             /* sigemptyset(), sigaddset(),
 
79
 
                                   sigaction(), SIGTERM, sigaction,
 
 
83
                                   sigaction(), SIGTERM, sig_atomic_t,
 
83
87
#include <sys/klog.h>           /* klogctl() */
 
 
306
310
        gpgme_recipient_t recipient;
 
307
311
        recipient = result->recipients;
 
309
 
          while(recipient != NULL){
 
310
 
            fprintf(stderr, "Public key algorithm: %s\n",
 
311
 
                    gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
312
 
            fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
313
 
            fprintf(stderr, "Secret key available: %s\n",
 
314
 
                    recipient->status == GPG_ERR_NO_SECKEY
 
316
 
            recipient = recipient->next;
 
 
312
        while(recipient != NULL){
 
 
313
          fprintf(stderr, "Public key algorithm: %s\n",
 
 
314
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
 
315
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
 
316
          fprintf(stderr, "Secret key available: %s\n",
 
 
317
                  recipient->status == GPG_ERR_NO_SECKEY
 
 
319
          recipient = recipient->next;
 
 
512
514
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
513
515
                      __attribute__((unused)) const char *txt){}
 
 
517
sig_atomic_t quit_now = 0;
 
 
518
int signal_received = 0;
 
515
520
/* Called when a Mandos server is found */
 
516
521
static int start_mandos_communication(const char *ip, uint16_t port,
 
517
522
                                      AvahiIfIndex if_index,
 
 
524
  int ret, tcp_sd = -1;
 
522
527
    struct sockaddr_in in;
 
 
526
531
  char *decrypted_buffer;
 
527
532
  size_t buffer_length = 0;
 
528
533
  size_t buffer_capacity = 0;
 
529
 
  ssize_t decrypted_buffer_size;
 
532
536
  gnutls_session_t session;
 
533
537
  int pf;                       /* Protocol family */
 
 
557
565
  tcp_sd = socket(pf, SOCK_STREAM, 0);
 
559
567
    perror("socket");
 
563
576
  memset(&to, 0, sizeof(to));
 
564
577
  if(af == AF_INET6){
 
565
 
    to.in6.sin6_family = (uint16_t)af;
 
 
578
    to.in6.sin6_family = (sa_family_t)af;
 
566
579
    ret = inet_pton(af, ip, &to.in6.sin6_addr);
 
567
580
  } else {                      /* IPv4 */
 
568
581
    to.in.sin_family = (sa_family_t)af;
 
 
587
602
      if(if_index == AVAHI_IF_UNSPEC){
 
588
603
        fprintf(stderr, "An IPv6 link-local address is incomplete"
 
589
604
                " without a network interface\n");
 
592
608
      /* Set the network interface number as scope */
 
593
609
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
 
668
701
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
671
708
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
674
715
    ret = gnutls_handshake(session);
 
675
719
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
677
721
  if(ret != GNUTLS_E_SUCCESS){
 
 
710
763
      case GNUTLS_E_AGAIN:
 
712
765
      case GNUTLS_E_REHANDSHAKE:
 
714
767
          ret = gnutls_handshake(session);
 
715
772
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
717
774
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
 
736
793
    fprintf(stderr, "Closing TLS session\n");
 
739
800
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
741
806
  if(buffer_length > 0){
 
 
807
    ssize_t decrypted_buffer_size;
 
742
808
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
744
810
                                               &decrypted_buffer);
 
745
811
    if(decrypted_buffer_size >= 0){
 
747
814
      while(written < (size_t) decrypted_buffer_size){
 
748
819
        ret = (int)fwrite(decrypted_buffer + written, 1,
 
749
820
                          (size_t)decrypted_buffer_size - written,
 
 
876
 
sig_atomic_t quit_now = 0;
 
878
960
/* stop main loop after sigterm has been called */
 
879
 
static void handle_sigterm(__attribute__((unused)) int sig){
 
 
961
static void handle_sigterm(int sig){
 
 
966
  signal_received = sig;
 
884
967
  int old_errno = errno;
 
885
968
  if(mc.simple_poll != NULL){
 
886
969
    avahi_simple_poll_quit(mc.simple_poll);
 
 
1046
1130
    exitcode = EXIT_FAILURE;
 
1049
 
  ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
 
1051
 
    perror("sigaction");
 
1052
 
    exitcode = EXIT_FAILURE;
 
 
1133
  /* Need to check if the handler is SIG_IGN before handling:
 
 
1134
     | [[info:libc:Initial Signal Actions]] |
 
 
1135
     | [[info:libc:Basic Signal Handling]]  |
 
 
1137
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
 
 
1139
    perror("sigaction");
 
 
1140
    return EXIT_FAILURE;
 
 
1142
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
 
1143
    ret = sigaction(SIGINT, &sigterm_action, NULL);
 
 
1145
      perror("sigaction");
 
 
1146
      exitcode = EXIT_FAILURE;
 
 
1150
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
 
 
1152
    perror("sigaction");
 
 
1153
    return EXIT_FAILURE;
 
 
1155
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
 
1156
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
 
 
1158
      perror("sigaction");
 
 
1159
      exitcode = EXIT_FAILURE;
 
 
1163
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
 
 
1165
    perror("sigaction");
 
 
1166
    return EXIT_FAILURE;
 
 
1168
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
 
1169
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
 
 
1171
      perror("sigaction");
 
 
1172
      exitcode = EXIT_FAILURE;
 
1056
1177
  /* If the interface is down, bring it up */
 
1057
1178
  if(interface[0] != '\0'){
 
 
1179
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
 
1181
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
 
1182
      exitcode = EXIT_FAILURE;
 
1058
1190
#ifdef __linux__
 
1059
1191
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1060
1192
       messages to mess up the prompt */
 
 
1098
1230
    if((network.ifr_flags & IFF_UP) == 0){
 
1099
1231
      network.ifr_flags |= IFF_UP;
 
 
1232
      take_down_interface = true;
 
1100
1233
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
 
1235
        take_down_interface = false;
 
1102
1236
        perror("ioctl SIOCSIFFLAGS");
 
1103
1237
        exitcode = EXIT_FAILURE;
 
1104
1238
#ifdef __linux__
 
 
1141
1278
#endif  /* __linux__ */
 
1144
1285
  uid = getuid();
 
1145
1286
  gid = getgid();
 
 
1288
  /* Drop any group privileges we might have, just to be safe */
 
1150
1292
    perror("setgid");
 
 
1295
  /* Drop user privileges */
 
 
1297
  /* Will we need privileges later? */
 
 
1298
  if(take_down_interface){
 
 
1299
    /* Drop user privileges temporarily */
 
 
1305
    /* Drop user privileges permanently */
 
1158
1316
  ret = init_gnutls_global(pubkey, seckey);
 
 
1164
1322
    gnutls_initialized = true;
 
 
1329
  tempdir_created = true;
 
1167
1330
  if(mkdtemp(tempdir) == NULL){
 
 
1331
    tempdir_created = false;
 
1168
1332
    perror("mkdtemp");
 
1171
 
  tempdir_created = true;
 
1173
1340
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
1174
1341
    fprintf(stderr, "init_gpgme failed\n");
 
 
1178
1345
    gpgme_initialized = true;
 
1181
 
  if(interface[0] != '\0'){
 
1182
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
1184
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
1185
 
      exitcode = EXIT_FAILURE;
 
1190
1352
  if(connect_to != NULL){
 
 
1253
1438
  /* Create the Avahi service browser */
 
1254
1439
  sb = avahi_s_service_browser_new(mc.server, if_index,
 
1255
1440
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
 
 
1295
1484
    gpgme_release(mc.ctx);
 
 
1487
  /* Take down the network interface */
 
 
1488
  if(take_down_interface){
 
 
1489
    /* Re-raise priviliges */
 
 
1496
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
 
1498
        perror("ioctl SIOCGIFFLAGS");
 
 
1499
      } else if(network.ifr_flags & IFF_UP) {
 
 
1500
        network.ifr_flags &= ~IFF_UP; /* clear flag */
 
 
1501
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
 
1503
          perror("ioctl SIOCSIFFLAGS");
 
 
1506
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
 
1510
      /* Lower privileges, permanently this time */
 
1298
1519
  /* Removes the temp directory used by GPGME */
 
1299
1520
  if(tempdir_created){