/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-2013 Teddy Hogeborn
6
 
 * Copyright © 2008-2013 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
 
                                   asprintf(), 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
 
                                   stderr, STDOUT_FILENO */
33
 
#include <sys/types.h>          /* DIR, fdopendir(), stat(), struct
34
 
                                   stat, waitpid(), WIFEXITED(),
35
 
                                   WEXITSTATUS(), wait(), pid_t,
36
 
                                   uid_t, gid_t, getuid(), getgid(),
37
 
                                   dirfd() */
 
32
                                   stderr, STDOUT_FILENO, fclose() */
 
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(),
41
40
                                   WEXITSTATUS(), WTERMSIG(),
42
41
                                   WCOREDUMP() */
43
 
#include <sys/stat.h>           /* struct stat, stat(), S_ISREG() */
 
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() */
47
 
#include <unistd.h>             /* struct stat, stat(), S_ISREG(),
48
 
                                   fcntl(), setuid(), setgid(),
49
 
                                   F_GETFD, F_SETFD, FD_CLOEXEC,
50
 
                                   access(), pipe(), fork(), close()
51
 
                                   dup2(), STDOUT_FILENO, _exit(),
52
 
                                   execve(), write(), read(),
53
 
                                   close() */
 
44
#include <dirent.h>             /* struct dirent, scandirat() */
 
45
#include <unistd.h>             /* fcntl(), F_GETFD, F_SETFD,
 
46
                                   FD_CLOEXEC, write(), STDOUT_FILENO,
 
47
                                   struct stat, fstat(), close(),
 
48
                                   setgid(), setuid(), S_ISREG(),
 
49
                                   faccessat() pipe2(), fork(),
 
50
                                   _exit(), dup2(), fexecve(), read()
 
51
                                */
54
52
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
55
 
                                   FD_CLOEXEC */
56
 
#include <string.h>             /* strsep, strlen(), asprintf(),
57
 
                                   strsignal(), strcmp(), strncmp() */
 
53
                                   FD_CLOEXEC, openat(), scandirat(),
 
54
                                   pipe2() */
 
55
#include <string.h>             /* strsep, strlen(), strsignal(),
 
56
                                   strcmp(), strncmp() */
58
57
#include <errno.h>              /* errno */
59
58
#include <argp.h>               /* struct argp_option, struct
60
59
                                   argp_state, struct argp,
72
71
                                   EX_CONFIG, EX_UNAVAILABLE, EX_OK */
73
72
#include <errno.h>              /* errno */
74
73
#include <error.h>              /* error() */
 
74
#include <fnmatch.h>            /* fnmatch() */
75
75
 
76
76
#define BUFFER_SIZE 256
77
77
 
78
78
#define PDIR "/lib/mandos/plugins.d"
 
79
#define PHDIR "/lib/mandos/plugin-helpers"
79
80
#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
80
81
 
81
82
const char *argp_program_version = "plugin-runner " VERSION;
240
241
  return add_to_char_array(def, &(p->environ), &(p->envc));
241
242
}
242
243
 
 
244
#ifndef O_CLOEXEC
243
245
/*
244
246
 * Based on the example in the GNU LibC manual chapter 13.13 "File
245
247
 * Descriptor Flags".
256
258
  return (int)TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD,
257
259
                                       ret | FD_CLOEXEC));
258
260
}
 
261
#endif  /* not O_CLOEXEC */
259
262
 
260
263
 
261
264
/* Mark processes as completed when they exit, and save their exit
345
348
 
346
349
int main(int argc, char *argv[]){
347
350
  char *plugindir = NULL;
 
351
  char *pluginhelperdir = NULL;
348
352
  char *argfile = NULL;
349
353
  FILE *conffp;
350
 
  size_t d_name_len;
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;
 
368
  int dir_fd = -1;
366
369
  
367
370
  /* Establish a signal handler */
368
371
  sigemptyset(&sigchld_action.sa_mask);
413
416
      .doc = "Group ID the plugins will run as", .group = 3 },
414
417
    { .name = "debug", .key = 132,
415
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 },
416
423
    /*
417
424
     * These reproduce what we would get without ARGP_NO_HELP
418
425
     */
544
551
    case 132:                   /* --debug */
545
552
      debug = true;
546
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;
547
561
      /*
548
562
       * These reproduce what we would get without ARGP_NO_HELP
549
563
       */
