/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-03-10 18:03:38 UTC
  • Revision ID: teddy@recompile.se-20150310180338-pcxw6r2qmw9k6br9
Add ":!RSA" to GnuTLS priority string, to disallow non-DHE kx.

If Mandos was somehow made to use a non-ephemeral Diffie-Hellman key
exchange algorithm in the TLS handshake, any saved network traffic
could then be decrypted later if the Mandos client key was obtained.
By default, Mandos uses ephemeral DH key exchanges which does not have
this problem, but a non-ephemeral key exchange algorithm was still
enabled by default.  The simplest solution is to simply turn that off,
which ensures that Mandos will always use ephemeral DH key exchanges.

There is a "PFS" priority string specifier, but we can't use it because:

1. Security-wise, it is a mix between "NORMAL" and "SECURE128" - it
   enables a lot more algorithms than "SECURE256".

2. It is only available since GnuTLS 3.2.4.

Thanks to Andreas Fischer <af@bantuX.org> for reporting this issue.

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-2021 Teddy Hogeborn
6
 
 * Copyright © 2008-2021 Björn Påhlsson
7
 
 * 
8
 
 * This file is part of Mandos.
9
 
 * 
10
 
 * Mandos is free software: you can redistribute it and/or modify it
11
 
 * under the terms of the GNU General Public License as published by
12
 
 * the Free Software Foundation, either version 3 of the License, or
13
 
 * (at your option) any later version.
14
 
 * 
15
 
 * Mandos is distributed in the hope that it will be useful, but
 
5
 * Copyright © 2008-2014 Teddy Hogeborn
 
6
 * Copyright © 2008-2014 Björn Påhlsson
 
7
 * 
 
8
 * This program is free software: you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License as
 
10
 * published by the Free Software Foundation, either version 3 of the
 
11
 * License, or (at your option) any later version.
 
12
 * 
 
13
 * This program is distributed in the hope that it will be useful, but
16
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
17
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
16
 * General Public License for more details.
19
17
 * 
20
18
 * You should have received a copy of the GNU General Public License
21
 
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
 
19
 * along with this program.  If not, see
 
20
 * <http://www.gnu.org/licenses/>.
22
21
 * 
23
22
 * Contact the authors at <mandos@recompile.se>.
24
23
 */
25
24
 
26
 
#define _GNU_SOURCE             /* strchrnul(), TEMP_FAILURE_RETRY(),
27
 
                                   getline(), asprintf(), O_CLOEXEC,
28
 
                                   scandirat(), pipe2() */
29
 
#include <argp.h>               /* argp_program_version,
30
 
                                   argp_program_bug_address,
31
 
                                   struct argp_option,
32
 
                                   struct argp_state, argp_error(),
33
 
                                   ARGP_NO_EXIT, argp_state_help,
34
 
                                   ARGP_HELP_STD_HELP,
35
 
                                   ARGP_HELP_USAGE, ARGP_HELP_EXIT_OK,
36
 
                                   ARGP_KEY_ARG, ARGP_ERR_UNKNOWN,
37
 
                                   struct argp, argp_parse(),
38
 
                                   ARGP_IN_ORDER, ARGP_NO_HELP */
39
 
#include <stdbool.h>            /* bool, false, true */
40
 
#include <sys/types.h>          /* pid_t, sig_atomic_t, uid_t, gid_t,
41
 
                                   getuid(), setgid(), setuid() */
 
25
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), getline(),
 
26
                                   O_CLOEXEC, pipe2() */
42
27
#include <stddef.h>             /* size_t, NULL */
43
 
#include <iso646.h>             /* or, and, not */
44
 
#include <string.h>             /* strcmp(), strdup(), strchrnul(),
45
 
                                   strncmp(), strlen(), strcpy(),
46
 
                                   strsep(), strchr(), strsignal() */
47
 
#include <stdlib.h>             /* malloc(), free(), reallocarray(),
48
 
                                   realloc(), EXIT_SUCCESS */
49
 
#include <errno.h>              /* errno, EINTR, ENOMEM, ECHILD,
50
 
                                   error_t, EINVAL, EMFILE, ENFILE,
51
 
                                   ENOENT, ESRCH */
52
 
#include <stdint.h>             /* SIZE_MAX */
53
 
