/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: 2015-07-01 20:01:26 UTC
  • mto: This revision was merged to the branch mainline in revision 759.
  • 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:
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
11
 * Everything else is
12
 
 * Copyright © 2008-2014 Teddy Hogeborn
13
 
 * Copyright © 2008-2014 Björn Påhlsson
 
12
 * Copyright © 2008-2015 Teddy Hogeborn
 
13
 * Copyright © 2008-2015 Björn Påhlsson
14
14
 * 
15
15
 * This program is free software: you can redistribute it and/or
16
16
 * modify it under the terms of the GNU General Public License as
234
234
                          .af = af };
235
235
  if(new_server->ip == NULL){
236
236
    perror_plus("strdup");
 
237
    free(new_server);
237
238
    return false;
238
239
  }
239
240
  ret = clock_gettime(CLOCK_MONOTONIC, &(new_server->last_seen));
240
241
  if(ret == -1){
241
242
    perror_plus("clock_gettime");
 
243
#ifdef __GNUC__
 
244
#pragma GCC diagnostic push
 
245
#pragma GCC diagnostic ignored "-Wcast-qual"
 
246
#endif
 
247
    free((char *)(new_server->ip));
 
248
#ifdef __GNUC__
 
249
#pragma GCC diagnostic pop
 
250
#endif
 
251
    free(new_server);
242
252
    return false;
243
253
  }
244
254
  /* Special case of first server */
640
650
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
641
651
                      __attribute__((unused)) const char *txt){}
642
652
 
 
653
/* Set effective uid to 0, return errno */
 
654
__attribute__((warn_unused_result))
 
655
error_t raise_privileges(void){
 
656
  error_t old_errno = errno;
 
657
  error_t ret_errno = 0;
 
658
  if(seteuid(0) == -1){
 
659
    ret_errno = errno;
 
660
  }
 
661
  errno = old_errno;
 
662
  return ret_errno;
 
663
}
 
664
 
 
665
/* Set effective and real user ID to 0.  Return errno. */
 
666
__attribute__((warn_unused_result))
 
667
error_t raise_privileges_permanently(void){
 
668
  error_t old_errno = errno;
 
669
  error_t ret_errno = raise_privileges();
 
670
  if(ret_errno != 0){
 
671
    errno = old_errno;
 
672
    return ret_errno;
 
673
  }
 
674
  if(setuid(0) == -1){
 
675
    ret_errno = errno;
 
676
  }
 
677
  errno = old_errno;
 
678
  return ret_errno;
 
679
}
 
680
 
 
681
/* Set effective user ID to unprivileged saved user ID */
 
682
__attribute__((warn_unused_result))
 
683
error_t lower_privileges(void){
 
684
  error_t old_errno = errno;
 
685
  error_t ret_errno = 0;
 
686
  if(seteuid(uid) == -1){
 
687
    ret_errno = errno;
 
688
  }
 
689
  errno = old_errno;
 
690
  return ret_errno;
 
691
}
 
692
 
 
693
/* Lower privileges permanently */
 
694
__attribute__((warn_unused_result))
 
695
error_t lower_privileges_permanently(void){
 
696
  error_t old_errno = errno;
 
697
  error_t ret_errno = 0;
 
698
  if(setuid(uid) == -1){
 
699
    ret_errno = errno;
 
700
  }
 
701
  errno = old_errno;
 
702
  return ret_errno;
 
703
}
 
704
 
 
705
/* Helper function to add_local_route() and remove_local_route() */
 
706
__attribute__((nonnull, warn_unused_result))
 
707
static bool add_remove_local_route(const bool add,
 
708
                                   const char *address,
 
709
                                   AvahiIfIndex if_index){
 
710
  int ret;
 
711
  char helper[] = "mandos-client-iprouteadddel";
 
712
  char add_arg[] = "add";
 
713
  char remove_arg[] = "remove";
 
714
  char *pluginhelperdir = getenv("MANDOSPLUGINHELPERDIR");
 
715
  if(pluginhelperdir == NULL){
 
716
    if(debug){
 
717
      fprintf_plus(stderr, "MANDOSPLUGINHELPERDIR environment"
 
718
                   " variable not set; cannot run helper\n");
 
719
    }
 
720
    return false;
 
721
  }
 
722
  
 
723
  char interface[IF_NAMESIZE];
 
724
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
725
    perror_plus("if_indextoname");
 
726
    return false;
 
727
  }
 
