57
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
58
58
                                   inet_pton(), connect(),
 
60
 
#include <fcntl.h>              /* open(), unlinkat(), AT_REMOVEDIR */
 
 
60
#include <fcntl.h>              /* open(), unlinkat() */
 
61
61
#include <dirent.h>             /* opendir(), struct dirent, readdir()
 
63
63
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
 
65
 
#include <errno.h>              /* perror(), errno, EINTR, EINVAL,
 
66
 
                                   EAI_SYSTEM, ENETUNREACH,
 
67
 
                                   EHOSTUNREACH, ECONNREFUSED, EPROTO,
 
68
 
                                   EIO, ENOENT, ENXIO, ENOMEM, EISDIR,
 
 
65
#include <errno.h>              /* perror(), errno,
 
70
66
                                   program_invocation_short_name */
 
71
67
#include <time.h>               /* nanosleep(), time(), sleep() */
 
72
68
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
 
 
572
575
                 safer_gnutls_strerror(ret));
 
575
 
  /* If a Diffie-Hellman parameters file was given, try to use it */
 
576
 
  if(dhparamsfilename != NULL){
 
577
 
    gnutls_datum_t params = { .data = NULL, .size = 0 };
 
579
 
      int dhpfile = open(dhparamsfilename, O_RDONLY);
 
582
 
        dhparamsfilename = NULL;
 
585
 
      size_t params_capacity = 0;
 
 
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 };
 
 
583
      int secfile = open(seckeyfilename, O_RDONLY);
 
 
584
      size_t buffer_capacity = 0;
 
587
 
        params_capacity = incbuffer((char **)¶ms.data,
 
589
 
                                    (size_t)params_capacity);
 
