/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/mandos-client.c

  • Committer: Teddy Hogeborn
  • Date: 2015-07-01 20:01:26 UTC
  • mto: (237.7.307 trunk)
  • mto: This revision was merged to the branch mainline in revision 325.
  • Revision ID: teddy@recompile.se-20150701200126-qb3f6c3jcas2f4og
mandos-client: Try to start a plugin to add and remove a local route.

* debian/mandos-client.README.Debian: Add setting of environment
                                      variable MANDOSPLUGINHELPERDIR
                                      to command line testing
                                      mandos-client.
* mandos-client.c (raise_privileges): Moved to top of file.
                  (raise_privileges_permanently): - '' -
                  (lower_privileges): - '' -
                  (lower_privileges_permanently): - '' -
  (add_remove_local_route, add_local_route, remove_local_route): New.
  (start_mandos_communication): Set SOCK_CLOEXEC flag on socket.  Run
                                the above functions to add (and
                                remove) local route, if the conditions
                                indicates it could help.
  (run_network_hooks): Use O_DIRECTORY, O_PATH, and O_CLOEXEC flags
                       when opening network hook directory. Do
                       TEMP_FAILURE_RETRY around opening of /dev/null
                       and network hook executables.  Move redirecting
                       of stdout and stderr to as late as possible
                       before fexecve().
  (main): Use O_DIRECTORY and O_PATH when opening temporary directory.
* plugins.d/mandos-client.xml (ENVIRONMENT): Document usage of the
                                             MANDOSPLUGINHELPERDIR
                                             environment variable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
493
493
  return plaintext_length;
494
494
}
495
495
 
496
 
__attribute__((warn_unused_result, const))
497
 
static const char *safe_string(const char *str){
498
 
  if(str == NULL)
499
 
    return "(unknown)";
500
 
  return str;
501
 
}
502
 
 
503
496
__attribute__((warn_unused_result))
504
497
static const char *safer_gnutls_strerror(int value){
505
498
  const char *ret = gnutls_strerror(value);
506
 
  return safe_string(ret);
 
499
  if(ret == NULL)
 
500
    ret = "(unknown)";
 
501
  return ret;
507
502
}
508
503
 
509
504
/* GnuTLS log function callback */
518
513
                              const char *seckeyfilename,
519
514
                              mandos_context *mc){
520
515
  int ret;
521
 
  unsigned int uret;
522
516
  
523
517
  if(debug){
524
518
    fprintf_plus(stderr, "Initializing GnuTLS\n");
575
569
                 safer_gnutls_strerror(ret));
576
570
    goto globalfail;
577
571
  }