728
  
 
729
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
 
730
  if(devnull == -1){
 
731
    perror_plus("open(\"/dev/null\", O_RDONLY)");
 
732
    return false;
 
733
  }
 
734
  pid_t pid = fork();
 
735
  if(pid == 0){
 
736
    /* Child */
 
737
    /* Raise privileges */
 
738
    errno = raise_privileges_permanently();
 
739
    if(errno != 0){
 
740
      perror_plus("Failed to raise privileges");
 
741
      /* _exit(EX_NOPERM); */
 
742
    } else {
 
743
      /* Set group */
 
744
      errno = 0;
 
745
      ret = setgid(0);
 
746
      if(ret == -1){
 
747
        perror_plus("setgid");
 
748
        _exit(EX_NOPERM);
 
749
      }
 
750
      /* Reset supplementary groups */
 
751
      errno = 0;
 
752
      ret = setgroups(0, NULL);
 
753
      if(ret == -1){
 
754
        perror_plus("setgroups");
 
755
        _exit(EX_NOPERM);
 
756
      }
 
757
    }
 
758
    ret = dup2(devnull, STDIN_FILENO);
 
759
    if(ret == -1){
 
760
      perror_plus("dup2(devnull, STDIN_FILENO)");
 
761
      _exit(EX_OSERR);
 
762
    }
 
763
    ret = close(devnull);
 
764
    if(ret == -1){
 
765
      perror_plus("close");
 
766
      _exit(EX_OSERR);
 
767
    }
 
768
    ret = dup2(STDERR_FILENO, STDOUT_FILENO);
 
769
    if(ret == -1){
 
770
      perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
 
771
      _exit(EX_OSERR);
 
772
    }
 
773
    int helperdir_fd = (int)TEMP_FAILURE_RETRY(open(pluginhelperdir,
 
774
                                                    O_RDONLY
 
775
                                                    | O_DIRECTORY
 
776
                                                    | O_PATH
 
777
                                                    | O_CLOEXEC));
 
778
    int helper_fd = (int)TEMP_FAILURE_RETRY(openat(helperdir_fd,
 
779
                                                   helper, O_RDONLY));
 
780
    TEMP_FAILURE_RETRY(close(helperdir_fd));
 
781
#ifdef __GNUC__
 
782
#pragma GCC diagnostic push
 
783
#pragma GCC diagnostic ignored "-Wcast-qual"
 
784
#endif
 
785
    if(fexecve(helper_fd, (char *const [])
 
786
               { helper, add ? add_arg : remove_arg, (char *)address,
 
787
                   interface, NULL }, environ) == -1){
 
788
#ifdef __GNUC__
 
789
#pragma GCC diagnostic pop
 
790
#endif
 
791
      perror_plus("fexecve");
 
792
      _exit(EXIT_FAILURE);
 
793
    }
 
794
  }
 
795
  if(pid == -1){
 
796
    perror_plus("fork");
 
797
    return false;
 
798
  }
 
799
  int status;
 
800
  pid_t pret = -1;
 
801
  errno = 0;
 
802
  do {
 
803
    pret = waitpid(pid, &status, 0);
 
804
    if(pret == -1 and errno == EINTR and quit_now){
 
805
      int errno_raising = 0;
 
806
      if((errno = raise_privileges()) != 0){
 
807
        errno_raising = errno;
 
808
        perror_plus("Failed to raise privileges in order to"
 
809
                    " kill helper program");
 
810
      }
 
811
      if(kill(pid, SIGTERM) == -1){
 
812
        perror_plus("kill");
 
813
      }
 
814
      if((errno_raising == 0) and (errno = lower_privileges()) != 0){
 
815
        perror_plus("Failed to lower privileges after killing"
 
816
                    " helper program");
 
817
      }
 
818
      return false;
 
819
    }
 
820
  } while(pret == -1 and errno == EINTR);
 