600
614
    case 130:                   /* --userid */
601
615
    case 131:                   /* --groupid */
602
616
    case 132:                   /* --debug */
 
617
    case 133:                   /* --plugin-helper-dir */
603
618
    case '?':                   /* --help */
604
619
    case -3:                    /* --usage */
605
620
    case 'V':                   /* --version */
686
701
        custom_argc += 1;
687
702
        {
688
703
          char **new_argv = realloc(custom_argv, sizeof(char *)
689
 
                                    * ((unsigned int)
690
 
                                       custom_argc + 1));
 
704
                                    * ((size_t)custom_argc + 1));
691
705
          if(new_argv == NULL){
692
706
            error(0, errno, "realloc");
693
707
            exitstatus = EX_OSERR;
760
774
    goto fallback;
761
775
  }
762
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
  
763
795
  if(debug){
764
796
    for(plugin *p = plugin_list; p != NULL; p=p->next){
765
797
      fprintf(stderr, "Plugin: %s has %d arguments\n",
779
811
       <http://bugs.debian.org/633582> */
780
812
    int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY);
781
813
    if(plugindir_fd == -1){
782
 
      error(0, errno, "open(\"" PDIR "\")");
 
814
      if(errno != ENOENT){
 
815
        error(0, errno, "open(\"" PDIR "\")");
 
816
      }
783
817
    } else {
784
818
      ret = (int)TEMP_FAILURE_RETRY(fstat(plugindir_fd, &st));
785
819
      if(ret == -1){
792
826
          }
793
827
        }
794
828
      }
795
 
      TEMP_FAILURE_RETRY(close(plugindir_fd));
 
829
      close(plugindir_fd);
796
830
    }
797
831
  }
798
832
  
808
842
  
809
843
  /* Open plugin directory with close_on_exec flag */
810
844
  {
811
 
    int dir_fd = -1;
812
 
    if(plugindir == NULL){
813
 
      dir_fd = open(PDIR, O_RDONLY |
814
 
#ifdef O_CLOEXEC
815
 
                    O_CLOEXEC
816
 
#else  /* not O_CLOEXEC */
817
 
                    0
818
 
#endif  /* not O_CLOEXEC */
819
 
                    );
820
 
    } else {
821
 
      dir_fd = open(plugindir, O_RDONLY |
822
 
#ifdef O_CLOEXEC
823
 
                    O_CLOEXEC
824
 
#else  /* not O_CLOEXEC */
825
 
                    0
826
 
#endif  /* not O_CLOEXEC */
827
 
                    );
828
 
    }
 
845
    dir_fd = open(plugindir != NULL ? plugindir : PDIR, O_RDONLY |
 
846
#ifdef O_CLOEXEC
 
847
                  O_CLOEXEC
 
848
#else  /* not O_CLOEXEC */
 
849
                  0
 
850
#endif  /* not O_CLOEXEC */
 
851
                  );
829
852
    if(dir_fd == -1){
830
853
      error(0, errno, "Could not open plugin dir");
831
854
      exitstatus = EX_UNAVAILABLE;
837
860
    ret = set_cloexec_flag(dir_fd);
838
861
    if(ret < 0){
839
862
      error(0, errno, "set_cloexec_flag");
840
 
      TEMP_FAILURE_RETRY(close(dir_fd));
841
863
      exitstatus = EX_OSERR;
842
864
      goto fallback;
843
865
    }
844
866
#endif  /* O_CLOEXEC */
845
 
    
846
 
    dir = fdopendir(dir_fd);
847
 
    if(dir == NULL){
848
 
      error(0, errno, "Could not open plugin dir");
849
 
      TEMP_FAILURE_RETRY(close(dir_fd));
850
 
      exitstatus = EX_OSERR;
851
 
      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
      }
852
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;
853
901
  }
854
902
  
855
903
  FD_ZERO(&rfds_all);
856
904
  
857
905
  /* Read and execute any executable in the plugin directory*/
858
 
  while(true){
859
 
    do {
860
 
      dirst = readdir(dir);
861
 
    } while(dirst == NULL and errno == EINTR);
862
 
    
863
 
    /* All directory entries have been processed */
864
 
    if(dirst == NULL){
865
 
      if(errno == EBADF){
866
 
        error(0, errno, "readdir");
867
 
        exitstatus = EX_IOERR;
868
 
        goto fallback;
869
 
      }
870
 
      break;
871
 
    }
872
 
    
873
 
    d_name_len = strlen(dirst->d_name);
874
 
    
875
 
    /* Ignore dotfiles, backup files and other junk */
876
 
    {
877
 
      bool bad_name = false;
878
 
      
879
 
      const char * const bad_prefixes[] = { ".", "#", NULL };
880
 
      
881
 
      const char * const bad_suffixes[] = { "~", "#", ".dpkg-new",
882
 
                                           ".dpkg-old",
883
 
                                           ".dpkg-bak",
884
 
                                           ".dpkg-divert", NULL };
885
 
#ifdef __GNUC__
886
 
#pragma GCC diagnostic push
887
 
#pragma GCC diagnostic ignored "-Wcast-qual"
888
 
#endif
889
 
      for(const char **pre = (const char **)bad_prefixes;
890
 
          *pre != NULL; pre++){
891
 
#ifdef __GNUC__
892
 
#pragma GCC diagnostic pop
893
 
#endif
894
 
        size_t pre_len = strlen(*pre);
895
 
        if((d_name_len >= pre_len)
896
 
           and strncmp((dirst->d_name), *pre, pre_len) == 0){
897
 
          if(debug){
898
 
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
899
 
                    " with bad prefix %s\n", dirst->d_name, *pre);
900
 
          }
901
 
          bad_name = true;
902
 
          break;
903
 
        }
904
 
      }
905
 
      if(bad_name){
906
 
        continue;
907
 
      }
908
 
#ifdef __GNUC__
909
 
#pragma GCC diagnostic push
910
 
#pragma GCC diagnostic ignored "-Wcast-qual"
911
 
#endif
912
 
      for(const char **suf = (const char **)bad_suffixes;
913
 
          *suf != NULL; suf++){
914
 
#ifdef __GNUC__
915
 
#pragma GCC diagnostic pop
916
 
#endif
917
 
        size_t suf_len = strlen(*suf);
918
 
        if((d_name_len >= suf_len)
919
 
           and (strcmp((dirst->d_name) + d_name_len-suf_len, *suf)
920
 
                == 0)){
921
 
          if(debug){
922
 
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
923
 
                    " with bad suffix %s\n", dirst->d_name, *suf);
924
 
          }
925
 
          bad_name = true;
926
 
          break;
927
 
        }
928
 
      }
929
 
      
930
 
      if(bad_name){
931
 
        continue;
932
 
      }
933
 
    }
