757
757
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
758
758
                      __attribute__((unused)) const char *txt){}
 
 
760
/* Set effective uid to 0, return errno */
 
 
761
__attribute__((warn_unused_result))
 
 
762
error_t raise_privileges(void){
 
 
763
  error_t old_errno = errno;
 
 
764
  error_t ret_errno = 0;
 
 
765
  if(seteuid(0) == -1){
 
 
772
/* Set effective and real user ID to 0.  Return errno. */
 
 
773
__attribute__((warn_unused_result))
 
 
774
error_t raise_privileges_permanently(void){
 
 
775
  error_t old_errno = errno;
 
 
776
  error_t ret_errno = raise_privileges();
 
 
788
/* Set effective user ID to unprivileged saved user ID */
 
 
789
__attribute__((warn_unused_result))
 
 
790
error_t lower_privileges(void){
 
 
791
  error_t old_errno = errno;
 
 
792
  error_t ret_errno = 0;
 
 
793
  if(seteuid(uid) == -1){
 
 
800
/* Lower privileges permanently */
 
 
801
__attribute__((warn_unused_result))
 
 
802
error_t lower_privileges_permanently(void){
 
 
803
  error_t old_errno = errno;
 
 
804
  error_t ret_errno = 0;
 
 
805
  if(setuid(uid) == -1){
 
 
812
/* Helper function to add_local_route() and delete_local_route() */
 
 
813
__attribute__((nonnull, warn_unused_result))
 
 
814
static bool add_delete_local_route(const bool add,
 
 
816
                                   AvahiIfIndex if_index){
 
 
818
  char helper[] = "mandos-client-iprouteadddel";
 
 
819
  char add_arg[] = "add";
 
 
820
  char delete_arg[] = "delete";
 
 
821
  char debug_flag[] = "--debug";
 
 
822
  char *pluginhelperdir = getenv("MANDOSPLUGINHELPERDIR");
 
 
823
  if(pluginhelperdir == NULL){
 
 
825
      fprintf_plus(stderr, "MANDOSPLUGINHELPERDIR environment"
 
 
826
                   " variable not set; cannot run helper\n");
 
 
831
  char interface[IF_NAMESIZE];
 
 
832
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
 
833
    perror_plus("if_indextoname");
 
 
837
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
 
 
839
    perror_plus("open(\"/dev/null\", O_RDONLY)");
 
 
845
    /* Raise privileges */
 
 
846
    errno = raise_privileges_permanently();
 
 
848
      perror_plus("Failed to raise privileges");
 
 
849
      /* _exit(EX_NOPERM); */
 
 
855
        perror_plus("setgid");
 
 
858
      /* Reset supplementary groups */
 
 
860
      ret = setgroups(0, NULL);
 
 
862
        perror_plus("setgroups");
 
 
866
    ret = dup2(devnull, STDIN_FILENO);
 
 
868
      perror_plus("dup2(devnull, STDIN_FILENO)");
 
 
871
    ret = (int)TEMP_FAILURE_RETRY(close(devnull));
 
 
873
      perror_plus("close");
 
 
876
    ret = dup2(STDERR_FILENO, STDOUT_FILENO);
 
 
878
      perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
 
 
881
    int helperdir_fd = (int)TEMP_FAILURE_RETRY(open(pluginhelperdir,
 
 
886
    if(helperdir_fd == -1){
 
 
888
      _exit(EX_UNAVAILABLE);
 
 
890
    int helper_fd = (int)TEMP_FAILURE_RETRY(openat(helperdir_fd,
 
 
893
      perror_plus("openat");
 
 
894
      _exit(EX_UNAVAILABLE);
 
 
896
    TEMP_FAILURE_RETRY(close(helperdir_fd));
 
 
898
#pragma GCC diagnostic push
 
 
899
#pragma GCC diagnostic ignored "-Wcast-qual"
 
 
901
    if(fexecve(helper_fd, (char *const [])
 
 
902
               { helper, add ? add_arg : delete_arg, (char *)address,
 
 
903
                   interface, debug ? debug_flag : NULL, NULL },
 
 
906
#pragma GCC diagnostic pop
 
 
908
      perror_plus("fexecve");
 
 
920
    pret = waitpid(pid, &status, 0);
 
 
921
    if(pret == -1 and errno == EINTR and quit_now){
 
 
922
      int errno_raising = 0;
 
 
923
      if((errno = raise_privileges()) != 0){
 
 
924
        errno_raising = errno;
 
 
925
        perror_plus("Failed to raise privileges in order to"
 
 
926
                    " kill helper program");
 
 
928
      if(kill(pid, SIGTERM) == -1){
 
 
931
      if((errno_raising == 0) and (errno = lower_privileges()) != 0){
 
 
932
        perror_plus("Failed to lower privileges after killing"
 
 
937
  } while(pret == -1 and errno == EINTR);
 
 
939
    perror_plus("waitpid");
 
 
942
  if(WIFEXITED(status)){
 
 
943
    if(WEXITSTATUS(status) != 0){
 
 
944
      fprintf_plus(stderr, "Error: iprouteadddel exited"
 
 
945
                   " with status %d\n", WEXITSTATUS(status));
 
 
950
  if(WIFSIGNALED(status)){
 
 
951
    fprintf_plus(stderr, "Error: iprouteadddel died by"
 
 
952
                 " signal %d\n", WTERMSIG(status));
 
 
955
  fprintf_plus(stderr, "Error: iprouteadddel crashed\n");
 
 
959
__attribute__((nonnull, warn_unused_result))
 
 
960
static bool add_local_route(const char *address,
 
 
961
                            AvahiIfIndex if_index){
 
 
963
    fprintf_plus(stderr, "Adding route to %s\n", address);
 
 
965
  return add_delete_local_route(true, address, if_index);
 
 
968
__attribute__((nonnull, warn_unused_result))
 
 
969
static bool delete_local_route(const char *address,
 
 
970
                               AvahiIfIndex if_index){
 
 
972
    fprintf_plus(stderr, "Removing route to %s\n", address);
 
 
974
  return add_delete_local_route(false, address, if_index);
 
760
977
/* Called when a Mandos server is found */
 
761
978
__attribute__((nonnull, warn_unused_result))
 
762
979
static int start_mandos_communication(const char *ip, in_port_t port,
 
 
931
1149
    goto mandos_end;
 
935
 
    ret = connect(tcp_sd, (struct sockaddr *)&to,
 
936
 
                  sizeof(struct sockaddr_in6));
 
938
 
    ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
939
 
                  sizeof(struct sockaddr_in));
 
942
 
    if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
944
 
      perror_plus("connect");
 
 
1154
      ret = connect(tcp_sd, (struct sockaddr *)&to,
 
 
1155
                    sizeof(struct sockaddr_in6));
 
 
1157
      ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
 
1158
                    sizeof(struct sockaddr_in));
 
 
1161
      if(errno == ENETUNREACH
 
 
1162
         and if_index != AVAHI_IF_UNSPEC
 
 
1163
         and connect_to == NULL
 
 
1164
         and not route_added and
 
 
1165
         ((af == AF_INET6 and not
 
 
1166
           IN6_IS_ADDR_LINKLOCAL(&(((struct sockaddr_in6 *)
 
 
1168
          or (af == AF_INET and
 
 
1169
              /* Not a a IPv4LL address */
 
 
1170
              (ntohl(((struct sockaddr_in *)&to)->sin_addr.s_addr)
 
 
1171
               & 0xFFFF0000L) != 0xA9FE0000L))){
 
 
1172
        /* Work around Avahi bug - Avahi does not announce link-local
 
 
1173
           addresses if it has a global address, so local hosts with
 
 
1174
           *only* a link-local address (e.g. Mandos clients) cannot
 
 
1175
           connect to a Mandos server announced by Avahi on a server
 
 
1176
           host with a global address.  Work around this by retrying
 
 
1177
           with an explicit route added with the server's address.
 
 
1179
           Avahi bug reference:
 
 
1180
           http://lists.freedesktop.org/archives/avahi/2010-February/001833.html
 
 
1181
           https://bugs.debian.org/587961
 
 
1184
          fprintf_plus(stderr, "Mandos server unreachable, trying"
 
 
1188
        route_added = add_local_route(ip, if_index);
 
 
1194
      if(errno != ECONNREFUSED or debug){
 
 
1196
        perror_plus("connect");
 
955
1209
  const char *out = mandos_protocol_version;
 
 
1572
 
/* Set effective uid to 0, return errno */
 
1573
 
__attribute__((warn_unused_result))
 
1574
 
error_t raise_privileges(void){
 
1575
 
  error_t old_errno = errno;
 
1576
 
  error_t ret_errno = 0;
 
1577
 
  if(seteuid(0) == -1){
 
1584
 
/* Set effective and real user ID to 0.  Return errno. */
 
1585
 
__attribute__((warn_unused_result))
 
1586
 
error_t raise_privileges_permanently(void){
 
1587
 
  error_t old_errno = errno;
 
1588
 
  error_t ret_errno = raise_privileges();
 
1593
 
  if(setuid(0) == -1){
 
1600
 
/* Set effective user ID to unprivileged saved user ID */
 
1601
 
__attribute__((warn_unused_result))
 
1602
 
error_t lower_privileges(void){
 
1603
 
  error_t old_errno = errno;
 
1604
 
  error_t ret_errno = 0;
 
1605
 
  if(seteuid(uid) == -1){
 
1612
 
/* Lower privileges permanently */
 
1613
 
__attribute__((warn_unused_result))
 
1614
 
error_t lower_privileges_permanently(void){
 
1615
 
  error_t old_errno = errno;
 
1616
 
  error_t ret_errno = 0;
 
1617
 
  if(setuid(uid) == -1){
 
1624
1832
__attribute__((nonnull))
 
1625
1833
void run_network_hooks(const char *mode, const char *interface,
 
1626
1834
                       const float delay){
 
1627
1835
  struct dirent **direntries = NULL;
 
1628
1836
  if(hookdir_fd == -1){
 
1629
 
    hookdir_fd = open(hookdir, O_RDONLY);
 
 
1837
    hookdir_fd = open(hookdir, O_RDONLY | O_DIRECTORY | O_PATH
 
1630
1839
    if(hookdir_fd == -1){
 
1631
1840
      if(errno == ENOENT){