821
  if(pret == -1){
 
822
    perror_plus("waitpid");
 
823
    return false;
 
824
  }
 
825
  if(WIFEXITED(status)){
 
826
    if(WEXITSTATUS(status) != 0){
 
827
      fprintf_plus(stderr, "Error: iprouteadddel exited"
 
828
                   " with status %d\n", WEXITSTATUS(status));
 
829
      return false;
 
830
    }
 
831
    return true;
 
832
  }
 
833
  if(WIFSIGNALED(status)){
 
834
    fprintf_plus(stderr, "Error: iprouteadddel died by"
 
835
                 " signal %d\n", WTERMSIG(status));
 
836
    return false;
 
837
  }
 
838
  fprintf_plus(stderr, "Error: iprouteadddel crashed\n");
 
839
  return false;
 
840
}
 
841
 
 
842
__attribute__((nonnull, warn_unused_result))
 
843
static bool add_local_route(const char *address,
 
844
                            AvahiIfIndex if_index){
 
845
  return add_remove_local_route(true, address, if_index);
 
846
}
 
847
 
 
848
__attribute__((nonnull, warn_unused_result))
 
849
static bool remove_local_route(const char *address,
 
850
                               AvahiIfIndex if_index){
 
851
  return add_remove_local_route(false, address, if_index);
 
852
}
 
853
 
643
854
/* Called when a Mandos server is found */
644
855
__attribute__((nonnull, warn_unused_result))
645
856
static int start_mandos_communication(const char *ip, in_port_t port,
656
867
  int retval = -1;
657
868
  gnutls_session_t session;
658
869
  int pf;                       /* Protocol family */
 
870
  bool route_added = false;
659
871
  
660
872
  errno = 0;
661
873
  
719
931
                 PRIuMAX "\n", ip, (uintmax_t)port);
720
932
  }
721
933
  
722
 
  tcp_sd = socket(pf, SOCK_STREAM, 0);
 
934
  tcp_sd = socket(pf, SOCK_STREAM | SOCK_CLOEXEC, 0);
723
935
  if(tcp_sd < 0){
724
936
    int e = errno;
725
937
    perror_plus("socket");
814
1026
    goto mandos_end;
815
1027
  }
816
1028
  
817
 
  if(af == AF_INET6){
818
 
    ret = connect(tcp_sd, (struct sockaddr *)&to,
819
 
                  sizeof(struct sockaddr_in6));
820
 
  } else {
821
 
    ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
822
 
                  sizeof(struct sockaddr_in));
823
 
  }
824
 
  if(ret < 0){
825
 
    if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
826
 
      int e = errno;
827
 
      perror_plus("connect");
828
 
      errno = e;
829
 
    }
830
 
    goto mandos_end;
831
 
  }
