71
71
                                   INET_ADDRSTRLEN, INET6_ADDRSTRLEN
 
73
73
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
 
74
 
                                   getuid(), getgid(), setuid(),
 
 
74
                                   getuid(), getgid(), seteuid(),
 
76
76
#include <arpa/inet.h>          /* inet_pton(), htons */
 
77
77
#include <iso646.h>             /* not, or, and */
 
 
80
80
                                   argp_parse(), ARGP_KEY_ARG,
 
81
81
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
 
82
82
#include <signal.h>             /* sigemptyset(), sigaddset(),
 
83
 
                                   sigaction(), SIGTERM, sigaction,
 
 
83
                                   sigaction(), SIGTERM, sig_atomic_t,
 
87
87
#include <sys/klog.h>           /* klogctl() */
 
 
310
310
        gpgme_recipient_t recipient;
 
311
311
        recipient = result->recipients;
 
313
 
          while(recipient != NULL){
 
314
 
            fprintf(stderr, "Public key algorithm: %s\n",
 
315
 
                    gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
316
 
            fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
317
 
            fprintf(stderr, "Secret key available: %s\n",
 
318
 
                    recipient->status == GPG_ERR_NO_SECKEY
 
320
 
            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;
 
 
476
474
static int init_gnutls_session(gnutls_session_t *session){
 
478
476
  /* GnuTLS session creation */
 
479
 
  ret = gnutls_init(session, GNUTLS_SERVER);
 
 
478
    ret = gnutls_init(session, GNUTLS_SERVER);
 
 
479
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
 
480
480
  if(ret != GNUTLS_E_SUCCESS){
 
481
481
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
 
482
482
            safer_gnutls_strerror(ret));
 
 
487
 
    ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
 
488
      ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
 
489
    } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
 
488
490
    if(ret != GNUTLS_E_SUCCESS){
 
489
491
      fprintf(stderr, "Syntax error at: %s\n", err);
 
490
492
      fprintf(stderr, "GnuTLS error: %s\n",
 
 
497
 
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
 
500
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
 
502
  } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
 
499
503
  if(ret != GNUTLS_E_SUCCESS){
 
500
504
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
 
501
505
            safer_gnutls_strerror(ret));
 
 
506
510
  /* ignore client certificate if any. */
 
507
 
  gnutls_certificate_server_set_request(*session,
 
 
511
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
 
510
513
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
 
 
516
519
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
517
520
                      __attribute__((unused)) const char *txt){}
 
 
522
sig_atomic_t quit_now = 0;
 
 
523
int signal_received = 0;
 
519
525
/* Called when a Mandos server is found */
 
520
526
static int start_mandos_communication(const char *ip, uint16_t port,
 
521
527
                                      AvahiIfIndex if_index,
 
 
529
  int ret, tcp_sd = -1;
 
526
532
    struct sockaddr_in in;
 
 
530
536
  char *decrypted_buffer;
 
531
537
  size_t buffer_length = 0;
 
532
538
  size_t buffer_capacity = 0;
 
533
 
  ssize_t decrypted_buffer_size;
 
536
541
  gnutls_session_t session;
 
537
542
  int pf;                       /* Protocol family */
 
 
561
570
  tcp_sd = socket(pf, SOCK_STREAM, 0);
 
563
572
    perror("socket");
 
567
581
  memset(&to, 0, sizeof(to));
 
568
582
  if(af == AF_INET6){
 
569
 
    to.in6.sin6_family = (uint16_t)af;
 
 
583
    to.in6.sin6_family = (sa_family_t)af;
 
570
584
    ret = inet_pton(af, ip, &to.in6.sin6_addr);
 
571
585
  } else {                      /* IPv4 */
 
572
586
    to.in.sin_family = (sa_family_t)af;
 
 
591
607
      if(if_index == AVAHI_IF_UNSPEC){
 
592
608
        fprintf(stderr, "An IPv6 link-local address is incomplete"
 
593
609
                " without a network interface\n");
 
596
613
      /* Set the network interface number as scope */
 
597
614
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
 
672
706
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
 
675
713
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
678
720
    ret = gnutls_handshake(session);
 
679
724
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
681
726
  if(ret != GNUTLS_E_SUCCESS){
 
 
714
768
      case GNUTLS_E_AGAIN:
 
716
770
      case GNUTLS_E_REHANDSHAKE:
 
718
772
          ret = gnutls_handshake(session);
 
719
777
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
721
779
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
 
740
798
    fprintf(stderr, "Closing TLS session\n");
 
743
805
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
745
811
  if(buffer_length > 0){
 
 
812
    ssize_t decrypted_buffer_size;
 
746
813
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
748
815
                                               &decrypted_buffer);
 
749
816
    if(decrypted_buffer_size >= 0){
 
751
819
      while(written < (size_t) decrypted_buffer_size){
 
752
824
        ret = (int)fwrite(decrypted_buffer + written, 1,
 
753
825
                          (size_t)decrypted_buffer_size - written,
 
 
880
 
sig_atomic_t quit_now = 0;
 
882
965
/* stop main loop after sigterm has been called */
 
883
 
static void handle_sigterm(__attribute__((unused)) int sig){
 
 
966
static void handle_sigterm(int sig){
 
 
971
  signal_received = sig;
 
888
972
  int old_errno = errno;
 
889
973
  if(mc.simple_poll != NULL){
 
890
974
    avahi_simple_poll_quit(mc.simple_poll);
 
 
915
1000
  bool gpgme_initialized = false;
 
916
1001
  float delay = 2.5f;
 
918
 
  struct sigaction old_sigterm_action;
 
 
1003
  struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
 
919
1004
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
 
 
1009
  /* Lower any group privileges we might have, just to be safe */
 
 
1016
  /* Lower user privileges (temporarily) */
 
922
1028
    struct argp_option options[] = {
 
923
1029
      { .name = "debug", .key = 128,
 
 
1050
1156
    exitcode = EXIT_FAILURE;
 
1053
 
  ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
 
1055
 
    perror("sigaction");
 
1056
 
    exitcode = EXIT_FAILURE;
 
 
1159
  /* Need to check if the handler is SIG_IGN before handling:
 
 
1160
     | [[info:libc:Initial Signal Actions]] |
 
 
1161
     | [[info:libc:Basic Signal Handling]]  |
 
 
1163
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
 
 
1165
    perror("sigaction");
 
 
1166
    return EXIT_FAILURE;
 
 
1168
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
 
1169
    ret = sigaction(SIGINT, &sigterm_action, NULL);
 
 
1171
      perror("sigaction");
 
 
1172
      exitcode = EXIT_FAILURE;
 
 
1176
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
 
 
1178
    perror("sigaction");
 
 
1179
    return EXIT_FAILURE;
 
 
1181
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
 
1182
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
 
 
1184
      perror("sigaction");
 
 
1185
      exitcode = EXIT_FAILURE;
 
 
1189
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
 
 
1191
    perror("sigaction");
 
 
1192
    return EXIT_FAILURE;
 
 
1194
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
 
1195
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
 
 
1197
      perror("sigaction");
 
 
1198
      exitcode = EXIT_FAILURE;
 
1060
1203
  /* If the interface is down, bring it up */
 
1061
1204
  if(interface[0] != '\0'){
 
 
1205
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
 
1207
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
 
1208
      exitcode = EXIT_FAILURE;
 
 
1216
    /* Re-raise priviliges */
 
1062
1223
#ifdef __linux__
 
1063
1224
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1064
1225
       messages to mess up the prompt */
 
 
1098
1265
#endif  /* __linux__ */
 
1099
1266
      exitcode = EXIT_FAILURE;
 
 
1267
      /* Lower privileges */
 
1102
1275
    if((network.ifr_flags & IFF_UP) == 0){
 
1103
1276
      network.ifr_flags |= IFF_UP;
 
 
1277
      take_down_interface = true;
 
1104
1278
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
 
1280
        take_down_interface = false;
 
1106
1281
        perror("ioctl SIOCSIFFLAGS");
 
1107
1282
        exitcode = EXIT_FAILURE;
 
1108
1283
#ifdef __linux__
 
 
1168
1357
    gnutls_initialized = true;
 
 
1364
  tempdir_created = true;
 
1171
1365
  if(mkdtemp(tempdir) == NULL){
 
 
1366
    tempdir_created = false;
 
1172
1367
    perror("mkdtemp");
 
1175
 
  tempdir_created = true;
 
1177
1375
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
1178
1376
    fprintf(stderr, "init_gpgme failed\n");
 
 
1182
1380
    gpgme_initialized = true;
 
1185
 
  if(interface[0] != '\0'){
 
1186
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
1188
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
1189
 
      exitcode = EXIT_FAILURE;
 
1194
1387
  if(connect_to != NULL){
 
 
1257
1473
  /* Create the Avahi service browser */
 
1258
1474
  sb = avahi_s_service_browser_new(mc.server, if_index,
 
1259
1475
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
 
 
1299
1519
    gpgme_release(mc.ctx);
 
 
1522
  /* Take down the network interface */
 
 
1523
  if(take_down_interface){
 
 
1524
    /* Re-raise priviliges */
 
 
1531
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
 
1533
        perror("ioctl SIOCGIFFLAGS");
 
 
1534
      } else if(network.ifr_flags & IFF_UP) {
 
 
1535
        network.ifr_flags &= ~IFF_UP; /* clear flag */
 
 
1536
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
 
1538
          perror("ioctl SIOCSIFFLAGS");
 
 
1541
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
 
1545
      /* Lower privileges permanently */
 
1302
1554
  /* Removes the temp directory used by GPGME */
 
1303
1555
  if(tempdir_created){