578
 
  if(mc->dh_bits == 0){
579
 
    /* Find out the optimal number of DH bits */
580
 
    /* Try to read the private key file */
581
 
    gnutls_datum_t buffer = { .data = NULL, .size = 0 };
582
 
    {
583
 
      int secfile = open(seckeyfilename, O_RDONLY);
584
 
      size_t buffer_capacity = 0;
585
 
      while(true){
586
 
        buffer_capacity = incbuffer((char **)&buffer.data,
587
 
                                    (size_t)buffer.size,
588
 
                                    (size_t)buffer_capacity);
589
 
        if(buffer_capacity == 0){
590
 
          perror_plus("incbuffer");
591
 
          free(buffer.data);
592
 
          buffer.data = NULL;
593
 
          break;
594
 
        }
595
 
        ssize_t bytes_read = read(secfile, buffer.data + buffer.size,
596
 
                                  BUFFER_SIZE);
597
 
        /* EOF */
598
 
        if(bytes_read == 0){
599
 
          break;
600
 
        }
601
 
        /* check bytes_read for failure */
602
 
        if(bytes_read < 0){
603
 
          perror_plus("read");
604
 
          free(buffer.data);
605
 
          buffer.data = NULL;
606
 
          break;
607
 
        }
608
 
        buffer.size += (unsigned int)bytes_read;
609
 
      }
610
 
      close(secfile);
611
 
    }
612
 
    /* If successful, use buffer to parse private key */
613
 
    gnutls_sec_param_t sec_param = GNUTLS_SEC_PARAM_ULTRA;
614
 
    if(buffer.data != NULL){
615
 
      {
616
 
        gnutls_openpgp_privkey_t privkey = NULL;
617
 
        ret = gnutls_openpgp_privkey_init(&privkey);
618
 
        if(ret != GNUTLS_E_SUCCESS){
619
 
          fprintf_plus(stderr, "Error initializing OpenPGP key"
620
 
                       " structure: %s", safer_gnutls_strerror(ret));
621
 
          free(buffer.data);
622
 
          buffer.data = NULL;
623
 
        } else {
624
 
          ret = gnutls_openpgp_privkey_import(privkey, &buffer,
625
 
                                            GNUTLS_OPENPGP_FMT_BASE64,
626
 
                                              "", 0);
627
 
          if(ret != GNUTLS_E_SUCCESS){
628
 
            fprintf_plus(stderr, "Error importing OpenPGP key : %s",
629
 
                         safer_gnutls_strerror(ret));
630
 
            privkey = NULL;
631
 
          }
632
 
          free(buffer.data);
633
 
          buffer.data = NULL;
634
 
          if(privkey != NULL){
635
 
            /* Use private key to suggest an appropriate sec_param */
636
 
            sec_param = gnutls_openpgp_privkey_sec_param(privkey);
637
 
            gnutls_openpgp_privkey_deinit(privkey);
638
 
            if(debug){
639
 
              fprintf_plus(stderr, "This OpenPGP key implies using a"
640
 
                           " GnuTLS security parameter \"%s\".\n",
641
 
                           safe_string(gnutls_sec_param_get_name
642
 
                                       (sec_param)));
643
 
            }
644
 
          }
645
 
        }
646
 
      }
647
 
      if(sec_param == GNUTLS_SEC_PARAM_UNKNOWN){
648
 
        /* Err on the side of caution */
649
 
        sec_param = GNUTLS_SEC_PARAM_ULTRA;
650
 
        if(debug){
651
 
          fprintf_plus(stderr, "Falling back to security parameter"
652
 
                       " \"%s\"\n",
653
 
                       safe_string(gnutls_sec_param_get_name
654
 
                                   (sec_param)));
655
 
        }
656
 
      }
657
 
    }
658
 
    uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
659
 
    if(uret != 0){
660
 
      mc->dh_bits = uret;
661
 
      if(debug){
662
 
        fprintf_plus(stderr, "A \"%s\" GnuTLS security parameter"
663
 
                     " implies %u DH bits; using that.\n",
664
 
                     safe_string(gnutls_sec_param_get_name
665
 
                                 (sec_param)),
666
 
                     mc->dh_bits);
667
 
      }
668
 
    } else {
669
 
      fprintf_plus(stderr, "Failed to get implied number of DH"
670
 
                   " bits for security parameter \"%s\"): %s\n",
671
 
                   safe_string(gnutls_sec_param_get_name(sec_param)),
672
 
                   safer_gnutls_strerror(ret));
673
 
      goto globalfail;
674
 
    }
675
 
  } else if(debug){
676
 
    fprintf_plus(stderr, "DH bits explicitly set to %u\n",
677
 
                 mc->dh_bits);
678
 
  }
679
572
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
680
573
  if(ret != GNUTLS_E_SUCCESS){
681
 
    fprintf_plus(stderr, "Error in GnuTLS prime generation (%u bits):"
682
 
                 " %s\n", mc->dh_bits, safer_gnutls_strerror(ret));
 
574
    fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
 
575
                 safer_gnutls_strerror(ret));
683
576
    goto globalfail;
684
577
  }
685
578
  
809
702
  return ret_errno;
810
703
}
811
704
 
812
 
/* Helper function to add_local_route() and delete_local_route() */
 
705
/* Helper function to add_local_route() and remove_local_route() */
813
706
__attribute__((nonnull, warn_unused_result))
814
 