832
 
  
833
 
  if(quit_now){
834
 
    errno = EINTR;
835
 
    goto mandos_end;
 
1029
  while(true){
 
1030
    if(af == AF_INET6){
 
1031
      ret = connect(tcp_sd, (struct sockaddr *)&to,
 
1032
                    sizeof(struct sockaddr_in6));
 
1033
    } else {
 
1034
      ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */
 
1035
                    sizeof(struct sockaddr_in));
 
1036
    }
 
1037
    if(ret < 0){
 
1038
      if(errno == ENETUNREACH
 
1039
         and if_index != AVAHI_IF_UNSPEC
 
1040
         and connect_to == NULL
 
1041
         and not route_added and
 
1042
         ((af == AF_INET6 and not
 
1043
           IN6_IS_ADDR_LINKLOCAL(&(((struct sockaddr_in6 *)
 
1044
                                    &to)->sin6_addr)))
 
1045
          or (af == AF_INET and
 
1046
              /* Not a a IPv4LL address */
 
1047
              (ntohl(((struct sockaddr_in *)&to)->sin_addr.s_addr)
 
1048
               & 0xFFFF0000L) != 0xA9FE0000L))){
 
1049
        /* Work around Avahi bug - Avahi does not announce link-local
 
1050
           addresses if it has a global address, so local hosts with
 
1051
           *only* a link-local address (e.g. Mandos clients) cannot
 
1052
           connect to a Mandos server announced by Avahi on a server
 
1053
           host with a global address.  Work around this by retrying
 
1054
           with an explicit route added with the server's address.
 
1055
           
 
1056
           Avahi bug reference:
 
1057
           http://lists.freedesktop.org/archives/avahi/2010-February/001833.html
 
1058
           https://bugs.debian.org/587961
 
1059
        */
 
1060
        int e = errno;
 
1061
        route_added = add_local_route(ip, if_index);
 
1062
        if(route_added){
 
1063
          continue;
 
1064
        }
 
1065
        errno = e;
 
1066
      }
 
1067
      if(errno != ECONNREFUSED or debug){
 
1068
        int e = errno;
 
1069
        perror_plus("connect");
 
1070
        errno = e;
 
1071
      }
 
1072
      goto mandos_end;
 
1073
    }
 
1074
    
 
1075
    if(quit_now){
 
1076
      errno = EINTR;
 
1077
      goto mandos_end;
 
1078
    }
 
1079
    break;
836
1080
  }
837
1081
  
838
1082
  const char *out = mandos_protocol_version;
1021
1265
  
1022
1266
 mandos_end:
1023
1267
  {
 
1268
    if(route_added){
 
1269
      if(not remove_local_route(ip, if_index)){
 
1270
        fprintf_plus(stderr, "Failed to remove local route to %s on"
 
1271
                     " interface %d", ip, if_index);
 
1272
      }
 
1273
    }
1024
1274
    int e = errno;
1025
1275
    free(decrypted_buffer);
1026
1276
    free(buffer);
1066
1316
     timed out */
1067
1317
  
1068
1318
  if(quit_now){
 
1319
    avahi_s_service_resolver_free(r);
1069
1320
    return;
1070
1321
  }
1071
1322
  
1451
1702
  }
1452
1703
}
1453
1704
 
1454
 
/* Set effective uid to 0, return errno */
1455
 
__attribute__((warn_unused_result))
1456
 
error_t raise_privileges(void){
1457
 
  error_t old_errno = errno;
1458
 
  error_t ret_errno = 0;
1459
 
  if(seteuid(0) == -1){
1460
 
    ret_errno = errno;
1461
 
  }
1462
 
  errno = old_errno;
1463
 
  return ret_errno;
1464
 
}
1465
 
 
1466
 
/* Set effective and real user ID to 0.  Return errno. */
1467
 
__attribute__((warn_unused_result))
1468
 
error_t raise_privileges_permanently(void){
1469
 
  error_t old_errno = errno;
1470
 
  error_t ret_errno = raise_privileges();
1471
 
  if(ret_errno != 0){
1472
 
    errno = old_errno;
1473
 
    return ret_errno;
1474
 
  }
1475
 
  if(setuid(0) == -1){
1476
 
    ret_errno = errno;
1477
 
  }
1478
 
  errno = old_errno;
1479
 
  return ret_errno;
1480
 
}
1481
 
 
1482
 
/* Set effective user ID to unprivileged saved user ID */
1483
 
__attribute__((warn_unused_result))
1484
 
error_t lower_privileges(void){
1485
 
  error_t old_errno = errno;
1486
 
  error_t ret_errno = 0;
1487
 
  if(seteuid(uid) == -1){
1488
 
    ret_errno = errno;
1489
 
  }
1490
 
  errno = old_errno;
1491
 
  return ret_errno;
1492
 
}
1493
 
 
1494
 
/* Lower privileges permanently */
1495
 
__attribute__((warn_unused_result))
1496
 
