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

  • Committer: Teddy Hogeborn
  • Date: 2015-07-20 03:03:33 UTC
  • Revision ID: teddy@recompile.se-20150720030333-203m2aeblypcsfte
Bug fix for GnuTLS 3: be compatible with old 2048-bit DSA keys.

The mandos-keygen program in Mandos version 1.6.0 and older generated
2048-bit DSA keys, and when GnuTLS uses these it has trouble
connecting using the Mandos default priority string.  This was
previously fixed in Mandos 1.6.2, but the bug reappeared when using
GnuTLS 3, so the default priority string has to change again; this
time also the Mandos client has to change its default, so now the
server and the client should use the same default priority string:

SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA:+SIGN-DSA-SHA256

* mandos (main/server_defaults): Changed default priority string.
* mandos-options.xml (/section/para[id="priority_compat"]): Removed.
  (/section/para[id="priority"]): Changed default priority string.
* mandos.conf ([DEFAULT]/priority): - '' -
* mandos.conf.xml (OPTIONS/priority): Refer to the id "priority"
                                      instead of "priority_compat".
* mandos.xml (OPTIONS/--priority): - '' -
* plugins.d/mandos-client.c (main): Changed default priority string.

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-2014 Teddy Hogeborn
 
6
 * Copyright © 2008-2014 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
 
                                   execv(), 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 */
760
775
    goto fallback;
761
776
  }
762
777
  
 
778
  {
 
779
    char *pluginhelperenv;
 
780
    bool bret = true;
 
781
    ret = asprintf(&pluginhelperenv, "MANDOSPLUGINHELPERDIR=%s",
 
782
                   pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
783
    if(ret != -1){
 
784
      bret = add_environment(getplugin(NULL), pluginhelperenv, true);
 
785
    }
 
786
    if(ret == -1 or not bret){
 
787
      error(0, errno, "Failed to set MANDOSPLUGINHELPERDIR"
 
788
            " environment variable to \"%s\" for all plugins\n",
 
789
            pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
790
    }
 
791
    if(ret != -1){
 
792
      free(pluginhelperenv);
 
793
    }
 
794
  }
 
795
  
763
796
  if(debug){
764
797
    for(plugin *p = plugin_list; p != NULL; p=p->next){
765
798
      fprintf(stderr, "Plugin: %s has %d arguments\n",
779
812
       <http://bugs.debian.org/633582> */
780
813
    int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY);
781
814
    if(plugindir_fd == -1){
782
 
      error(0, errno, "open");
 
815
      if(errno != ENOENT){
 
816
        error(0, errno, "open(\"" PDIR "\")");
 
817
      }
783
818
    } else {
784
819
      ret = (int)TEMP_FAILURE_RETRY(fstat(plugindir_fd, &st));
785
820
      if(ret == -1){
792
827
          }
793
828
        }
794
829
      }
795
 
      TEMP_FAILURE_RETRY(close(plugindir_fd));
 
830
      close(plugindir_fd);
796
831
    }
797
832
  }
798
833
  
808
843
  
809
844
  /* Open plugin directory with close_on_exec flag */
810
845
  {
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
 
    }
 
846
    dir_fd = open(plugindir != NULL ? plugindir : PDIR, O_RDONLY |
 
847
#ifdef O_CLOEXEC
 
848
                  O_CLOEXEC
 
849
#else  /* not O_CLOEXEC */
 
850
                  0
 
851
#endif  /* not O_CLOEXEC */
 
852
                  );
829
853
    if(dir_fd == -1){
830
854
      error(0, errno, "Could not open plugin dir");
831
855
      exitstatus = EX_UNAVAILABLE;
837
861
    ret = set_cloexec_flag(dir_fd);
838
862
    if(ret < 0){
839
863
      error(0, errno, "set_cloexec_flag");
840
 
      TEMP_FAILURE_RETRY(close(dir_fd));
841
864
      exitstatus = EX_OSERR;
842
865
      goto fallback;
843
866
    }
844
867
#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;
 
868
  }
 
869
  
 
870
  int good_name(const struct dirent * const dirent){
 
871
    const char * const patterns[] = { ".*", "#*#", "*~", "*.dpkg-new",
 
872
                                      "*.dpkg-old", "*.dpkg-bak",
 
873
                                      "*.dpkg-divert", NULL };
 
874
#ifdef __GNUC__
 
875
#pragma GCC diagnostic push
 
876
#pragma GCC diagnostic ignored "-Wcast-qual"
 
877
#endif
 
878
    for(const char **pat = (const char **)patterns;
 
879
        *pat != NULL; pat++){
 
880
#ifdef __GNUC__
 
881
#pragma GCC diagnostic pop
 
882
#endif
 
883
      if(fnmatch(*pat, dirent->d_name, FNM_FILE_NAME | FNM_PERIOD)
 
884
         != FNM_NOMATCH){
 
885
        if(debug){
 
886
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
 
887
                    " matching pattern %s\n", dirent->d_name, *pat);
 
888
        }
 
889
        return 0;
 
890
      }
852
891
    }
 
892
    return 1;
 
893
  }
 
