/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 plugin-runner.c

  • Committer: Teddy Hogeborn
  • Date: 2016-03-17 20:40:55 UTC
  • mto: (237.7.594 trunk)
  • mto: This revision was merged to the branch mainline in revision 341.
  • Revision ID: teddy@recompile.se-20160317204055-bhsh5xsidq7w5cxu
Client: Fix plymouth agent; broken since 1.7.2.

Fix an very old memory bug in the plymouth agent (which has been
present since its apperance in version 1.2), but which was only
recently detected at run time due to the new -fsanitize=address
compile- time flag, which has been used since version 1.7.2.  This
detection of a memory access violation causes the program to abort,
making the Plymouth graphical boot system unable to accept interactive
input of passwords when using the Mandos client.

* plugins.d/plymouth.c (exec_and_wait): Fix memory allocation bug when
  allocating new_argv.  Also tolerate a zero-length argv.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Mandos plugin runner - Run Mandos plugins
4
4
 *
5
 
 * Copyright © 2008-2014 Teddy Hogeborn
6
 
 * Copyright © 2008-2014 Björn Påhlsson
 
5
 * Copyright © 2008-2016 Teddy Hogeborn
 
6
 * Copyright © 2008-2016 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
23
23
 */
24
24
 
25
25
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), getline(),
26
 
                                   O_CLOEXEC */
 
26
                                   O_CLOEXEC, pipe2() */
27
27
#include <stddef.h>             /* size_t, NULL */
28
28
#include <stdlib.h>             /* malloc(), exit(), EXIT_SUCCESS,
29
29
                                   realloc() */
30
30
#include <stdbool.h>            /* bool, true, false */
31
31
#include <stdio.h>              /* fileno(), fprintf(),
32
32
                                   stderr, STDOUT_FILENO, fclose() */
33
 
#include <sys/types.h>          /* DIR, fdopendir(), fstat(), struct
34
 
                                   stat, waitpid(), WIFEXITED(),
35
 
                                   WEXITSTATUS(), wait(), pid_t,
36
 
                                   uid_t, gid_t, getuid(), getgid(),
37
 
                                   dirfd() */
 
33
#include <sys/types.h>          /* fstat(), struct stat, waitpid(),
 
34
                                   WIFEXITED(), WEXITSTATUS(), wait(),
 
35
                                   pid_t, uid_t, gid_t, getuid(),
 
36
                                   getgid() */
38
37
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
39
38
                                   FD_SET(), FD_ISSET(), FD_CLR */
40
39
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
42
41
                                   WCOREDUMP() */
43
42
#include <sys/stat.h>           /* struct stat, fstat(), S_ISREG() */
44
43
#include <iso646.h>             /* and, or, not */
45
 
#include <dirent.h>             /* DIR, struct dirent, fdopendir(),
46
 
                                   readdir(), closedir(), dirfd() */
 
44
#include <dirent.h>             /* struct dirent, scandirat() */
47
45
#include <unistd.h>             /* fcntl(), F_GETFD, F_SETFD,
48
46
                                   FD_CLOEXEC, write(), STDOUT_FILENO,
49
47
                                   struct stat, fstat(), close(),
50
48
                                   setgid(), setuid(), S_ISREG(),
51
 
                                   faccessat() pipe(), fork(),
 
49
                                   faccessat() pipe2(), fork(),
52
50
                                   _exit(), dup2(), fexecve(), read()
53
51
                                */
54
52
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
55
 
                                   FD_CLOEXEC, openat() */
 
53
                                   FD_CLOEXEC, openat(), scandirat(),
 
54
                                   pipe2() */
56
55
#include <string.h>             /* strsep, strlen(), strsignal(),
57
56
                                   strcmp(), strncmp() */
58
57
#include <errno.h>              /* errno */
77
76
#define BUFFER_SIZE 256
78
77
 
79
78
#define PDIR "/lib/mandos/plugins.d"
 
79
#define PHDIR "/lib/mandos/plugin-helpers"
80
80
#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
81
81
 