#define _GNU_SOURCE             /* strchrnul(), TEMP_FAILURE_RETRY(),
54
 
                                   getline(), asprintf(), O_CLOEXEC,
55
 
                                   scandirat(), pipe2() */
56
 
#include <unistd.h>             /* TEMP_FAILURE_RETRY(), ssize_t,
57
 
                                   write(), STDOUT_FILENO, uid_t,
58
 
                                   gid_t, getuid(), fchown(), close(),
59
 
                                   symlink(), setgid(), setuid(),
60
 
                                   faccessat(), X_OK, pipe(), pipe2(),
61
 
                                   fork(), _exit(), dup2(), fexecve(),
62
 
                                   read(), getpass() */
 
28
#include <stdlib.h>             /* malloc(), exit(), EXIT_SUCCESS,
 
29
                                   realloc() */
 
30
#include <stdbool.h>            /* bool, true, false */
 
31
#include <stdio.h>              /* fileno(), fprintf(),
 
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() */
 
37
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
 
38
                                   FD_SET(), FD_ISSET(), FD_CLR */
 
39
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
 
40
                                   WEXITSTATUS(), WTERMSIG(),
 
41
                                   WCOREDUMP() */
 
42
#include <sys/stat.h>           /* struct stat, fstat(), S_ISREG() */
 
43
#include <iso646.h>             /* and, or, not */
 
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
                                */
63
52
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
64
 
                                   FD_CLOEXEC, open(), O_RDONLY,
65
 
                                   O_CLOEXEC, openat() */
66
 
#include <sys/wait.h>           /* waitpid(), WNOHANG, WIFEXITED(),
67
 
                                   WEXITSTATUS(), WIFSIGNALED(),
68
 
                                   WTERMSIG(), wait() */
69
 
#include <error.h>              /* error() */
70
 
#include <stdio.h>              /* FILE, fprintf(), fopen(),
71
 
                                   getline(), fclose(), EOF,
72
 
                                   asprintf(), stderr */
73
 
#include <dirent.h>             /* struct dirent, scandirat(),
74
 
                                   alphasort() */
75
 
#include <sys/stat.h>           /* struct stat, fstat(), S_ISDIR(),
76
 
                                   lstat(), S_ISREG() */
77
 
#include <sys/select.h>         /* fd_set, FD_ZERO(), FD_SETSIZE,
78
 
                                   FD_SET(), select(), FD_CLR(),
79
 
                                   FD_ISSET() */
80
 
#include <signal.h>             /* struct sigaction, SA_NOCLDSTOP,
81
 
                                   sigemptyset(), sigaddset(),
82
 
                                   SIGCHLD, sigprocmask(), SIG_BLOCK,
83
 
                                   SIG_UNBLOCK, kill(), SIGTERM */
 
53
                                   FD_CLOEXEC, openat(), scandirat(),
 
54
                                   pipe2() */
 
55
#include <string.h>             /* strsep, strlen(), strsignal(),
 
56
                                   strcmp(), strncmp() */
 
57
#include <errno.h>              /* errno */
 
58
#include <argp.h>               /* struct argp_option, struct
 
59
                                   argp_state, struct argp,
 
60
                                   argp_parse(), ARGP_ERR_UNKNOWN,
 
61
                                   ARGP_KEY_END, ARGP_KEY_ARG,
 
62
                                   error_t */
 
63
#include <signal.h>             /* struct sigaction, sigemptyset(),
 
64
                                   sigaddset(), sigaction(),
 
65
                                   sigprocmask(), SIG_BLOCK, SIGCHLD,
 
66
                                   SIG_UNBLOCK, kill(), sig_atomic_t
 
67
                                */
 
68
#include <errno.h>              /* errno, EBADF */
 
69
#include <inttypes.h>           /* intmax_t, PRIdMAX, strtoimax() */
84
70
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_IOERR,
85
71
                                   EX_CONFIG, EX_UNAVAILABLE, EX_OK */
86
 
#include <inttypes.h>           /* intmax_t, strtoimax(), PRIdMAX */
87
 
#include <fnmatch.h>            /* fnmatch(), FNM_FILE_NAME,
88
 
                                   FNM_PERIOD, FNM_NOMATCH */
 