894
  
 
895
#ifdef __GLIBC__
 
896
#if __GLIBC_PREREQ(2, 15)
 
897
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
 
898
                             alphasort);
 
899
#else  /* not __GLIBC_PREREQ(2, 15) */
 
900
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
 
901
                           &direntries, good_name, alphasort);
 
902
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
903
#else   /* not __GLIBC__ */
 
904
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
 
905
                           &direntries, good_name, alphasort);
 
906
#endif  /* not __GLIBC__ */
 
907
  if(numplugins == -1){
 
908
    error(0, errno, "Could not scan plugin dir");
 
909
    direntries = NULL;
 
910
    exitstatus = EX_OSERR;
 
911
    goto fallback;
853
912
  }
854
913
  
855
914
  FD_ZERO(&rfds_all);
856
915
  
857
916
  /* 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");
 
917
  for(int i = 0; i < numplugins; i++){
 
918
    
 
919
    int plugin_fd = openat(dir_fd, direntries[i]->d_name, O_RDONLY);
 
920
    if(plugin_fd == -1){
 
921
      error(0, errno, "Could not open plugin");
 
922
      free(direntries[i]);
946
923
      continue;
947
924
    }
948
 
    
949
 
    ret = (int)TEMP_FAILURE_RETRY(stat(filename, &st));
 
925
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
950
926
    if(ret == -1){
951
927
      error(0, errno, "stat");
952
 
      free(filename);
 
928
      close(plugin_fd);
 
929
      free(direntries[i]);
953
930
      continue;
954
931
    }
955
932
    
956
933
    /* Ignore non-executable files */
957
934
    if(not S_ISREG(st.st_mode)
958
 
       or (TEMP_FAILURE_RETRY(access(filename, X_OK)) != 0)){
 
935
       or (TEMP_FAILURE_RETRY(faccessat(dir_fd, direntries[i]->d_name,
 
936
                                        X_OK, 0)) != 0)){
959
937
      if(debug){
960
 
        fprintf(stderr, "Ignoring plugin dir entry \"%s\""
961
 
                " with bad type or mode\n", filename);
 
938
        fprintf(stderr, "Ignoring plugin dir entry \"%s/%s\""
 
939
                " with bad type or mode\n",
 
940
                plugindir != NULL ? plugindir : PDIR,
 
941
                direntries[i]->d_name);
962
942
      }
963
 
      free(filename);
 
943
      close(plugin_fd);
 
944
      free(direntries[i]);
964
945
      continue;
965
946
    }
966
947
    
967
 
    plugin *p = getplugin(dirst->d_name);
 
948
    plugin *p = getplugin(direntries[i]->d_name);
968
949
    if(p == NULL){
969
950
      error(0, errno, "getplugin");
970
 
      free(filename);
 
951
      close(plugin_fd);
 
952
      free(direntries[i]);
971
953
      continue;
972
954
    }
973
955
    if(p->disabled){
974
956
      if(debug){
975
957
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
976
 
                dirst->d_name);
 
958
                direntries[i]->d_name);
977
959
      }
978
 
      free(filename);
 
960
      close(plugin_fd);
 
961
      free(direntries[i]);
979
962
      continue;
980
963
    }
981
964
    {
995
978
        }
996
979
      }
997
980
    }
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. */
 
981
    /* If this plugin has any environment variables, we need to
 
982
       duplicate the environment from this process, too. */
1001
983
    if(p->environ[0] != NULL){
1002
984
      for(char **e = environ; *e != NULL; e++){
1003
985
        if(not add_environment(p, *e, false)){
1007
989
    }
1008
990
    
1009
991
    int pipefd[2];
 
992
#ifndef O_CLOEXEC
1010
993
    ret = (int)TEMP_FAILURE_RETRY(pipe(pipefd));
 
994
#else  /* O_CLOEXEC */
 
995
    ret = (int)TEMP_FAILURE_RETRY(pipe2(pipefd, O_CLOEXEC));
 
996
#endif  /* O_CLOEXEC */
1011
997
    if(ret == -1){
1012
998
      error(0, errno, "pipe");
1013
999
      exitstatus = EX_OSERR;
1014
 
      goto fallback;
1015
 
    }
 
1000
      free(direntries[i]);
 
1001
      goto fallback;
 
1002
    }
 
1003
    if(pipefd[0] >= FD_SETSIZE){
 
1004
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
 
1005
              FD_SETSIZE);
 
1006
      close(pipefd[0]);
 
1007
      close(pipefd[1]);
 
1008
      exitstatus = EX_OSERR;
 
1009
      free(direntries[i]);
 
1010
      goto fallback;
 
1011
    }
 
1012
#ifndef O_CLOEXEC
1016
1013
    /* Ask OS to automatic close the pipe on exec */