82
82
const char *argp_program_version = "plugin-runner " VERSION;
241
241
  return add_to_char_array(def, &(p->environ), &(p->envc));
242
242
}
243
243
 
 
244
#ifndef O_CLOEXEC
244
245
/*
245
246
 * Based on the example in the GNU LibC manual chapter 13.13 "File
246
247
 * Descriptor Flags".
257
258
  return (int)TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD,
258
259
                                       ret | FD_CLOEXEC));
259
260
}
 
261
#endif  /* not O_CLOEXEC */
260
262
 
261
263
 
262
264
/* Mark processes as completed when they exit, and save their exit
346
348
 
347
349
int main(int argc, char *argv[]){
348
350
  char *plugindir = NULL;
 
351
  char *pluginhelperdir = NULL;
349
352
  char *argfile = NULL;
350
353
  FILE *conffp;
351
 
  DIR *dir = NULL;
352
 
  struct dirent *dirst;
 
354
  struct dirent **direntries = NULL;
353
355
  struct stat st;
354
356
  fd_set rfds_all;
355
357
  int ret, maxfd = 0;
363
365
                                      .sa_flags = SA_NOCLDSTOP };
364
366
  char **custom_argv = NULL;
365
367
  int custom_argc = 0;
366
 
  int dir_fd;
 
368
  int dir_fd = -1;
367
369
  
368
370
  /* Establish a signal handler */
369
371
  sigemptyset(&sigchld_action.sa_mask);
414
416
      .doc = "Group ID the plugins will run as", .group = 3 },
415
417
    { .name = "debug", .key = 132,
416
418
      .doc = "Debug mode", .group = 4 },
 
419
    { .name = "plugin-helper-dir", .key = 133,
 
420
      .arg = "DIRECTORY",
 
421
      .doc = "Specify a different plugin helper directory",
 
422
      .group = 2 },
417
423
    /*
418
424
     * These reproduce what we would get without ARGP_NO_HELP
419
425
     */
545
551
    case 132:                   /* --debug */
546
552
      debug = true;
547
553
      break;
 
554
    case 133:                   /* --plugin-helper-dir */
 
555
      free(pluginhelperdir);
 
556
      pluginhelperdir = strdup(arg);
 
557
      if(pluginhelperdir != NULL){
 
558
        errno = 0;
 
559
      }
 
560
      break;
548
561
      /*
549
562
       * These reproduce what we would get without ARGP_NO_HELP
550
563
       */
601
614
    case 130:                   /* --userid */
602
615
    case 131:                   /* --groupid */
603
616
    case 132:                   /* --debug */
 
617
    case 133:                   /* --plugin-helper-dir */
604
618
    case '?':                   /* --help */
605
619
    case -3:                    /* --usage */
606
620
    case 'V':                   /* --version */
687
701
        custom_argc += 1;
688
702
        {
689
703
          char **new_argv = realloc(custom_argv, sizeof(char *)
690
 
                                    * ((unsigned int)
691
 
                                       custom_argc + 1));
 
704
                                    * ((size_t)custom_argc + 1));
692
705
          if(new_argv == NULL){
693
706
            error(0, errno, "realloc");
694
707
            exitstatus = EX_OSERR;
761
774
    goto fallback;
762
775
  }
763
776
  
 
777
  {
 
778
    char *pluginhelperenv;
 
779
    bool bret = true;
 
780
    ret = asprintf(&pluginhelperenv, "MANDOSPLUGINHELPERDIR=%s",
 
781
                   pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
782
    if(ret != -1){
 
783
      bret = add_environment(getplugin(NULL), pluginhelperenv, true);
 
784
    }
 
785
    if(ret == -1 or not bret){
 
786
      error(0, errno, "Failed to set MANDOSPLUGINHELPERDIR"
 
787
            " environment variable to \"%s\" for all plugins\n",
 
788
            pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
789
    }
 
790
    if(ret != -1){
 
791
      free(pluginhelperenv);
 
792
    }
 
793
  }
 
794
  
764
795
  if(debug){
765
796
    for(plugin *p = plugin_list; p != NULL; p=p->next){
766
797
      fprintf(stderr, "Plugin: %s has %d arguments\n",
795
826
          }
796
827
        }
797
828
      }
798
 
      TEMP_FAILURE_RETRY(close(plugindir_fd));
 
829
      close(plugindir_fd);
799
830
    }
800
831
  }