error_t lower_privileges_permanently(void){
1497
 
  error_t old_errno = errno;
1498
 
  error_t ret_errno = 0;
1499
 
  if(setuid(uid) == -1){
1500
 
    ret_errno = errno;
1501
 
  }
1502
 
  errno = old_errno;
1503
 
  return ret_errno;
1504
 
}
1505
 
 
1506
1705
__attribute__((nonnull))
1507
1706
void run_network_hooks(const char *mode, const char *interface,
1508
1707
                       const float delay){
1509
1708
  struct dirent **direntries = NULL;
1510
1709
  if(hookdir_fd == -1){
1511
 
    hookdir_fd = open(hookdir, O_RDONLY);
 
1710
    hookdir_fd = open(hookdir, O_RDONLY | O_DIRECTORY | O_PATH
 
1711
                      | O_CLOEXEC);
1512
1712
    if(hookdir_fd == -1){
1513
1713
      if(errno == ENOENT){
1514
1714
        if(debug){
1539
1739
  }
1540
1740
  struct dirent *direntry;
1541
1741
  int ret;
1542
 
  int devnull = open("/dev/null", O_RDONLY);
 
1742
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
 
1743
  if(devnull == -1){
 
1744
    perror_plus("open(\"/dev/null\", O_RDONLY)");
 
1745
    return;
 
1746
  }
1543
1747
  for(int i = 0; i < numhooks; i++){
1544
1748
    direntry = direntries[i];
1545
1749
    if(debug){
1569
1773
        perror_plus("setgroups");
1570
1774
        _exit(EX_NOPERM);
1571
1775
      }
1572
 
      ret = dup2(devnull, STDIN_FILENO);
1573
 
      if(ret == -1){
1574
 
        perror_plus("dup2(devnull, STDIN_FILENO)");
1575
 
        _exit(EX_OSERR);
1576
 
      }
1577
 
      ret = close(devnull);
1578
 
      if(ret == -1){
1579
 
        perror_plus("close");
1580
 
        _exit(EX_OSERR);
1581
 
      }
1582
 
      ret = dup2(STDERR_FILENO, STDOUT_FILENO);
1583
 
      if(ret == -1){
1584
 
        perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
1585
 
        _exit(EX_OSERR);
1586
 
      }
1587
1776
      ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
1588
1777
      if(ret == -1){
1589
1778
        perror_plus("setenv");
1624
1813
          _exit(EX_OSERR);
1625
1814
        }
1626
1815
      }
1627
 
      int hook_fd = openat(hookdir_fd, direntry->d_name, O_RDONLY);
 
1816
      int hook_fd = TEMP_FAILURE_RETRY(openat(hookdir_fd,
 
1817
                                              direntry->d_name,
 
1818
                                              O_RDONLY));
1628
1819
      if(hook_fd == -1){
1629
1820
        perror_plus("openat");
1630
1821
        _exit(EXIT_FAILURE);
1633
1824
        perror_plus("close");
1634
1825
        _exit(EXIT_FAILURE);
1635
1826
      }
 
1827
      ret = dup2(devnull, STDIN_FILENO);
 
1828
      if(ret == -1){
 
1829
        perror_plus("dup2(devnull, STDIN_FILENO)");
 
1830
        _exit(EX_OSERR);
 
1831
      }
 
1832
      ret = close(devnull);
 
1833
      if(ret == -1){
 
1834
        perror_plus("close");
 
1835
        _exit(EX_OSERR);
 
1836
      }
 
1837
      ret = dup2(STDERR_FILENO, STDOUT_FILENO);
 
1838
      if(ret == -1){
 
1839
        perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)");
 
1840
        _exit(EX_OSERR);
 
1841
      }
1636
1842
      if(fexecve(hook_fd, (char *const []){ direntry->d_name, NULL },
1637
1843
                 environ) == -1){
1638
1844
        perror_plus("fexecve");
1639
1845
        _exit(EXIT_FAILURE);
1640
1846
      }
1641
1847
    } else {
 
1848
      if(hook_pid == -1){
 
1849
        perror_plus("fork");
 
1850
        free(direntry);
 
1851
        continue;
 
1852
      }
1642
1853
      int status;
1643
1854
      if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1644
1855
        perror_plus("waitpid");
 
1856
        free(direntry);
1645
1857
        continue;
1646
1858
      }
1647
1859
      if(WIFEXITED(status)){
1649
1861
          fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1650
1862
                       " with status %d\n", direntry->d_name,
1651
1863
                       WEXITSTATUS(status));
 
1864
          free(direntry);
1652
1865
          continue;
1653
1866
        }
1654
1867
      } else if(WIFSIGNALED(status)){
1655
1868
        fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1656
1869
                     " signal %d\n", direntry->d_name,
1657
1870
                     WTERMSIG(status));
 