static bool add_delete_local_route(const bool add,
 
707
static bool add_remove_local_route(const bool add,
815
708
                                   const char *address,
816
709
                                   AvahiIfIndex if_index){
817
710
  int ret;
818
711
  char helper[] = "mandos-client-iprouteadddel";
819
712
  char add_arg[] = "add";
820
 
  char delete_arg[] = "delete";
821
 
  char debug_flag[] = "--debug";
 
713
  char remove_arg[] = "remove";
822
714
  char *pluginhelperdir = getenv("MANDOSPLUGINHELPERDIR");
823
715
  if(pluginhelperdir == NULL){
824
716
    if(debug){
868
760
      perror_plus("dup2(devnull, STDIN_FILENO)");
869
761
      _exit(EX_OSERR);
870
762
    }
871
 
    ret = (int)TEMP_FAILURE_RETRY(close(devnull));
 
763
    ret = close(devnull);
872
764
    if(ret == -1){
873
765
      perror_plus("close");
874
766
      _exit(EX_OSERR);
883
775
                                                    | O_DIRECTORY
884
776
                                                    | O_PATH
885
777
                                                    | O_CLOEXEC));
886
 
    if(helperdir_fd == -1){
887
 
      perror_plus("open");
888
 
      _exit(EX_UNAVAILABLE);
889
 
    }
890
778
    int helper_fd = (int)TEMP_FAILURE_RETRY(openat(helperdir_fd,
891
779
                                                   helper, O_RDONLY));
892
 
    if(helper_fd == -1){
893
 
      perror_plus("openat");
894
 
      _exit(EX_UNAVAILABLE);
895
 
    }
896
780
    TEMP_FAILURE_RETRY(close(helperdir_fd));
897
781
#ifdef __GNUC__
898
782
#pragma GCC diagnostic push
899
783
#pragma GCC diagnostic ignored "-Wcast-qual"
900
784
#endif
901
785
    if(fexecve(helper_fd, (char *const [])
902
 
               { helper, add ? add_arg : delete_arg, (char *)address,
903
 
                   interface, debug ? debug_flag : NULL, NULL },
904
 
               environ) == -1){
 
786
               { helper, add ? add_arg : remove_arg, (char *)address,
 
787
                   interface, NULL }, environ) == -1){
905
788
#ifdef __GNUC__
906
789
#pragma GCC diagnostic pop
907
790
#endif
959
842
__attribute__((nonnull, warn_unused_result))
960
843
static bool add_local_route(const char *address,
961
844
                            AvahiIfIndex if_index){
962
 
  if(debug){
963
 
    fprintf_plus(stderr, "Adding route to %s\n", address);
964
 
  }
965
 
  return add_delete_local_route(true, address, if_index);
 
845
  return add_remove_local_route(true, address, if_index);
966
846
}
967
847
 
968
848
__attribute__((nonnull, warn_unused_result))
969
 
static bool delete_local_route(const char *address,
 
849
static bool remove_local_route(const char *address,
970
850
                               AvahiIfIndex if_index){
971
 
  if(debug){
972
 
    fprintf_plus(stderr, "Removing route to %s\n", address);
973
 
  }
974
 
  return add_delete_local_route(false, address, if_index);
 
851
  return add_remove_local_route(false, address, if_index);
975
852
}
976
853
 
977
854
/* Called when a Mandos server is found */
1180
1057
           http://lists.freedesktop.org/archives/avahi/2010-February/001833.html
1181
1058
           https://bugs.debian.org/587961
1182
1059
        */
1183
 
        if(debug){
1184
 
          fprintf_plus(stderr, "Mandos server unreachable, trying"
1185
 
                       " direct route\n");
1186
 
        }
1187
1060
        int e = errno;
1188
1061
        route_added = add_local_route(ip, if_index);
1189
1062
        if(route_added){
1393
1266
 mandos_end:
1394
1267
  {
1395
1268
    if(route_added){
1396
 
      if(not delete_local_route(ip, if_index)){
1397
 
        fprintf_plus(stderr, "Failed to delete local route to %s on"
 
1269
      if(not remove_local_route(ip, if_index)){
 
1270
        fprintf_plus(stderr, "Failed to remove local route to %s on"
1398
1271
                     " interface %d", ip, if_index);
1399
1272
      }
1400
1273
    }
1940
1813
          _exit(EX_OSERR);
1941
1814
        }
1942
1815
      }
1943
 
      int hook_fd = (int)TEMP_FAILURE_RETRY(openat(hookdir_fd,
1944
 
                                                   direntry->d_name,
1945
 
                                                   O_RDONLY));
 
1816
      int hook_fd = TEMP_FAILURE_RETRY(openat(hookdir_fd,
 
1817
                                              direntry->d_name,
 
1818
                                              O_RDONLY));
1946
1819
      if(hook_fd == -1){
1947
1820
        perror_plus("openat");
1948
1821
        _exit(EXIT_FAILURE);
1956
1829
        perror_plus("dup2(devnull, STDIN_FILENO)");
1957
1830
        _exit(EX_OSERR);
1958
1831
      }
1959
 
      ret = (int)TEMP_FAILURE_RETRY(close(devnull));
 
1832
      ret = close(devnull);
1960
1833
      if(ret == -1){
1961
1834
        perror_plus("close");
1962
1835
        _exit(EX_OSERR);
2222
2095
}
2223
2096
 
2224
2097
int main(int argc, char *argv[]){
2225
 
  mandos_context mc = { .server = NULL, .dh_bits = 0,
 
2098
  mandos_context mc = { .server = NULL, .dh_bits = 1024,
2226
2099
                        .priority = "SECURE256:!CTYPE-X.509:"
2227
 
                        "+CTYPE-OPENPGP:!RSA", .current_server = NULL,
 
2100
                        "+CTYPE-OPENPGP", .current_server = NULL,
2228
2101
                        .interfaces = NULL, .interfaces_size = 0 };
2229
2102
  AvahiSServiceBrowser *sb = NULL;
2230
2103
  error_t ret_errno;