801
832
  
829
860
    ret = set_cloexec_flag(dir_fd);
830
861
    if(ret < 0){
831
862
      error(0, errno, "set_cloexec_flag");
832
 
      TEMP_FAILURE_RETRY(close(dir_fd));
833
863
      exitstatus = EX_OSERR;
834
864
      goto fallback;
835
865
    }
836
866
#endif  /* O_CLOEXEC */
837
 
    
838
 
    dir = fdopendir(dir_fd);
839
 
    if(dir == NULL){
840
 
      error(0, errno, "Could not open plugin dir");
841
 
      TEMP_FAILURE_RETRY(close(dir_fd));
842
 
      exitstatus = EX_OSERR;
843
 
      goto fallback;
 
867
  }
 
868
  
 
869
  int good_name(const struct dirent * const dirent){
 
870
    const char * const patterns[] = { ".*", "#*#", "*~", "*.dpkg-new",
 
871
                                      "*.dpkg-old", "*.dpkg-bak",
 
872
                                      "*.dpkg-divert", NULL };
 
873
#ifdef __GNUC__
 
874
#pragma GCC diagnostic push
 
875
#pragma GCC diagnostic ignored "-Wcast-qual"
 
876
#endif
 
877
    for(const char **pat = (const char **)patterns;
 
878
        *pat != NULL; pat++){
 
879
#ifdef __GNUC__
 
880
#pragma GCC diagnostic pop
 
881
#endif
 
882
      if(fnmatch(*pat, dirent->d_name, FNM_FILE_NAME | FNM_PERIOD)
 
883
         != FNM_NOMATCH){
 
884
        if(debug){
 
885
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
 
886
                    " matching pattern %s\n", dirent->d_name, *pat);
 
887
        }
 
888
        return 0;
 
889
      }
844
890
    }
 
891
    return 1;
 
892
  }
 
893
  
 
894
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
 
895
                             alphasort);
 
896
  if(numplugins == -1){
 
897
    error(0, errno, "Could not scan plugin dir");
 
898
    direntries = NULL;
 
899
    exitstatus = EX_OSERR;
 
900
    goto fallback;
845
901
  }
846
902
  
847
903
  FD_ZERO(&rfds_all);
848
904
  
849
905
  /* Read and execute any executable in the plugin directory*/
850
 
  while(true){
851
 
    do {
852
 
      dirst = readdir(dir);
853
 
    } while(dirst == NULL and errno == EINTR);
854
 
    
855
 
    /* All directory entries have been processed */
856
 
    if(dirst == NULL){
857
 
      if(errno == EBADF){
858
 
        error(0, errno, "readdir");
859
 
        exitstatus = EX_IOERR;
860
 
        goto fallback;
861
 
      }
862
 
      break;
863
 
    }
864
 
    
865
 
    /* Ignore dotfiles, backup files and other junk */
866
 
    {
867
 
      bool bad_name = false;
868
 
      const char * const patterns[] = { ".*", "#*#", "*~",
869
 
                                        "*.dpkg-new", "*.dpkg-old",
870
 
                                        "*.dpkg-bak", "*.dpkg-divert",
871
 
                                        NULL };
872
 
#ifdef __GNUC__
873
 
#pragma GCC diagnostic push
874
 
#pragma GCC diagnostic ignored "-Wcast-qual"
875
 
#endif
876
 
      for(const char **pat = (const char **)patterns;
877
 
          *pat != NULL; pat++){
878
 
#ifdef __GNUC__
879
 
#pragma GCC diagnostic pop
880
 
#endif
881
 
        if(fnmatch(*pat, dirst->d_name,
882
 
                   FNM_FILE_NAME | FNM_PERIOD) != FNM_NOMATCH){
883
 
          if(debug){
884
 
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
885
 
                    " matching pattern %s\n", dirst->d_name, *pat);
886
 
          }
887
 
          bad_name = true;
888
 
          break;
889
 
        }
890
 
      }
891
 
      if(bad_name){
892
 
        continue;
893
 
      }
894
 
    }