934
 
    
935
 
    char *filename;
936
 
    if(plugindir == NULL){
937
 
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s",
938
 
                                             dirst->d_name));
939
 
    } else {
940
 
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s",
941
 
                                             plugindir,
942
 
                                             dirst->d_name));
943
 
    }
944
 
    if(ret < 0){
945
 
      error(0, errno, "asprintf");
 
906
  for(int i = 0; i < numplugins; i++){
 
907
    
 
908
    int plugin_fd = openat(dir_fd, direntries[i]->d_name, O_RDONLY);
 
909
    if(plugin_fd == -1){
 
910
      error(0, errno, "Could not open plugin");
 
911
      free(direntries[i]);
946
912
      continue;
947
913
    }
948
 
    
949
 
    ret = (int)TEMP_FAILURE_RETRY(stat(filename, &st));
 
914
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
950
915
    if(ret == -1){
951
916
      error(0, errno, "stat");
952
 
      free(filename);
 
917
      close(plugin_fd);
 
918
      free(direntries[i]);
953
919
      continue;
954
920
    }
955
921
    
956
922
    /* Ignore non-executable files */
957
923
    if(not S_ISREG(st.st_mode)
958
 
       or (TEMP_FAILURE_RETRY(access(filename, X_OK)) != 0)){
 
924
       or (TEMP_FAILURE_RETRY(faccessat(dir_fd, direntries[i]->d_name,
 
925
                                        X_OK, 0)) != 0)){
959
926
      if(debug){
960
 
        fprintf(stderr, "Ignoring plugin dir entry \"%s\""
961
 
                " with bad type or mode\n", filename);
 
927
        fprintf(stderr, "Ignoring plugin dir entry \"%s/%s\""
 
928
                " with bad type or mode\n",
 
929
                plugindir != NULL ? plugindir : PDIR,
 
930
                direntries[i]->d_name);
962
931
      }
963
 
      free(filename);
 
932
      close(plugin_fd);
 
933
      free(direntries[i]);
964
934
      continue;
965
935
    }
966
936
    
967
 
    plugin *p = getplugin(dirst->d_name);
 
937
    plugin *p = getplugin(direntries[i]->d_name);
968
938
    if(p == NULL){
969
939
      error(0, errno, "getplugin");
970
 
      free(filename);
 
940
      close(plugin_fd);
 
941
      free(direntries[i]);
971
942
      continue;
972
943
    }
973
944
    if(p->disabled){
974
945
      if(debug){
975
946
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
976
 
                dirst->d_name);
 
947
                direntries[i]->d_name);
977
948
      }
978
 
      free(filename);
 
949
      close(plugin_fd);
 
950
      free(direntries[i]);
979
951
      continue;
980
952
    }