1871
        free(direntry);
1658
1872
        continue;
1659
1873
      } else {
1660
1874
        fprintf_plus(stderr, "Warning: network hook \"%s\""
1661
1875
                     " crashed\n", direntry->d_name);
 
1876
        free(direntry);
1662
1877
        continue;
1663
1878
      }
1664
1879
    }
1666
1881
      fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1667
1882
                   direntry->d_name);
1668
1883
    }
 
1884
    free(direntry);
1669
1885
  }
1670
1886
  free(direntries);
1671
1887
  if((int)TEMP_FAILURE_RETRY(close(hookdir_fd)) == -1){
2076
2292
      goto end;
2077
2293
    }
2078
2294
  }
2079
 
    
 
2295
  
2080
2296
  {
2081
2297
    /* Work around Debian bug #633582:
2082
2298
       <http://bugs.debian.org/633582> */
2109
2325
          TEMP_FAILURE_RETRY(close(seckey_fd));
2110
2326
        }
2111
2327
      }
2112
 
    
 
2328
      
2113
2329
      if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){
2114
2330
        int pubkey_fd = open(pubkey, O_RDONLY);
2115
2331
        if(pubkey_fd == -1){
2130
2346
          TEMP_FAILURE_RETRY(close(pubkey_fd));
2131
2347
        }
2132
2348
      }
2133
 
    
 
2349
      
2134
2350
      /* Lower privileges */
2135
2351
      ret_errno = lower_privileges();
2136
2352
      if(ret_errno != 0){
2265
2481
        if(ret_errno != 0){
2266
2482
          errno = ret_errno;
2267
2483
          perror_plus("argz_add");
 
2484
          free(direntries[i]);
2268
2485
          continue;
2269
2486
        }
2270
2487
        if(debug){
2271
2488
          fprintf_plus(stderr, "Will use interface \"%s\"\n",
2272
2489
                       direntries[i]->d_name);
2273
2490
        }
 
2491
        free(direntries[i]);
2274
2492
      }
2275
2493
      free(direntries);
2276
2494
    } else {
2546
2764
    mc.current_server->prev->next = NULL;
2547
2765
    while(mc.current_server != NULL){
2548
2766
      server *next = mc.current_server->next;
 
2767
#ifdef __GNUC__
 
2768
#pragma GCC diagnostic push
 
2769
#pragma GCC diagnostic ignored "-Wcast-qual"
 
2770
#endif
 
2771
      free((char *)(mc.current_server->ip));
 
2772
#ifdef __GNUC__
 
2773
#pragma GCC diagnostic pop
 
2774
#endif
2549
2775
      free(mc.current_server);
2550
2776
      mc.current_server = next;
2551
2777
    }
2595
2821
  /* Removes the GPGME temp directory and all files inside */
2596
2822
  if(tempdir != NULL){
2597
2823
    struct dirent **direntries = NULL;
2598
 
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY |
2599
 
                                                  O_NOFOLLOW));
 
2824
    int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY
 
2825
                                                  | O_NOFOLLOW
 
2826
                                                  | O_DIRECTORY
 
2827
                                                  | O_PATH));
2600
2828
    if(tempdir_fd == -1){
2601
2829
      perror_plus("open");
2602
2830
    } else {
2620
2848
                         " \"%s\", 0): %s\n", tempdir,
2621
2849
                         direntries[i]->d_name, strerror(errno));
2622
2850
          }
 
2851
          free(direntries[i]);
2623
2852
        }
2624
2853
        
2625
2854
        /* need to clean even if 0 because man page doesn't specify */