895
 
    
896
 
    int plugin_fd = openat(dir_fd, dirst->d_name, O_RDONLY |
897
 
#ifdef O_CLOEXEC
898
 
                            O_CLOEXEC
899
 
#else  /* not O_CLOEXEC */
900
 
                            0
901
 
#endif  /* not O_CLOEXEC */
902
 
                            );
 
906
  for(int i = 0; i < numplugins; i++){
 
907
    
 
908
    int plugin_fd = openat(dir_fd, direntries[i]->d_name, O_RDONLY);
903
909
    if(plugin_fd == -1){
904
910
      error(0, errno, "Could not open plugin");
905
 
      continue;
906
 
    }
907
 
#ifndef O_CLOEXEC
908
 
  /* Set the FD_CLOEXEC flag on the plugin FD */
909
 
    ret = set_cloexec_flag(plugin_fd);
910
 
    if(ret < 0){
911
 
      error(0, errno, "set_cloexec_flag");
912
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
913
 
      continue;
914
 
    }
915
 
#endif  /* O_CLOEXEC */
 
911
      free(direntries[i]);
 
912
      continue;
 
913
    }
916
914
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
917
915
    if(ret == -1){
918
916
      error(0, errno, "stat");
919
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
917
      close(plugin_fd);
 
918
      free(direntries[i]);
920
919
      continue;
921
920
    }
922
921
    
923
922
    /* Ignore non-executable files */
924
923
    if(not S_ISREG(st.st_mode)
925
 
       or (TEMP_FAILURE_RETRY(faccessat(dir_fd, dirst->d_name, X_OK,
926
 
                                        0)) != 0)){
 
924
       or (TEMP_FAILURE_RETRY(faccessat(dir_fd, direntries[i]->d_name,
 
925
                                        X_OK, 0)) != 0)){
927
926
      if(debug){
928
927
        fprintf(stderr, "Ignoring plugin dir entry \"%s/%s\""
929
928
                " with bad type or mode\n",
930
 
                plugindir != NULL ? plugindir : PDIR, dirst->d_name);
 
929
                plugindir != NULL ? plugindir : PDIR,
 
930
                direntries[i]->d_name);
931
931
      }
932
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
932
      close(plugin_fd);
 
933
      free(direntries[i]);
933
934
      continue;
934
935
    }
935
936
    
936
 
    plugin *p = getplugin(dirst->d_name);
 
937
    plugin *p = getplugin(direntries[i]->d_name);
937
938
    if(p == NULL){
938
939
      error(0, errno, "getplugin");
939
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
940
      close(plugin_fd);
 
941
      free(direntries[i]);
940
942
      continue;
941
943
    }
942
944
    if(p->disabled){
943
945
      if(debug){
944
946
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
945
 
                dirst->d_name);
 
947
                direntries[i]->d_name);
946
948
      }
947
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
949
      close(plugin_fd);
 
950
      free(direntries[i]);
948
951
      continue;
949
952
    }
950
953
    {
975
978
    }
976
979
    
977
980
    int pipefd[2];
 
981
#ifndef O_CLOEXEC
978
982
    ret = (int)TEMP_FAILURE_RETRY(pipe(pipefd));
 
983
#else  /* O_CLOEXEC */
 
984
    ret = (int)TEMP_FAILURE_RETRY(pipe2(pipefd, O_CLOEXEC));
 
985
#endif  /* O_CLOEXEC */
979
986
    if(ret == -1){
980
987
      error(0, errno, "pipe");
981
988
      exitstatus = EX_OSERR;
982
 
      goto fallback;
983
 
    }
 