72
#include <errno.h>              /* errno */
 
73
#include <error.h>              /* error() */
 
74
#include <fnmatch.h>            /* fnmatch() */
89
75
 
90
76
#define BUFFER_SIZE 256
91
77
 
92
78
#define PDIR "/lib/mandos/plugins.d"
93
 
#define PHDIR "/lib/mandos/plugin-helpers"
94
79
#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
95
80
 
96
81
const char *argp_program_version = "plugin-runner " VERSION;
193
178
  /* Resize the pointed-to array to hold one more pointer */
194
179
  char **new_array = NULL;
195
180
  do {
196
 
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
197
 
    new_array = reallocarray(*array, (size_t)((*len) + 2),
198
 
                             sizeof(char *));
199
 
#else
200
 
    if(((size_t)((*len) + 2)) > (SIZE_MAX / sizeof(char *))){
201
 
      /* overflow */
202
 
      new_array = NULL;
203
 
      errno = ENOMEM;
204
 
    } else {
205
 
      new_array = realloc(*array, (size_t)((*len) + 2)
206
 
                          * sizeof(char *));
207
 
    }
208
 
#endif
 
181
    new_array = realloc(*array, sizeof(char *)
 
182
                        * (size_t) ((*len) + 2));
209
183
  } while(new_array == NULL and errno == EINTR);
210
184
  /* Malloc check */