981
953
    {
995
967
        }
996
968
      }
997
969
    }
998
 
    /* If this plugin has any environment variables, we will call
999
 
       using execve and need to duplicate the environment from this
1000
 
       process, too. */
 
970
    /* If this plugin has any environment variables, we need to
 
971
       duplicate the environment from this process, too. */
1001
972
    if(p->environ[0] != NULL){
1002
973
      for(char **e = environ; *e != NULL; e++){
1003
974
        if(not add_environment(p, *e, false)){
1007
978
    }
1008
979
    
1009
980
    int pipefd[2];
 
981
#ifndef O_CLOEXEC
1010
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 */
1011
986
    if(ret == -1){
1012
987
      error(0, errno, "pipe");
1013
988
      exitstatus = EX_OSERR;
1014
 
      goto fallback;
1015
 
    }
 
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
1016
1002
    /* Ask OS to automatic close the pipe on exec */
1017
1003
    ret = set_cloexec_flag(pipefd[0]);
1018
1004
    if(ret < 0){
1019
1005
      error(0, errno, "set_cloexec_flag");
 
1006
      close(pipefd[0]);
 
1007
      close(pipefd[1]);
1020
1008
      exitstatus = EX_OSERR;
 
1009
      free(direntries[i]);
1021
1010
      goto fallback;
1022
1011
    }
1023
1012
    ret = set_cloexec_flag(pipefd[1]);
1024
1013
    if(ret < 0){
1025
1014
      error(0, errno, "set_cloexec_flag");
 
1015
      close(pipefd[0]);
 
1016
      close(pipefd[1]);
1026
1017
      exitstatus = EX_OSERR;
 
1018
      free(direntries[i]);
1027
1019
      goto fallback;
1028
1020
    }
 
1021
#endif  /* not O_CLOEXEC */
1029
1022
    /* Block SIGCHLD until process is safely in process list */
1030
1023
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK,
1031
1024
                                              &sigchld_action.sa_mask,
1033
1026
    if(ret < 0){
1034
1027
      error(0, errno, "sigprocmask");
1035
1028
      exitstatus = EX_OSERR;
 
1029
      free(direntries[i]);
1036
1030
      goto fallback;
1037
1031
    }
1038
1032
    /* Starting a new process to be watched */
1042
1036
    } while(pid == -1 and errno == EINTR);
1043
1037
    if(pid == -1){
1044
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]);
1045
1043
      exitstatus = EX_OSERR;
 
1044
      free(direntries[i]);
1046
1045
      goto fallback;
1047
1046
    }
1048
1047
    if(pid == 0){
1064
1063
        _exit(EX_OSERR);
1065
1064
      }
1066
1065
      
1067
 
      if(dirfd(dir) < 0){
1068
 
        /* If dir has no file descriptor, we could not set FD_CLOEXEC
1069
 
           above and must now close it manually here. */
1070
 
        closedir(dir);
1071
 
      }
1072
 
      if(execve(filename, p->argv,
 
1066
      if(fexecve(plugin_fd, p->argv,
1073
1067
                (p->environ[0] != NULL) ? p->environ : environ) < 0){
1074
 
        error(0, errno, "execve for %s", filename);
 
1068
        error(0, errno, "fexecve for %s/%s",
 
1069
              plugindir != NULL ? plugindir : PDIR,
 
1070
              direntries[i]->d_name);
1075
1071
        _exit(EX_OSERR);
1076
1072
      }
1077
1073
      /* no return */
1078
1074
    }
1079
1075
    /* Parent process */
1080
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1081
 
                                             pipe */
1082
 
    free(filename);
1083
 
    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);