989
      free(direntries[i]);
 
990
      goto fallback;
 
991
    }
 
992
    if(pipefd[0] >= FD_SETSIZE){
 
993
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
 
994
              FD_SETSIZE);
 
995
      close(pipefd[0]);
 
996
      close(pipefd[1]);
 
997
      exitstatus = EX_OSERR;
 
998
      free(direntries[i]);
 
999
      goto fallback;
 
1000
    }
 
1001
#ifndef O_CLOEXEC
984
1002
    /* Ask OS to automatic close the pipe on exec */
985
1003
    ret = set_cloexec_flag(pipefd[0]);
986
1004
    if(ret < 0){
987
1005
      error(0, errno, "set_cloexec_flag");
 
1006
      close(pipefd[0]);
 
1007
      close(pipefd[1]);
988
1008
      exitstatus = EX_OSERR;
 
1009
      free(direntries[i]);
989
1010
      goto fallback;
990
1011
    }
991
1012
    ret = set_cloexec_flag(pipefd[1]);
992
1013
    if(ret < 0){
993
1014
      error(0, errno, "set_cloexec_flag");
 
1015
      close(pipefd[0]);
 
1016
      close(pipefd[1]);
994
1017
      exitstatus = EX_OSERR;
 
1018
      free(direntries[i]);
995
1019
      goto fallback;
996
1020
    }
 
1021
#endif  /* not O_CLOEXEC */
997
1022
    /* Block SIGCHLD until process is safely in process list */
998
1023
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK,
999
1024
                                              &sigchld_action.sa_mask,
1001
1026
    if(ret < 0){
1002
1027
      error(0, errno, "sigprocmask");
1003
1028
      exitstatus = EX_OSERR;
 
1029
      free(direntries[i]);
1004
1030
      goto fallback;
1005
1031
    }
1006
1032
    /* Starting a new process to be watched */
1010
1036
    } while(pid == -1 and errno == EINTR);
1011
1037
    if(pid == -1){
1012
1038
      error(0, errno, "fork");
 
1039
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
 
1040
                                     &sigchld_action.sa_mask, NULL));
 
1041
      close(pipefd[0]);
 
1042
      close(pipefd[1]);
1013
1043
      exitstatus = EX_OSERR;
 
1044
      free(direntries[i]);
1014
1045
      goto fallback;
1015
1046
    }
1016
1047
    if(pid == 0){
1032
1063
        _exit(EX_OSERR);
1033
1064
      }
1034
1065
      
1035
 
      if(dirfd(dir) < 0){
1036
 
        /* If dir has no file descriptor, we could not set FD_CLOEXEC
1037
 
           above and must now close it manually here. */
1038
 
        closedir(dir);
1039
 
      }
1040
1066
      if(fexecve(plugin_fd, p->argv,
1041
1067
                (p->environ[0] != NULL) ? p->environ : environ) < 0){
1042
1068
        error(0, errno, "fexecve for %s/%s",
1043
 
              plugindir != NULL ? plugindir : PDIR, dirst->d_name);
 
1069
              plugindir != NULL ? plugindir : PDIR,
 
1070
              direntries[i]->d_name);
1044
1071
        _exit(EX_OSERR);
1045
1072
      }
1046
1073
      /* no return */
1047
1074
    }
1048
1075
    /* Parent process */
1049
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1050
 
                                             pipe */
1051
 
    TEMP_FAILURE_RETRY(close(plugin_fd));
1052
 
    plugin *new_plugin = getplugin(dirst->d_name);
 
1076
    close(pipefd[1]);           /* Close unused write end of pipe */
 
1077
    close(plugin_fd);
 
1078
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1053
1079
    if(new_plugin == NULL){
1054
1080
      error(0, errno, "getplugin");
1055
1081
      ret = (int)(TEMP_FAILURE_RETRY
1059
1085
        error(0, errno, "sigprocmask");
1060
1086
      }
1061
1087
      exitstatus = EX_OSERR;
 
1088
      free(direntries[i]);
1062
1089
      goto fallback;
1063
1090
    }
 
