/mandos/trunk

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

« back to all changes in this revision

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

  • Committer: Teddy Hogeborn
  • Date: 2016-06-03 17:27:03 UTC
  • Revision ID: teddy@recompile.se-20160603172703-mc6tjor6rhq4xy74
mandos: Bug fix: Do multiprocessing cleanup correctly on exit

* mandos (main): Save module "multiprocessing" and open file "wnull"
                 as scope variables accessible by function cleanup(),
                 since the module and global variable may not be
                 accessible when the cleanup() function is run as
                 scheduled by atexit().

Show diffs side-by-side

added added

removed removed

Lines of Context:
57
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
58
58
                                   inet_pton(), connect(),
59
59
                                   getnameinfo() */
60
 
#include <fcntl.h>              /* open(), unlinkat() */
 
60
#include <fcntl.h>              /* open(), unlinkat(), AT_REMOVEDIR */
61
61
#include <dirent.h>             /* opendir(), struct dirent, readdir()
62
62
                                 */
63
63
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
64
64
                                   strtoimax() */
65
 
#include <errno.h>              /* perror(), errno,
 
65
#include <errno.h>              /* perror(), errno, EINTR, EINVAL,
 
66
                                   EAI_SYSTEM, ENETUNREACH,
 
67
                                   EHOSTUNREACH, ECONNREFUSED, EPROTO,
 
68
                                   EIO, ENOENT, ENXIO, ENOMEM, EISDIR,
 
69
                                   ENOTEMPTY,
66
70
                                   program_invocation_short_name */
67
71
#include <time.h>               /* nanosleep(), time(), sleep() */
68
72
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
813
817
 
814
818
/* Set effective uid to 0, return errno */
815
819
__attribute__((warn_unused_result))
816
 