211
185
  if(new_array == NULL){
338
312
__attribute__((nonnull))
339
313
static void free_plugin(plugin *plugin_node){
340
314
  
341
 
  for(char **arg = (plugin_node->argv)+1; *arg != NULL; arg++){
 
315
  for(char **arg = plugin_node->argv; *arg != NULL; arg++){
342
316
    free(*arg);
343
317
  }
344
 
  free(plugin_node->name);
345
318
  free(plugin_node->argv);
346
319
  for(char **env = plugin_node->environ; *env != NULL; env++){
347
320
    free(*env);
374
347
 
375
348
int main(int argc, char *argv[]){
376
349
  char *plugindir = NULL;
377
 
  char *pluginhelperdir = NULL;
378
350
  char *argfile = NULL;
379
351
  FILE *conffp;
380
352
  struct dirent **direntries = NULL;
442
414
      .doc = "Group ID the plugins will run as", .group = 3 },
443
415
    { .name = "debug", .key = 132,
444
416
      .doc = "Debug mode", .group = 4 },
445
 
    { .name = "plugin-helper-dir", .key = 133,
446
 
      .arg = "DIRECTORY",
447
 
      .doc = "Specify a different plugin helper directory",
448
 
      .group = 2 },
449
417
    /*
450
418
     * These reproduce what we would get without ARGP_NO_HELP
451
419
     */
577
545
    case 132:                   /* --debug */
578
546
      debug = true;
579
547
      break;
580
 
    case 133:                   /* --plugin-helper-dir */
581
 
      free(pluginhelperdir);
582
 
      pluginhelperdir = strdup(arg);
583
 
      if(pluginhelperdir != NULL){
584
 
        errno = 0;
585
 
      }
586
 
      break;
587
548
      /*
588
549
       * These reproduce what we would get without ARGP_NO_HELP
589
550
       */
590
551
    case '?':                   /* --help */
591
552
      state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
592
553
      argp_state_help(state, state->out_stream, ARGP_HELP_STD_HELP);
593
 
      __builtin_unreachable();
594
554
    case -3:                    /* --usage */
595
555
      state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
596
556
      argp_state_help(state, state->out_stream,
597
557
                      ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
598
 
      __builtin_unreachable();
599
558
    case 'V':                   /* --version */
600
559
      fprintf(state->out_stream, "%s\n", argp_program_version);
601
560
      exit(EXIT_SUCCESS);
611
570
      if(arg[0] == '\0'){
612
571
        break;
613
572
      }
614
 
#if __GNUC__ >= 7
615
 
      __attribute__((fallthrough));
616
 
#else
617
 
          /* FALLTHROUGH */
618
 
#endif
619
573
    default:
620
574
      return ARGP_ERR_UNKNOWN;
621
575
    }
647
601
    case 130:                   /* --userid */
648
602
    case 131:                   /* --groupid */
649
603
    case 132:                   /* --debug */
650
 
    case 133:                   /* --plugin-helper-dir */
651
604
    case '?':                   /* --help */
652
605
    case -3:                    /* --usage */
653
606
    case 'V':                   /* --version */
733
686
        
734
687
        custom_argc += 1;
735
688
        {
736
 
#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 26)
737
 
          char **new_argv = reallocarray(custom_argv, (size_t)custom_argc + 1,
738
 
                                         sizeof(char *));
739
 
#else
740
 
          char **new_argv = NULL;
741
 
          if(((size_t)custom_argc + 1) > (SIZE_MAX / sizeof(char *))){
742
 
            /* overflow */
743
 
            errno = ENOMEM;
744
 
          } else {
745
 
            new_argv = realloc(custom_argv, ((size_t)custom_argc + 1)
746
 
                               * sizeof(char *));
747
 
          }
748
 
#endif
 
689
          char **new_argv = realloc(custom_argv, sizeof(char *)
 
690
                                    * ((unsigned int)
 
691
                                       custom_argc + 1));
749
692
          if(new_argv == NULL){
750
 
            error(0, errno, "reallocarray");
 
693
            error(0, errno, "realloc");
751
694
            exitstatus = EX_OSERR;
752
695
            free(new_arg);
753
696
            free(org_line);
818
761
    goto fallback;
819
762
  }
820
763
  
821
 
  {
822
 
    char *pluginhelperenv;
823
 
    bool bret = true;
824
 
    ret = asprintf(&pluginhelperenv, "MANDOSPLUGINHELPERDIR=%s",
825
 
                   pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
826
 
    if(ret != -1){
827
 
      bret = add_environment(getplugin(NULL), pluginhelperenv, true);
828
 
    }
829
 
    if(ret == -1 or not bret){
830
 
      error(0, errno, "Failed to set MANDOSPLUGINHELPERDIR"
831
 
            " environment variable to \"%s\" for all plugins\n",
832
 
            pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
833
 
    }
834
 
    if(ret != -1){
835
 
      free(pluginhelperenv);
836
 
    }
837
 
  }
838
 
  
839
764
  if(debug){
840
 
    for(plugin *p = plugin_list; p != NULL; p = p->next){
 
765
    for(plugin *p = plugin_list; p != NULL; p=p->next){
841
766
      fprintf(stderr, "Plugin: %s has %d arguments\n",
842
767
              p->name ? p->name : "Global", p->argc - 1);
843
768
      for(char **a = p->argv; *a != NULL; a++){
852
777
  
853
778
  if(getuid() == 0){
854
779
    /* Work around Debian bug #633582:
855
 
       <https://bugs.debian.org/633582> */
 
780
       <http://bugs.debian.org/633582> */
856
781
    int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY);
857
782
    if(plugindir_fd == -1){
858
783
      if(errno != ENOENT){
870
795
          }
871
796
        }
872
797
      }
873
 
      close(plugindir_fd);
874
 
    }
875
 
 
876
 
    /* Work around Debian bug #981302
877
 
       <https://bugs.debian.org/981302> */
878
 
    if(lstat("/dev/fd", &st) != 0 and errno == ENOENT){
879
 
      ret = symlink("/proc/self/fd", "/dev/fd");
880
 
      if(ret == -1){
881
 
        error(0, errno, "Failed to create /dev/fd symlink");
882
 
      }
 
798
      TEMP_FAILURE_RETRY(close(plugindir_fd));
883
799
    }
884
800
  }
885
801
  
944
860
    return 1;
945
861
  }
946
862
  
 
863
#ifdef __GLIBC__
 
864
#if __GLIBC_PREREQ(2, 15)
947
865
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
948
866
                             alphasort);
 
867
#else  /* not __GLIBC_PREREQ(2, 15) */
 
868
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
 
869
                           &direntries, good_name, alphasort);
 
870
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
871
#else   /* not __GLIBC__ */
 
872
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
 
873
                           &direntries, good_name, alphasort);
 
874
#endif  /* not __GLIBC__ */
949
875
  if(numplugins == -1){
950
876
    error(0, errno, "Could not scan plugin dir");
951
877
    direntries = NULL;
967
893
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
968
894
    if(ret == -1){
969
895
      error(0, errno, "stat");
970
 
      close(plugin_fd);
 
896
      TEMP_FAILURE_RETRY(close(plugin_fd));
971
897
      free(direntries[i]);
972
898
      continue;
973
899
    }
982
908
                plugindir != NULL ? plugindir : PDIR,
983
909
                direntries[i]->d_name);
984
910
      }
985
 
      close(plugin_fd);
 
911
      TEMP_FAILURE_RETRY(close(plugin_fd));
986
912
      free(direntries[i]);
987
913
      continue;
988
914
    }
990
916
    plugin *p = getplugin(direntries[i]->d_name);
991
917
    if(p == NULL){
992
918
      error(0, errno, "getplugin");
993
 
      close(plugin_fd);
 
919
      TEMP_FAILURE_RETRY(close(plugin_fd));
994
920
      free(direntries[i]);
995
921
      continue;
996
922
    }
999
925
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
1000
926
                direntries[i]->d_name);
1001
927
      }