1091
    free(direntries[i]);
1064
1092
    
1065
1093
    new_plugin->pid = pid;
1066
1094
    new_plugin->fd = pipefd[0];
1076
1104
      goto fallback;
1077
1105
    }
1078
1106
    
1079
 
#if defined (__GNUC__) and defined (__GLIBC__)
1080
 
#if not __GLIBC_PREREQ(2, 16)
1081
 
#pragma GCC diagnostic push
1082
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1083
 
#endif
1084
 
#endif
1085
 
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
1086
 
                                          -Wconversion in GNU libc
1087
 
                                          before 2.16 */
1088
 
#if defined (__GNUC__) and defined (__GLIBC__)
1089
 
#if not __GLIBC_PREREQ(2, 16)
1090
 
#pragma GCC diagnostic pop
1091
 
#endif
1092
 
#endif
 
1107
    FD_SET(new_plugin->fd, &rfds_all);
1093
1108
    
1094
1109
    if(maxfd < new_plugin->fd){
1095
1110
      maxfd = new_plugin->fd;
1096
1111
    }
1097
1112
  }
1098
1113
  
1099
 
  TEMP_FAILURE_RETRY(closedir(dir));
1100
 
  dir = NULL;
 
1114
  free(direntries);
 
1115
  direntries = NULL;
 
1116
  close(dir_fd);
 
1117
  dir_fd = -1;
1101
1118
  free_plugin(getplugin(NULL));
1102
1119
  
1103
1120
  for(plugin *p = plugin_list; p != NULL; p = p->next){
1149
1166
          }
1150
1167
          
1151
1168
          /* Remove the plugin */
1152
 
#if defined (__GNUC__) and defined (__GLIBC__)
1153
 
#if not __GLIBC_PREREQ(2, 16)
1154
 
#pragma GCC diagnostic push
1155
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1156
 
#endif
1157
 
#endif
1158
 
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
1159
 
                                          -Wconversion in GNU libc
1160
 
                                          before 2.16 */
1161
 
#if defined (__GNUC__) and defined (__GLIBC__)
1162
 
#if not __GLIBC_PREREQ(2, 16)
1163
 
#pragma GCC diagnostic pop
1164
 
#endif
1165
 
#endif
 
1169
          FD_CLR(proc->fd, &rfds_all);
1166
1170
          
1167
1171
          /* Block signal while modifying process_list */
1168
1172
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1208
1212
      }
1209
1213
      
1210
1214
      /* This process has not completed.  Does it have any output? */
1211
 
#if defined (__GNUC__) and defined (__GLIBC__)
1212
 
#if not __GLIBC_PREREQ(2, 16)
1213
 
#pragma GCC diagnostic push
1214
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1215
 
#endif
1216
 
#endif
1217
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1218
 
                                                         warning from
1219
 
                                                         -Wconversion
1220
 
                                                         in GNU libc
1221
 
                                                         before
1222
 
                                                         2.16 */
1223
 
#if defined (__GNUC__) and defined (__GLIBC__)
1224
 
#if not __GLIBC_PREREQ(2, 16)
1225
 
#pragma GCC diagnostic pop
1226
 
#endif
1227
 
#endif
 
1215
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1228
1216
        /* This process had nothing to say at this time */
1229
1217
        proc = proc->next;
1230
1218
        continue;
1297
1285
    free(custom_argv);
1298
1286
  }
1299
1287
  
1300
 
  if(dir != NULL){
1301
 
    closedir(dir);
 
1288
  free(direntries);
 
1289
  
 
1290
  if(dir_fd != -1){
 
1291
    close(dir_fd);
1302
1292
  }
1303
1293
  
1304
1294
  /* Kill the processes */
1324
1314
  free_plugin_list();
1325
1315
  
1326
1316
  free(plugindir);
 
1317
  free(pluginhelperdir);
1327
1318
  free(argfile);
1328
1319
  
1329
1320
  return exitstatus;