error_t raise_privileges(void){
817
 
  error_t old_errno = errno;
818
 
  error_t ret_errno = 0;
 
820
int raise_privileges(void){
 
821
  int old_errno = errno;
 
822
  int ret = 0;
819
823
  if(seteuid(0) == -1){
820
 
    ret_errno = errno;
 
824
    ret = errno;
821
825
  }
822
826
  errno = old_errno;
823
 
  return ret_errno;
 
827
  return ret;
824
828
}
825
829
 
826
830
/* Set effective and real user ID to 0.  Return errno. */
827
831
__attribute__((warn_unused_result))
828
 
error_t raise_privileges_permanently(void){
829
 
  error_t old_errno = errno;
830
 
  error_t ret_errno = raise_privileges();
831
 
  if(ret_errno != 0){
 
832
int raise_privileges_permanently(void){
 
833
  int old_errno = errno;
 
834
  int ret = raise_privileges();
 
835
  if(ret != 0){
832
836
    errno = old_errno;
833
 
    return ret_errno;
 
837
    return ret;
834
838
  }
835
839
  if(setuid(0) == -1){
836
 
    ret_errno = errno;
 
840
    ret = errno;
837
841
  }
838
842
  errno = old_errno;
839
 
  return ret_errno;
 
843
  return ret;
840
844
}
841
845
 
842
846
/* Set effective user ID to unprivileged saved user ID */
843
847
__attribute__((warn_unused_result))
844
 
error_t lower_privileges(void){
845
 
  error_t old_errno = errno;
846
 
  error_t ret_errno = 0;
 
848
int lower_privileges(void){
 
849
  int old_errno = errno;
 
850
  int ret = 0;
847
851
  if(seteuid(uid) == -1){
848
 
    ret_errno = errno;
 
852
    ret = errno;
849
853
  }
850
854
  errno = old_errno;
851
 
  return ret_errno;
 
855
  return ret;
852
856
}
853
857
 
854
858
/* Lower privileges permanently */
855
859
__attribute__((warn_unused_result))
856
 
error_t lower_privileges_permanently(void){
857
 
  error_t old_errno = errno;
858
 
  error_t ret_errno = 0;
 
860
int lower_privileges_permanently(void){
 
861
  int old_errno = errno;
 
862
  int ret = 0;
859
863
  if(setuid(uid) == -1){
860
 
    ret_errno = errno;
 
864
    ret = errno;
861
865
  }
862
866
  errno = old_errno;
863
 
  return ret_errno;
 
867
  return ret;
864
868
}
865
869
 
866
870
/* Helper function to add_local_route() and delete_local_route() */
1619
1623
__attribute__((nonnull, warn_unused_result))
1620
1624
bool get_flags(const char *ifname, struct ifreq *ifr){
1621
1625
  int ret;
1622
 
  error_t ret_errno;
 
1626
  int old_errno;
1623
1627
  
1624
1628
  int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1625
1629
  if(s < 0){
1626
 
    ret_errno = errno;
 
1630
    old_errno = errno;
1627
1631
    perror_plus("socket");
1628
 
    errno = ret_errno;
 
1632
    errno = old_errno;
1629
1633
    return false;
1630
1634
  }
1631
1635
  strncpy(ifr->ifr_name, ifname, IF_NAMESIZE);
1633
1637
  ret = ioctl(s, SIOCGIFFLAGS, ifr);
1634
1638
  if(ret == -1){
1635
1639
    if(debug){
1636
 
      ret_errno = errno;
 
1640
      old_errno = errno;
1637
1641
      perror_plus("ioctl SIOCGIFFLAGS");
1638
 
      errno = ret_errno;
 
1642
      errno = old_errno;
1639
1643
    }
1640
1644
    return false;
1641
1645
  }
2067
2071
}
2068
2072
 
2069
2073
__attribute__((nonnull, warn_unused_result))
2070
 
error_t bring_up_interface(const char *const interface,
2071
 
                           const float delay){
2072
 
  error_t old_errno = errno;
 
2074
int bring_up_interface(const char *const interface,
 
2075
                       const float delay){
 
2076
  int old_errno = errno;
2073
2077
  int ret;
2074
2078
  struct ifreq network;
2075
2079
  unsigned int if_index = if_nametoindex(interface);
2085
2089
  }
2086
2090
  
2087
2091
  if(not interface_is_up(interface)){
2088
 
    error_t ret_errno = 0, ioctl_errno = 0;
 
2092
    int ret_errno = 0;
 
2093
    int ioctl_errno = 0;
2089
2094
    if(not get_flags(interface, &network)){
2090
2095
      ret_errno = errno;
2091
2096
      fprintf_plus(stderr, "Failed to get flags for interface "
2194
2199
}
2195
2200
 
2196
2201
__attribute__((nonnull, warn_unused_result))
2197
 
error_t take_down_interface(const char *const interface){
2198
 
  error_t old_errno = errno;
 
2202
int take_down_interface(const char *const interface){
 
2203
  int old_errno = errno;
2199
2204
  struct ifreq network;
2200
2205
  unsigned int if_index = if_nametoindex(interface);
2201
2206
  if(if_index == 0){
2204
2209
    return ENXIO;
2205
2210
  }
2206
2211
  if(interface_is_up(interface)){
2207
 
    error_t ret_errno = 0, ioctl_errno = 0;
 
2212
    int ret_errno = 0;
 
2213
    int ioctl_errno = 0;
2208
2214
    if(not get_flags(interface, &network) and debug){
2209
2215
      ret_errno = errno;
2210
2216
      fprintf_plus(stderr, "Failed to get flags for interface "
2460
2466
                         .args_doc = "",
2461
2467
                         .doc = "Mandos client -- Get and decrypt"
2462
2468
                         " passwords from a Mandos server" };
2463
 
    ret = argp_parse(&argp, argc, argv,
2464
 
                     ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
2465
 
    switch(ret){
 
2469
    ret_errno = argp_parse(&argp, argc, argv,
 
2470
                           ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
 
2471
    switch(ret_errno){
2466
2472
    case 0:
2467
2473
      break;
2468
2474
    case ENOMEM:
2469
2475
    default:
2470
 
      errno = ret;
 
2476
      errno = ret_errno;
2471
2477
      perror_plus("argp_parse");
2472
2478
      exitcode = EX_OSERR;
2473
2479
      goto end;
2482
2488
       <http://bugs.debian.org/633582> */
2483
2489
    
2484
2490
    /* Re-raise privileges */
2485
 
    ret_errno = raise_privileges();
2486
 
    if(ret_errno != 0){
2487
 
      errno = ret_errno;
 
2491
    ret = raise_privileges();
 
2492
    if(ret != 0){
 
2493
      errno = ret;
2488
2494
      perror_plus("Failed to raise privileges");
2489
2495
    } else {
2490
2496
      struct stat st;
2554
2560
      }
2555
2561
      
2556
2562
      /* Lower privileges */
2557
 
      ret_errno = lower_privileges();
2558
 
      if(ret_errno != 0){
2559
 
        errno = ret_errno;
 
2563
      ret = lower_privileges();
 
2564
      if(ret != 0){
 
2565
        errno = ret;
2560
2566
        perror_plus("Failed to lower privileges");
2561
2567
      }
2562
2568
    }
2890
2896
    
2891
2897
    /* Allocate a new server */
2892
2898
    mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
2893
 
                                 &config, NULL, NULL, &ret_errno);
 
2899
                                 &config, NULL, NULL, &ret);
2894
2900
    
2895
2901
    /* Free the Avahi configuration data */
2896
2902
    avahi_server_config_free(&config);
2899
2905
  /* Check if creating the Avahi server object succeeded */
2900
2906
  if(mc.server == NULL){
2901
2907
    fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
2902
 
                 avahi_strerror(ret_errno));
 
2908
                 avahi_strerror(ret));
2903
2909
    exitcode = EX_UNAVAILABLE;
2904
2910
    goto end;
2905
2911
  }
2985
2991
  
2986
2992
  /* Re-raise privileges */
2987
2993
  {
2988
 
    ret_errno = raise_privileges();
2989
 
    if(ret_errno != 0){
2990
 
      errno = ret_errno;
 
2994
    ret = raise_privileges();
 
2995
    if(ret != 0){
 
2996
      errno = ret;
2991
2997
      perror_plus("Failed to raise privileges");
2992
2998
    } else {
2993
2999
      
3001
3007
        while((interface=argz_next(interfaces_to_take_down,
3002
3008
                                   interfaces_to_take_down_size,
3003
3009
                                   interface))){
3004
 
          ret_errno = take_down_interface(interface);
3005
 
          if(ret_errno != 0){
3006
 
            errno = ret_errno;
 
3010
          ret = take_down_interface(interface);
 
3011
          if(ret != 0){
 
3012
            errno = ret;
3007
3013
            perror_plus("Failed to take down interface");
3008
3014
          }
3009
3015
        }
3014
3020
      }
3015
3021
    }
3016
3022
    
3017
 
    ret_errno = lower_privileges_permanently();
3018
 
    if(ret_errno != 0){
3019
 
      errno = ret_errno;
 
3023
    ret = lower_privileges_permanently();
 
3024
    if(ret != 0){
 
3025
      errno = ret;
3020
3026
      perror_plus("Failed to lower privileges permanently");
3021
3027
    }
3022
3028
  }
3024
3030
  free(interfaces_to_take_down);
3025
3031
  free(interfaces_hooks);
3026
3032
  
 
3033
  void clean_dir_at(int base, const char * const dirname,
 
3034
                    uintmax_t level){
 
3035
    struct dirent **direntries = NULL;
 
3036
    int dret;
 
3037
    int dir_fd = (int)TEMP_FAILURE_RETRY(openat(base, dirname,
 
3038
                                                O_RDONLY
 
3039
                                                | O_NOFOLLOW
 
3040
                                                | O_DIRECTORY
 
3041
                                                | O_PATH));
 
3042
    if(dir_fd == -1){
 
3043
      perror_plus("open");
 
3044
    }
 
3045
    int numentries = scandirat(dir_fd, ".", &direntries,
 
3046
                               notdotentries, alphasort);
 
3047
    if(numentries >= 0){
 
3048
      for(int i = 0; i < numentries; i++){
 
3049
        if(debug){
 
3050
          fprintf_plus(stderr, "Unlinking \"%s/%s\"\n",
 
3051
                       dirname, direntries[i]->d_name);
 
3052
        }
 
3053
        dret = unlinkat(dir_fd, direntries[i]->d_name, 0);
 
3054
        if(dret == -1){
 
3055
          if(errno == EISDIR){
 
3056
              dret = unlinkat(dir_fd, direntries[i]->d_name,
 
3057
                              AT_REMOVEDIR);
 
3058
          }         
 
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);
 
3064
            dret = 0;
 
3065
          }
 
3066
          if(dret == -1){
 
3067
            fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
 
3068
                         direntries[i]->d_name, strerror(errno));
 
3069
          }
 
3070
        }
 
3071
        free(direntries[i]);
 
3072
      }
 
3073
      
 
3074
      /* need to clean even if 0 because man page doesn't specify */
 
3075
      free(direntries);
 
3076
      if(numentries == -1){
 
3077
        perror_plus("scandirat");
 
3078
      }
 
3079
      dret = unlinkat(base, dirname, AT_REMOVEDIR);
 
3080
      if(dret == -1 and errno != ENOENT){
 
3081
        perror_plus("rmdir");
 
3082
      }
 
3083
    } else {
 
3084
      perror_plus("scandirat");
 
3085
    }
 
3086
    close(dir_fd);
 
3087
  }
 
3088
  
3027
3089
  /* Removes the GPGME temp directory and all files inside */
3028
3090
  if(tempdir != NULL){
3029
 
    struct dirent **direntries = NULL;
3030
 
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY
3031
 
                                                  | O_NOFOLLOW
3032
 
                                                  | O_DIRECTORY
3033
 
                                                  | O_PATH));
3034
 
    if(tempdir_fd == -1){
3035
 
      perror_plus("open");
3036
 
    } else {
3037
 
      int numentries = scandirat(tempdir_fd, ".", &direntries,
3038
 
                                 notdotentries, alphasort);
3039
 
      if(numentries >= 0){
3040
 
        for(int i = 0; i < numentries; i++){
3041
 
          ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
3042
 
          if(ret == -1){
3043
 
            fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
3044
 
                         " \"%s\", 0): %s\n", tempdir,
3045
 
                         direntries[i]->d_name, strerror(errno));
3046
 
          }
3047
 
          free(direntries[i]);
3048
 
        }
3049
 
        
3050
 
        /* need to clean even if 0 because man page doesn't specify */
3051
 
        free(direntries);
3052
 
        if(numentries == -1){
3053
 
          perror_plus("scandir");
3054
 
        }
3055
 
        ret = rmdir(tempdir);
3056
 
        if(ret == -1 and errno != ENOENT){
3057
 
          perror_plus("rmdir");
3058
 
        }
3059
 
      }
3060
 
      close(tempdir_fd);
3061
 
    }
 
3091
    clean_dir_at(-1, tempdir, 0);
3062
3092
  }
3063
3093
  
3064
3094
  if(quit_now){