1002
 
      close(plugin_fd);
 
928
      TEMP_FAILURE_RETRY(close(plugin_fd));
1003
929
      free(direntries[i]);
1004
930
      continue;
1005
931
    }
1045
971
    if(pipefd[0] >= FD_SETSIZE){
1046
972
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
1047
973
              FD_SETSIZE);
1048
 
      close(pipefd[0]);
1049
 
      close(pipefd[1]);
 
974
      TEMP_FAILURE_RETRY(close(pipefd[0]));
 
975
      TEMP_FAILURE_RETRY(close(pipefd[1]));
1050
976
      exitstatus = EX_OSERR;
1051
977
      free(direntries[i]);
1052
978
      goto fallback;
1056
982
    ret = set_cloexec_flag(pipefd[0]);
1057
983
    if(ret < 0){
1058
984
      error(0, errno, "set_cloexec_flag");
1059
 
      close(pipefd[0]);
1060
 
      close(pipefd[1]);
 
985
      TEMP_FAILURE_RETRY(close(pipefd[0]));
 
986
      TEMP_FAILURE_RETRY(close(pipefd[1]));
1061
987
      exitstatus = EX_OSERR;
1062
988
      free(direntries[i]);
1063
989
      goto fallback;
1065
991
    ret = set_cloexec_flag(pipefd[1]);
1066
992
    if(ret < 0){
1067
993
      error(0, errno, "set_cloexec_flag");
1068
 
      close(pipefd[0]);
1069
 
      close(pipefd[1]);
 
994
      TEMP_FAILURE_RETRY(close(pipefd[0]));
 
995
      TEMP_FAILURE_RETRY(close(pipefd[1]));
1070
996
      exitstatus = EX_OSERR;
1071
997
      free(direntries[i]);
1072
998
      goto fallback;
1091
1017
      error(0, errno, "fork");
1092
1018
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1093
1019
                                     &sigchld_action.sa_mask, NULL));
1094
 
      close(pipefd[0]);
1095
 
      close(pipefd[1]);
 
1020
      TEMP_FAILURE_RETRY(close(pipefd[0]));
 
1021
      TEMP_FAILURE_RETRY(close(pipefd[1]));
1096
1022
      exitstatus = EX_OSERR;
1097
1023
      free(direntries[i]);
1098
1024
      goto fallback;
1126
1052
      /* no return */
1127
1053
    }
1128
1054
    /* Parent process */
1129
 
    close(pipefd[1]);           /* Close unused write end of pipe */
1130
 
    close(plugin_fd);
 
1055
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
 
1056
                                             pipe */
 
1057
    TEMP_FAILURE_RETRY(close(plugin_fd));
1131
1058
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1132
1059
    if(new_plugin == NULL){
1133
1060
      error(0, errno, "getplugin");
1145
1072
    
1146
1073
    new_plugin->pid = pid;
1147
1074
    new_plugin->fd = pipefd[0];
1148
 
 
1149
 
    if(debug){
1150
 
      fprintf(stderr, "Plugin %s started (PID %" PRIdMAX ")\n",
1151
 
              new_plugin->name, (intmax_t) (new_plugin->pid));
1152
 
    }
1153
 
 
 
1075
    
1154
1076
    /* Unblock SIGCHLD so signal handler can be run if this process
1155
1077
       has already completed */
1156
1078
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1162
1084
      goto fallback;
1163
1085
    }