590
 
        if(params_capacity == 0){
 
 
586
        buffer_capacity = incbuffer((char **)&buffer.data,
 
 
588
                                    (size_t)buffer_capacity);
 
 
589
        if(buffer_capacity == 0){
 
591
590
          perror_plus("incbuffer");
 
594
 
          dhparamsfilename = NULL;
 
597
 
        ssize_t bytes_read = read(dhpfile,
 
598
 
                                  params.data + params.size,
 
 
595
        ssize_t bytes_read = read(secfile, buffer.data + buffer.size,
 
601
598
        if(bytes_read == 0){
 
 
604
601
        /* check bytes_read for failure */
 
605
602
        if(bytes_read < 0){
 
606
603
          perror_plus("read");
 
609
 
          dhparamsfilename = NULL;
 
612
 
        params.size += (unsigned int)bytes_read;
 
614
 
      if(params.data == NULL){
 
615
 
        dhparamsfilename = NULL;
 
617
 
      if(dhparamsfilename == NULL){
 
620
 
      ret = gnutls_dh_params_import_pkcs3(mc->dh_params, ¶ms,
 
621
 
                                          GNUTLS_X509_FMT_PEM);
 
622
 
      if(ret != GNUTLS_E_SUCCESS){
 
623
 
        fprintf_plus(stderr, "Failed to parse DH parameters in file"
 
624
 
                     " \"%s\": %s\n", dhparamsfilename,
 
625
 
                     safer_gnutls_strerror(ret));
 
626
 
        dhparamsfilename = NULL;
 
630
 
  if(dhparamsfilename == NULL){
 
631
 
    if(mc->dh_bits == 0){
 
632
 
      /* Find out the optimal number of DH bits */
 
633
 
      /* Try to read the private key file */
 
634
 
      gnutls_datum_t buffer = { .data = NULL, .size = 0 };
 
636
 
        int secfile = open(seckeyfilename, O_RDONLY);
 
641
 
        size_t buffer_capacity = 0;
 
643
 
          buffer_capacity = incbuffer((char **)&buffer.data,
 
645
 
                                      (size_t)buffer_capacity);
 
646
 
          if(buffer_capacity == 0){
 
647
 
            perror_plus("incbuffer");
 
652
 
          ssize_t bytes_read = read(secfile,
 
653
 
                                    buffer.data + buffer.size,
 
659
 
          /* check bytes_read for failure */
 
666
 
          buffer.size += (unsigned int)bytes_read;
 
670
 
      /* If successful, use buffer to parse private key */
 
671
 
      gnutls_sec_param_t sec_param = GNUTLS_SEC_PARAM_ULTRA;
 
672
 
      if(buffer.data != NULL){
 
674
 
          gnutls_openpgp_privkey_t privkey = NULL;
 
675
 
          ret = gnutls_openpgp_privkey_init(&privkey);
 
 
608
        buffer.size += (unsigned int)bytes_read;
 
 
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){
 
 
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));
 
 
624
          ret = gnutls_openpgp_privkey_import(privkey, &buffer,
 
 
625
                                            GNUTLS_OPENPGP_FMT_BASE64,
 
676
627
          if(ret != GNUTLS_E_SUCCESS){
 
677
 
            fprintf_plus(stderr, "Error initializing OpenPGP key"
 
 
628
            fprintf_plus(stderr, "Error importing OpenPGP key : %s",
 
679
629
                         safer_gnutls_strerror(ret));
 
683
 
            ret = gnutls_openpgp_privkey_import
 
684
 
              (privkey, &buffer, GNUTLS_OPENPGP_FMT_BASE64, "", 0);
 
685
 
            if(ret != GNUTLS_E_SUCCESS){
 
686
 
              fprintf_plus(stderr, "Error importing OpenPGP key : %s",
 
687
 
                           safer_gnutls_strerror(ret));
 
693
 
              /* Use private key to suggest an appropriate
 
695
 
              sec_param = gnutls_openpgp_privkey_sec_param(privkey);
 
696
 
              gnutls_openpgp_privkey_deinit(privkey);
 
698
 
                fprintf_plus(stderr, "This OpenPGP key implies using"
 
699
 
                             " a GnuTLS security parameter \"%s\".\n",
 
700
 
                             safe_string(gnutls_sec_param_get_name
 
706
 
        if(sec_param == GNUTLS_SEC_PARAM_UNKNOWN){
 
707
 
          /* Err on the side of caution */
 
708
 
          sec_param = GNUTLS_SEC_PARAM_ULTRA;
 
710
 
            fprintf_plus(stderr, "Falling back to security parameter"
 
712
 
                         safe_string(gnutls_sec_param_get_name
 
 
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);
 
 
639
              fprintf_plus(stderr, "This OpenPGP key implies using a"
 
 
640
                           " GnuTLS security parameter \"%s\".\n",
 
 
641
                           safe_string(gnutls_sec_param_get_name
 
717
 
      uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
 
 
647
      if(sec_param == GNUTLS_SEC_PARAM_UNKNOWN){
 
 
648
        /* Err on the side of caution */
 
 
649
        sec_param = GNUTLS_SEC_PARAM_ULTRA;
 
721
 
          fprintf_plus(stderr, "A \"%s\" GnuTLS security parameter"
 
722
 
                       " implies %u DH bits; using that.\n",
 
 
651
          fprintf_plus(stderr, "Falling back to security parameter"
 
723
653
                       safe_string(gnutls_sec_param_get_name
 
728
 
        fprintf_plus(stderr, "Failed to get implied number of DH"
 
729
 
                     " bits for security parameter \"%s\"): %s\n",
 
 
658
    uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
 
 
662
        fprintf_plus(stderr, "A \"%s\" GnuTLS security parameter"
 
 
663
                     " implies %u DH bits; using that.\n",
 
730
664
                     safe_string(gnutls_sec_param_get_name
 
732
 
                     safer_gnutls_strerror(ret));
 
736
 
      fprintf_plus(stderr, "DH bits explicitly set to %u\n",
 
739
 
    ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
740
 
    if(ret != GNUTLS_E_SUCCESS){
 
741
 
      fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
 
742
 
                   " bits): %s\n", mc->dh_bits,
 
 
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)),
 
743
672
                   safer_gnutls_strerror(ret));
 
 
676
    fprintf_plus(stderr, "DH bits explicitly set to %u\n",
 
 
679
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
 
680
  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));
 
747
686
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
 
 
818
760
/* Set effective uid to 0, return errno */
 
819
761
__attribute__((warn_unused_result))
 
820
 
int raise_privileges(void){
 
821
 
  int old_errno = errno;
 
 
762
error_t raise_privileges(void){
 
 
763
  error_t old_errno = errno;
 
 
764
  error_t ret_errno = 0;
 
823
765
  if(seteuid(0) == -1){
 
826
768
  errno = old_errno;
 
830
772
/* Set effective and real user ID to 0.  Return errno. */
 
831
773
__attribute__((warn_unused_result))
 
832
 
int raise_privileges_permanently(void){
 
833
 
  int old_errno = errno;
 
834
 
  int ret = raise_privileges();
 
 
774
error_t raise_privileges_permanently(void){
 
 
775
  error_t old_errno = errno;
 
 
776
  error_t ret_errno = raise_privileges();
 
836
778
    errno = old_errno;
 
839
781
  if(setuid(0) == -1){
 
842
784
  errno = old_errno;
 
846
788
/* Set effective user ID to unprivileged saved user ID */
 
847
789
__attribute__((warn_unused_result))
 
848
 
int lower_privileges(void){
 
849
 
  int old_errno = errno;
 
 
790
error_t lower_privileges(void){
 
 
791
  error_t old_errno = errno;
 
 
792
  error_t ret_errno = 0;
 
851
793
  if(seteuid(uid) == -1){
 
854
796
  errno = old_errno;
 
858
800
/* Lower privileges permanently */
 
859
801
__attribute__((warn_unused_result))
 
860
 
int lower_privileges_permanently(void){
 
861
 
  int old_errno = errno;
 
 
802
error_t lower_privileges_permanently(void){
 
 
803
  error_t old_errno = errno;
 
 
804
  error_t ret_errno = 0;
 
863
805
  if(setuid(uid) == -1){
 
866
808
  errno = old_errno;
 
870
812
/* Helper function to add_local_route() and delete_local_route() */
 
 
3030
2945
  free(interfaces_to_take_down);
 
3031
2946
  free(interfaces_hooks);
 
3033
 
  void clean_dir_at(int base, const char * const dirname,
 
3035
 
    struct dirent **direntries = NULL;
 
3037
 
    int dir_fd = (int)TEMP_FAILURE_RETRY(openat(base, dirname,
 
3043
 
      perror_plus("open");
 
3045
 
    int numentries = scandirat(dir_fd, ".", &direntries,
 
3046
 
                               notdotentries, alphasort);
 
3047
 
    if(numentries >= 0){
 
3048
 
      for(int i = 0; i < numentries; i++){
 
3050
 
          fprintf_plus(stderr, "Unlinking \"%s/%s\"\n",
 
3051
 
                       dirname, direntries[i]->d_name);
 
3053
 
        dret = unlinkat(dir_fd, direntries[i]->d_name, 0);
 
3055
 
          if(errno == EISDIR){
 
3056
 
              dret = unlinkat(dir_fd, direntries[i]->d_name,
 
3059
 
          if((dret == -1) and (errno == ENOTEMPTY)
 
3060
 
             and (strcmp(direntries[i]->d_name, "private-keys-v1.d")
 
3061
 
                  == 0) and (level == 0)){
 
3062
 
            /* Recurse only in this special case */
 
3063
 
            clean_dir_at(dir_fd, direntries[i]->d_name, level+1);
 
3067
 
            fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
 
3068
 
                         direntries[i]->d_name, strerror(errno));
 
3071
 
        free(direntries[i]);
 
3074
 
      /* need to clean even if 0 because man page doesn't specify */
 
3076
 
      if(numentries == -1){
 
3077
 
        perror_plus("scandirat");
 
3079
 
      dret = unlinkat(base, dirname, AT_REMOVEDIR);
 
3080
 
      if(dret == -1 and errno != ENOENT){
 
3081
 
        perror_plus("rmdir");
 
3084
 
      perror_plus("scandirat");
 
3089
2948
  /* Removes the GPGME temp directory and all files inside */
 
3090
2949
  if(tempdir != NULL){
 
3091
 
    clean_dir_at(-1, tempdir, 0);
 
 
2950
    struct dirent **direntries = NULL;
 
 
2951
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY
 
 
2955
    if(tempdir_fd == -1){
 
 
2956
      perror_plus("open");
 
 
2959
#if __GLIBC_PREREQ(2, 15)
 
 
2960
      int numentries = scandirat(tempdir_fd, ".", &direntries,
 
 
2961
                                 notdotentries, alphasort);
 
 
2962
#else  /* not __GLIBC_PREREQ(2, 15) */
 
 
2963
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
 
2965
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
 
2966
#else   /* not __GLIBC__ */
 
 
2967
      int numentries = scandir(tempdir, &direntries, notdotentries,
 
 
2969
#endif  /* not __GLIBC__ */
 
 
2970
      if(numentries >= 0){
 
 
2971
        for(int i = 0; i < numentries; i++){
 
 
2972
          ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
 
 
2974
            fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
 
 
2975
                         " \"%s\", 0): %s\n", tempdir,
 
 
2976
                         direntries[i]->d_name, strerror(errno));
 
 
2978
          free(direntries[i]);
 
 
2981
        /* need to clean even if 0 because man page doesn't specify */
 
 
2983
        if(numentries == -1){
 
 
2984
          perror_plus("scandir");
 
 
2986
        ret = rmdir(tempdir);
 
 
2987
        if(ret == -1 and errno != ENOENT){
 
 
2988
          perror_plus("rmdir");
 
 
2991
      TEMP_FAILURE_RETRY(close(tempdir_fd));