1084
1079
    if(new_plugin == NULL){
1085
1080
      error(0, errno, "getplugin");
1086
1081
      ret = (int)(TEMP_FAILURE_RETRY
1090
1085
        error(0, errno, "sigprocmask");
1091
1086
      }
1092
1087
      exitstatus = EX_OSERR;
 
1088
      free(direntries[i]);
1093
1089
      goto fallback;
1094
1090
    }
 
1091
    free(direntries[i]);
1095
1092
    
1096
1093
    new_plugin->pid = pid;
1097
1094
    new_plugin->fd = pipefd[0];
1107
1104
      goto fallback;
1108
1105
    }
1109
1106
    
1110
 
#if defined (__GNUC__) and defined (__GLIBC__)
1111
 
#if not __GLIBC_PREREQ(2, 16)
1112
 
#pragma GCC diagnostic push
1113
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1114
 
#endif
1115
 
#endif
1116
 
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
1117
 
                                          -Wconversion in GNU libc
1118
 
                                          before 2.16 */
1119
 
#if defined (__GNUC__) and defined (__GLIBC__)
1120
 
#if not __GLIBC_PREREQ(2, 16)
1121
 
#pragma GCC diagnostic pop
1122
 
#endif
1123
 
#endif
 
1107
    FD_SET(new_plugin->fd, &rfds_all);
1124
1108
    
1125
1109
    if(maxfd < new_plugin->fd){
1126
1110
      maxfd = new_plugin->fd;
1127
1111
    }
1128
1112
  }
1129
1113
  
1130
 
  TEMP_FAILURE_RETRY(closedir(dir));
1131
 
  dir = NULL;
 
1114
  free(direntries);
 
1115
  direntries = NULL;
 
1116
  close(dir_fd);
 
1117
  dir_fd = -1;
1132
1118
  free_plugin(getplugin(NULL));
1133
1119
  
1134
1120
  for(plugin *p = plugin_list; p != NULL; p = p->next){
1180
1166
          }
1181
1167
          
1182
1168
          /* Remove the plugin */
1183
 
#if defined (__GNUC__) and defined (__GLIBC__)
1184
 
#if not __GLIBC_PREREQ(2, 16)
1185
 
#pragma GCC diagnostic push
1186
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1187
 
#endif
1188
 
#endif
1189
 
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
1190
 
                                          -Wconversion in GNU libc
1191
 
                                          before 2.16 */
1192
 
#if defined (__GNUC__) and defined (__GLIBC__)
1193
 
#if not __GLIBC_PREREQ(2, 16)
1194
 
#pragma GCC diagnostic pop
1195
 
#endif
1196
 
#endif
 
1169
          FD_CLR(proc->fd, &rfds_all);
1197
1170
          
1198
1171
          /* Block signal while modifying process_list */
1199
1172
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1239
1212
      }
1240
1213
      
1241
1214
      /* This process has not completed.  Does it have any output? */
1242
 
#if defined (__GNUC__) and defined (__GLIBC__)
1243
 
#if not __GLIBC_PREREQ(2, 16)
1244
 
#pragma GCC diagnostic push
1245
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1246
 
#endif
1247
 
#endif
1248
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1249
 
                                                         warning from
1250
 
                                                         -Wconversion
1251
 
                                                         in GNU libc
1252
 
                                                         before
1253
 
                                                         2.16 */
1254
 
#if defined (__GNUC__) and defined (__GLIBC__)
1255
 
#if not __GLIBC_PREREQ(2, 16)
1256
 
#pragma GCC diagnostic pop
1257
 
#endif
1258
 
#endif
 
1215
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1259
1216
        /* This process had nothing to say at this time */
1260
1217
        proc = proc->next;
1261
1218
        continue;
1328
1285
    free(custom_argv);
1329
1286
  }
1330
1287
  
1331
 
  if(dir != NULL){
1332
 
    closedir(dir);
 
1288
  free(direntries);
 
1289
  
 
1290
  if(dir_fd != -1){
 
1291
    close(dir_fd);
1333
1292
  }
1334
1293
  
1335
1294
  /* Kill the processes */
1355
1314
  free_plugin_list();
1356
1315
  
1357
1316
  free(plugindir);
 
1317
  free(pluginhelperdir);
1358
1318
  free(argfile);
1359
1319
  
1360
1320
  return exitstatus;