1017
1014
    ret = set_cloexec_flag(pipefd[0]);
1018
1015
    if(ret < 0){
1019
1016
      error(0, errno, "set_cloexec_flag");
 
1017
      close(pipefd[0]);
 
1018
      close(pipefd[1]);
1020
1019
      exitstatus = EX_OSERR;
 
1020
      free(direntries[i]);
1021
1021
      goto fallback;
1022
1022
    }
1023
1023
    ret = set_cloexec_flag(pipefd[1]);
1024
1024
    if(ret < 0){
1025
1025
      error(0, errno, "set_cloexec_flag");
 
1026
      close(pipefd[0]);
 
1027
      close(pipefd[1]);
1026
1028
      exitstatus = EX_OSERR;
 
1029
      free(direntries[i]);
1027
1030
      goto fallback;
1028
1031
    }
 
1032
#endif  /* not O_CLOEXEC */
1029
1033
    /* Block SIGCHLD until process is safely in process list */
1030
1034
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK,
1031
1035
                                              &sigchld_action.sa_mask,
1033
1037
    if(ret < 0){
1034
1038
      error(0, errno, "sigprocmask");
1035
1039
      exitstatus = EX_OSERR;
 
1040
      free(direntries[i]);
1036
1041
      goto fallback;
1037
1042
    }
1038
1043
    /* Starting a new process to be watched */
1042
1047
    } while(pid == -1 and errno == EINTR);
1043
1048
    if(pid == -1){
1044
1049
      error(0, errno, "fork");
 
1050
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
 
1051
                                     &sigchld_action.sa_mask, NULL));
 
1052
      close(pipefd[0]);
 
1053
      close(pipefd[1]);
1045
1054
      exitstatus = EX_OSERR;
 
1055
      free(direntries[i]);
1046
1056
      goto fallback;
1047
1057
    }
1048
1058
    if(pid == 0){
1064
1074
        _exit(EX_OSERR);
1065
1075
      }
1066
1076
      
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(p->environ[0] == NULL){
1073
 
        if(execv(filename, p->argv) < 0){
1074
 
          error(0, errno, "execv for %s", filename);
1075
 
          _exit(EX_OSERR);
1076
 
        }
1077
 
      } else {
1078
 
        if(execve(filename, p->argv, p->environ) < 0){
1079
 
          error(0, errno, "execve for %s", filename);
1080
 
          _exit(EX_OSERR);
1081
 
        }
 
1077
      if(fexecve(plugin_fd, p->argv,
 
1078
                (p->environ[0] != NULL) ? p->environ : environ) < 0){
 
1079
        error(0, errno, "fexecve for %s/%s",
 
1080
              plugindir != NULL ? plugindir : PDIR,
 
1081
              direntries[i]->d_name);
 
1082
        _exit(EX_OSERR);
1082
1083
      }
1083
1084
      /* no return */
1084
1085
    }
1085
1086
    /* Parent process */
1086
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1087
 
                                             pipe */
1088
 
    free(filename);
1089
 
    plugin *new_plugin = getplugin(dirst->d_name);
 
1087
    close(pipefd[1]);           /* Close unused write end of pipe */
 
1088
    close(plugin_fd);
 
1089
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1090
1090
    if(new_plugin == NULL){
1091
1091
      error(0, errno, "getplugin");
1092
1092
      ret = (int)(TEMP_FAILURE_RETRY
1096
1096
        error(0, errno, "sigprocmask");
1097
1097
      }
1098
1098
      exitstatus = EX_OSERR;
 
1099
      free(direntries[i]);
1099
1100
      goto fallback;
1100
1101
    }
 
1102
    free(direntries[i]);
1101
1103
    
1102
1104
    new_plugin->pid = pid;
1103
1105
    new_plugin->fd = pipefd[0];
1133
1135
    }
1134
1136
  }
1135
1137
  
1136
 
  TEMP_FAILURE_RETRY(closedir(dir));
1137
 
  dir = NULL;
 
1138
  free(direntries);
 
1139
  direntries = NULL;
 
1140
  close(dir_fd);
 
1141
  dir_fd = -1;
1138
1142
  free_plugin(getplugin(NULL));
1139
1143
  
1140
1144
  for(plugin *p = plugin_list; p != NULL; p = p->next){
1334
1338
    free(custom_argv);
1335
1339
  }
1336
1340
  
1337
 
  if(dir != NULL){
1338
 
    closedir(dir);
 
1341
  free(direntries);
 
1342
  
 
1343
  if(dir_fd != -1){
 
1344
    close(dir_fd);
1339
1345
  }
1340
1346
  
1341
1347
  /* Kill the processes */
1361
1367
  free_plugin_list();
1362
1368
  
1363
1369
  free(plugindir);
 
1370
  free(pluginhelperdir);
1364
1371
  free(argfile);
1365
1372
  
1366
1373
  return exitstatus;