1164
1086
    
1165
 
    FD_SET(new_plugin->fd, &rfds_all);
 
1087
#if defined (__GNUC__) and defined (__GLIBC__)
 
1088
#if not __GLIBC_PREREQ(2, 16)
 
1089
#pragma GCC diagnostic push
 
1090
#pragma GCC diagnostic ignored "-Wsign-conversion"
 
1091
#endif
 
1092
#endif
 
1093
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
 
1094
                                          -Wconversion in GNU libc
 
1095
                                          before 2.16 */
 
1096
#if defined (__GNUC__) and defined (__GLIBC__)
 
1097
#if not __GLIBC_PREREQ(2, 16)
 
1098
#pragma GCC diagnostic pop
 
1099
#endif
 
1100
#endif
1166
1101
    
1167
1102
    if(maxfd < new_plugin->fd){
1168
1103
      maxfd = new_plugin->fd;
1171
1106
  
1172
1107
  free(direntries);
1173
1108
  direntries = NULL;
1174
 
  close(dir_fd);
 
1109
  TEMP_FAILURE_RETRY(close(dir_fd));
1175
1110
  dir_fd = -1;
1176
1111
  free_plugin(getplugin(NULL));
1177
1112
  
1217
1152
                      (intmax_t) (proc->pid),
1218
1153
                      WTERMSIG(proc->status),
1219
1154
                      strsignal(WTERMSIG(proc->status)));
 
1155
            } else if(WCOREDUMP(proc->status)){
 
1156
              fprintf(stderr, "Plugin %s [%" PRIdMAX "] dumped"
 
1157
                      " core\n", proc->name, (intmax_t) (proc->pid));
1220
1158
            }
1221
1159
          }
1222
1160
          
1223
1161
          /* Remove the plugin */
1224
 
          FD_CLR(proc->fd, &rfds_all);
 
1162
#if defined (__GNUC__) and defined (__GLIBC__)
 
1163
#if not __GLIBC_PREREQ(2, 16)
 
1164
#pragma GCC diagnostic push
 
1165
#pragma GCC diagnostic ignored "-Wsign-conversion"
 
1166
#endif
 
1167
#endif
 
1168
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
 
1169
                                          -Wconversion in GNU libc
 
1170
                                          before 2.16 */
 
1171
#if defined (__GNUC__) and defined (__GLIBC__)
 
1172
#if not __GLIBC_PREREQ(2, 16)
 
1173
#pragma GCC diagnostic pop
 
1174
#endif
 
1175
#endif
1225
1176
          
1226
1177
          /* Block signal while modifying process_list */
1227
1178
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1267
1218
      }
1268
1219
      
1269
1220
      /* This process has not completed.  Does it have any output? */
1270
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
 
1221
#if defined (__GNUC__) and defined (__GLIBC__)
 
1222
#if not __GLIBC_PREREQ(2, 16)
 
1223
#pragma GCC diagnostic push
 
1224
#pragma GCC diagnostic ignored "-Wsign-conversion"
 
1225
#endif
 
1226
#endif
 
1227
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
 
1228
                                                         warning from
 
1229
                                                         -Wconversion
 
1230
                                                         in GNU libc
 
1231
                                                         before
 
1232
                                                         2.16 */
 
1233
#if defined (__GNUC__) and defined (__GLIBC__)
 
1234
#if not __GLIBC_PREREQ(2, 16)
 
1235
#pragma GCC diagnostic pop
 
1236
#endif
 
1237
#endif
1271
1238
        /* This process had nothing to say at this time */
1272
1239
        proc = proc->next;
1273
1240
        continue;
1343
1310
  free(direntries);
1344
1311
  
1345
1312
  if(dir_fd != -1){
1346
 
    close(dir_fd);
 
1313
    TEMP_FAILURE_RETRY(close(dir_fd));
1347
1314
  }
1348
1315
  
1349
1316
  /* Kill the processes */
1369
1336
  free_plugin_list();
1370
1337
  
1371
1338
  free(plugindir);
1372
 
  free(pluginhelperdir);
1373
1339
  free(argfile);
1374
1340
  
1375
1341
  return exitstatus;