/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: 2011-12-31 20:07:11 UTC
  • mfrom: (535.1.9 wireless-network-hook)
  • Revision ID: teddy@recompile.se-20111231200711-6dli3r8drftem57r
Merge new wireless network hook.  Fix bridge network hook to use
hardware addresses instead of interface names.  Implement and document
new "CONNECT" environment variable for network hooks.

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-2011 Teddy Hogeborn
 
6
 * Copyright © 2008-2011 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
                                   asprintf(), O_CLOEXEC */
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, fclose() */
33
 
#include <sys/types.h>          /* DIR, fdopendir(), fstat(), struct
 
32
                                   stderr, STDOUT_FILENO */
 
33
#include <sys/types.h>          /* DIR, fdopendir(), stat(), struct
34
34
                                   stat, waitpid(), WIFEXITED(),
35
35
                                   WEXITSTATUS(), wait(), pid_t,
36
36
                                   uid_t, gid_t, getuid(), getgid(),
40
40
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
41
41
                                   WEXITSTATUS(), WTERMSIG(),
42
42
                                   WCOREDUMP() */
43
 
#include <sys/stat.h>           /* struct stat, fstat(), S_ISREG() */
 
43
#include <sys/stat.h>           /* struct stat, stat(), S_ISREG() */
44
44
#include <iso646.h>             /* and, or, not */
45
45
#include <dirent.h>             /* DIR, struct dirent, fdopendir(),
46
46
                                   readdir(), closedir(), dirfd() */
47
 
#include <unistd.h>             /* fcntl(), F_GETFD, F_SETFD,
48
 
                                   FD_CLOEXEC, write(), STDOUT_FILENO,
49
 
                                   struct stat, fstat(), close(),
50
 
                                   setgid(), setuid(), S_ISREG(),
51
 
                                   faccessat() pipe(), fork(),
52
 
                                   _exit(), dup2(), fexecve(), read()
53
 
                                */
 
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() */
54
54
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
55
 
                                   FD_CLOEXEC, openat() */
56
 
#include <string.h>             /* strsep, strlen(), strsignal(),
57
 
                                   strcmp(), strncmp() */
 
55
                                   FD_CLOEXEC */
 
56
#include <string.h>             /* strsep, strlen(), asprintf(),
 
57
                                   strsignal(), strcmp(), strncmp() */
58
58
#include <errno.h>              /* errno */
59
59
#include <argp.h>               /* struct argp_option, struct
60
60
                                   argp_state, struct argp,
72
72
                                   EX_CONFIG, EX_UNAVAILABLE, EX_OK */
73
73
#include <errno.h>              /* errno */
74
74
#include <error.h>              /* error() */
75
 
#include <fnmatch.h>            /* fnmatch() */
76
75
 
77
76
#define BUFFER_SIZE 256
78
77
 
106
105
 
107
106
/* Gets an existing plugin based on name,
108
107
   or if none is found, creates a new one */
109
 
__attribute__((warn_unused_result))
110
108
static plugin *getplugin(char *name){
111
109
  /* Check for existing plugin with that name */
112
110
  for(plugin *p = plugin_list; p != NULL; p = p->next){
173
171
}
174
172
 
175
173
/* Helper function for add_argument and add_environment */
176
 
__attribute__((nonnull, warn_unused_result))
 
174
__attribute__((nonnull))
177
175
static bool add_to_char_array(const char *new, char ***array,
178
176
                              int *len){
179
177
  /* Resize the pointed-to array to hold one more pointer */
180
 
  char **new_array = NULL;
181
178
  do {
182
 
    new_array = realloc(*array, sizeof(char *)
183
 
                        * (size_t) ((*len) + 2));
184
 
  } while(new_array == NULL and errno == EINTR);
 
179
    *array = realloc(*array, sizeof(char *)
 
180
                     * (size_t) ((*len) + 2));
 
181
  } while(*array == NULL and errno == EINTR);
185
182
  /* Malloc check */
186
 
  if(new_array == NULL){
 
183
  if(*array == NULL){
187
184
    return false;
188
185
  }
189
 
  *array = new_array;
190
186
  /* Make a copy of the new string */
191
187
  char *copy;
192
188
  do {
204
200
}
205
201
 
206
202
/* Add to a plugin's argument vector */
207
 
__attribute__((nonnull(2), warn_unused_result))
 
203
__attribute__((nonnull(2)))
208
204
static bool add_argument(plugin *p, const char *arg){
209
205
  if(p == NULL){
210
206
    return false;
213
209
}
214
210
 
215
211
/* Add to a plugin's environment */
216
 
__attribute__((nonnull(2), warn_unused_result))
 
212
__attribute__((nonnull(2)))
217
213
static bool add_environment(plugin *p, const char *def, bool replace){
218
214
  if(p == NULL){
219
215
    return false;
221
217
  /* namelen = length of name of environment variable */
222
218
  size_t namelen = (size_t)(strchrnul(def, '=') - def);
223
219
  /* Search for this environment variable */
224
 
  for(char **envdef = p->environ; *envdef != NULL; envdef++){
225
 
    if(strncmp(*envdef, def, namelen + 1) == 0){
 
220
  for(char **e = p->environ; *e != NULL; e++){
 
221
    if(strncmp(*e, def, namelen + 1) == 0){
226
222
      /* It already exists */
227
223
      if(replace){
228
 
        char *new_envdef;
 
224
        char *new;
229
225
        do {
230
 
          new_envdef = realloc(*envdef, strlen(def) + 1);
231
 
        } while(new_envdef == NULL and errno == EINTR);
232
 
        if(new_envdef == NULL){
 
226
          new = realloc(*e, strlen(def) + 1);
 
227
        } while(new == NULL and errno == EINTR);
 
228
        if(new == NULL){
233
229
          return false;
234
230
        }
235
 
        *envdef = new_envdef;
236
 
        strcpy(*envdef, def);
 
231
        *e = new;
 
232
        strcpy(*e, def);
237
233
      }
238
234
      return true;
239
235
    }
246
242
 * Descriptor Flags".
247
243
 | [[info:libc:Descriptor%20Flags][File Descriptor Flags]] |
248
244
 */
249
 
__attribute__((warn_unused_result))
250
245
static int set_cloexec_flag(int fd){
251
246
  int ret = (int)TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0));
252
247
  /* If reading the flags failed, return error indication now. */
294
289
}
295
290
 
296
291
/* Prints out a password to stdout */
297
 
__attribute__((nonnull, warn_unused_result))
 
292
__attribute__((nonnull))
298
293
static bool print_out_password(const char *buffer, size_t length){
299
294
  ssize_t ret;
300
295
  for(size_t written = 0; written < length; written += (size_t)ret){
348
343
  char *plugindir = NULL;
349
344
  char *argfile = NULL;
350
345
  FILE *conffp;
 
346
  size_t d_name_len;
351
347
  DIR *dir = NULL;
352
348
  struct dirent *dirst;
353
349
  struct stat st;
363
359
                                      .sa_flags = SA_NOCLDSTOP };
364
360
  char **custom_argv = NULL;
365
361
  int custom_argc = 0;
366
 
  int dir_fd;
367
362
  
368
363
  /* Establish a signal handler */
369
364
  sigemptyset(&sigchld_action.sa_mask);
440
435
            break;
441
436
          }
442
437
        }
443
 
        errno = 0;
444
438
      }
445
439
      break;
446
440
    case 'G':                   /* --global-env */
447
 
      if(add_environment(getplugin(NULL), arg, true)){
448
 
        errno = 0;
449
 
      }
 
441
      add_environment(getplugin(NULL), arg, true);
450
442
      break;
451
443
    case 'o':                   /* --options-for */
452
444
      {
469
461
            break;
470
462
          }
471
463
        }
472
 
        errno = 0;
473
464
      }
474
465
      break;
475
466
    case 'E':                   /* --env-for */
487
478
          errno = EINVAL;
488
479
          break;
489
480
        }
490
 
        if(add_environment(getplugin(arg), envdef, true)){
491
 
          errno = 0;
492
 
        }
 
481
        add_environment(getplugin(arg), envdef, true);
493
482
      }
494
483
      break;
495
484
    case 'd':                   /* --disable */
497
486
        plugin *p = getplugin(arg);
498
487
        if(p != NULL){
499
488
          p->disabled = true;
500
 
          errno = 0;
501
489
        }
502
490
      }
503
491
      break;
506
494
        plugin *p = getplugin(arg);
507
495
        if(p != NULL){
508
496
          p->disabled = false;
509
 
          errno = 0;
510
497
        }
511
498
      }
512
499
      break;
513
500
    case 128:                   /* --plugin-dir */
514
501
      free(plugindir);
515
502
      plugindir = strdup(arg);
516
 
      if(plugindir != NULL){
517
 
        errno = 0;
518
 
      }
519
503
      break;
520
504
    case 129:                   /* --config-file */
521
505
      /* This is already done by parse_opt_config_file() */
529
513
        break;
530
514
      }
531
515
      uid = (uid_t)tmp_id;
532
 
      errno = 0;
533
516
      break;
534
517
    case 131:                   /* --groupid */
535
518
      tmp_id = strtoimax(arg, &tmp, 10);
540
523
        break;
541
524
      }
542
525
      gid = (gid_t)tmp_id;
543
 
      errno = 0;
544
526
      break;
545
527
    case 132:                   /* --debug */
546
528
      debug = true;
594
576
    case 129:                   /* --config-file */
595
577
      free(argfile);
596
578
      argfile = strdup(arg);
597
 
      if(argfile != NULL){
598
 
        errno = 0;
599
 
      }
600
579
      break;
601
580
    case 130:                   /* --userid */
602
581
    case 131:                   /* --groupid */
685
664
        }
686
665
        
687
666
        custom_argc += 1;
688
 
        {
689
 
          char **new_argv = realloc(custom_argv, sizeof(char *)
690
 
                                    * ((unsigned int)
691
 
                                       custom_argc + 1));
692
 
          if(new_argv == NULL){
693
 
            error(0, errno, "realloc");
694
 
            exitstatus = EX_OSERR;
695
 
            free(new_arg);
696
 
            free(org_line);
697
 
            goto fallback;
698
 
          } else {
699
 
            custom_argv = new_argv;
700
 
          }
 
667
        custom_argv = realloc(custom_argv, sizeof(char *)
 
668
                              * ((unsigned int) custom_argc + 1));
 
669
        if(custom_argv == NULL){
 
670
          error(0, errno, "realloc");
 
671
          exitstatus = EX_OSERR;
 
672
          free(org_line);
 
673
          goto fallback;
701
674
        }
702
675
        custom_argv[custom_argc-1] = new_arg;
703
676
        custom_argv[custom_argc] = NULL;
780
753
       <http://bugs.debian.org/633582> */
781
754
    int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY);
782
755
    if(plugindir_fd == -1){
783
 
      if(errno != ENOENT){
784
 
        error(0, errno, "open(\"" PDIR "\")");
785
 
      }
 
756
      error(0, errno, "open");
786
757
    } else {
787
758
      ret = (int)TEMP_FAILURE_RETRY(fstat(plugindir_fd, &st));
788
759
      if(ret == -1){
800
771
  }
801
772
  
802
773
  /* Lower permissions */
803
 
  ret = setgid(gid);
 
774
  setgid(gid);
804
775
  if(ret == -1){
805
776
    error(0, errno, "setgid");
806
777
  }
811
782
  
812
783
  /* Open plugin directory with close_on_exec flag */
813
784
  {
814
 
    dir_fd = open(plugindir != NULL ? plugindir : PDIR, O_RDONLY |
815
 
#ifdef O_CLOEXEC
816
 
                  O_CLOEXEC
817
 
#else  /* not O_CLOEXEC */
818
 
                  0
819
 
#endif  /* not O_CLOEXEC */
820
 
                  );
 
785
    int dir_fd = -1;
 
786
    if(plugindir == NULL){
 
787
      dir_fd = open(PDIR, O_RDONLY |
 
788
#ifdef O_CLOEXEC
 
789
                    O_CLOEXEC
 
790
#else  /* not O_CLOEXEC */
 
791
                    0
 
792
#endif  /* not O_CLOEXEC */
 
793
                    );
 
794
    } else {
 
795
      dir_fd = open(plugindir, O_RDONLY |
 
796
#ifdef O_CLOEXEC
 
797
                    O_CLOEXEC
 
798
#else  /* not O_CLOEXEC */
 
799
                    0
 
800
#endif  /* not O_CLOEXEC */
 
801
                    );
 
802
    }
821
803
    if(dir_fd == -1){
822
804
      error(0, errno, "Could not open plugin dir");
823
805
      exitstatus = EX_UNAVAILABLE;
862
844
      break;
863
845
    }
864
846
    
 
847
    d_name_len = strlen(dirst->d_name);
 
848
    
865
849
    /* Ignore dotfiles, backup files and other junk */
866
850
    {
867
851
      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
 
      }
 
852
      
 
853
      const char const *bad_prefixes[] = { ".", "#", NULL };
 
854
      
 
855
      const char const *bad_suffixes[] = { "~", "#", ".dpkg-new",
 
856
                                           ".dpkg-old",
 
857
                                           ".dpkg-bak",
 
858
                                           ".dpkg-divert", NULL };
 
859
      for(const char **pre = bad_prefixes; *pre != NULL; pre++){
 
860
        size_t pre_len = strlen(*pre);
 
861
        if((d_name_len >= pre_len)
 
862
           and strncmp((dirst->d_name), *pre, pre_len) == 0){
 
863
          if(debug){
 
864
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
 
865
                    " with bad prefix %s\n", dirst->d_name, *pre);
 
866
          }
 
867
          bad_name = true;
 
868
          break;
 
869
        }
 
870
      }
 
871
      if(bad_name){
 
872
        continue;
 
873
      }
 
874
      for(const char **suf = bad_suffixes; *suf != NULL; suf++){
 
875
        size_t suf_len = strlen(*suf);
 
876
        if((d_name_len >= suf_len)
 
877
           and (strcmp((dirst->d_name) + d_name_len-suf_len, *suf)
 
878
                == 0)){
 
879
          if(debug){
 
880
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
 
881
                    " with bad suffix %s\n", dirst->d_name, *suf);
 
882
          }
 
883
          bad_name = true;
 
884
          break;
 
885
        }
 
886
      }
 
887
      
891
888
      if(bad_name){
892
889
        continue;
893
890
      }
894
891
    }
895
892
    
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
 
                            );
903
 
    if(plugin_fd == -1){
904
 
      error(0, errno, "Could not open plugin");
905
 
      continue;
 
893
    char *filename;
 
894
    if(plugindir == NULL){
 
895
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s",
 
896
                                             dirst->d_name));
 
897
    } else {
 
898
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s",
 
899
                                             plugindir,
 
900
                                             dirst->d_name));
906
901
    }
907
 
#ifndef O_CLOEXEC
908
 
  /* Set the FD_CLOEXEC flag on the plugin FD */
909
 
    ret = set_cloexec_flag(plugin_fd);
910
902
    if(ret < 0){
911
 
      error(0, errno, "set_cloexec_flag");
912
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
903
      error(0, errno, "asprintf");
913
904
      continue;
914
905
    }
915
 
#endif  /* O_CLOEXEC */
916
 
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
 
906
    
 
907
    ret = (int)TEMP_FAILURE_RETRY(stat(filename, &st));
917
908
    if(ret == -1){
918
909
      error(0, errno, "stat");
919
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
910
      free(filename);
920
911
      continue;
921
912
    }
922
913
    
923
914
    /* Ignore non-executable files */
924
915
    if(not S_ISREG(st.st_mode)
925
 
       or (TEMP_FAILURE_RETRY(faccessat(dir_fd, dirst->d_name, X_OK,
926
 
                                        0)) != 0)){
 
916
       or (TEMP_FAILURE_RETRY(access(filename, X_OK)) != 0)){
927
917
      if(debug){
928
 
        fprintf(stderr, "Ignoring plugin dir entry \"%s/%s\""
929
 
                " with bad type or mode\n",
930
 
                plugindir != NULL ? plugindir : PDIR, dirst->d_name);
 
918
        fprintf(stderr, "Ignoring plugin dir entry \"%s\""
 
919
                " with bad type or mode\n", filename);
931
920
      }
932
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
921
      free(filename);
933
922
      continue;
934
923
    }
935
924
    
936
925
    plugin *p = getplugin(dirst->d_name);
937
926
    if(p == NULL){
938
927
      error(0, errno, "getplugin");
939
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
928
      free(filename);
940
929
      continue;
941
930
    }
942
931
    if(p->disabled){
944
933
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
945
934
                dirst->d_name);
946
935
      }
947
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
936
      free(filename);
948
937
      continue;
949
938
    }
950
939
    {
964
953
        }
965
954
      }
966
955
    }
967
 
    /* If this plugin has any environment variables, we need to
968
 
       duplicate the environment from this process, too. */
 
956
    /* If this plugin has any environment variables, we will call
 
957
       using execve and need to duplicate the environment from this
 
958
       process, too. */
969
959
    if(p->environ[0] != NULL){
970
960
      for(char **e = environ; *e != NULL; e++){
971
961
        if(not add_environment(p, *e, false)){
1037
1027
           above and must now close it manually here. */
1038
1028
        closedir(dir);
1039
1029
      }
1040
 
      if(fexecve(plugin_fd, p->argv,
1041
 
                (p->environ[0] != NULL) ? p->environ : environ) < 0){
1042
 
        error(0, errno, "fexecve for %s/%s",
1043
 
              plugindir != NULL ? plugindir : PDIR, dirst->d_name);
1044
 
        _exit(EX_OSERR);
 
1030
      if(p->environ[0] == NULL){
 
1031
        if(execv(filename, p->argv) < 0){
 
1032
          error(0, errno, "execv for %s", filename);
 
1033
          _exit(EX_OSERR);
 
1034
        }
 
1035
      } else {
 
1036
        if(execve(filename, p->argv, p->environ) < 0){
 
1037
          error(0, errno, "execve for %s", filename);
 
1038
          _exit(EX_OSERR);
 
1039
        }
1045
1040
      }
1046
1041
      /* no return */
1047
1042
    }
1048
1043
    /* Parent process */
1049
1044
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1050
1045
                                             pipe */
1051
 
    TEMP_FAILURE_RETRY(close(plugin_fd));
 
1046
    free(filename);
1052
1047
    plugin *new_plugin = getplugin(dirst->d_name);
1053
1048
    if(new_plugin == NULL){
1054
1049
      error(0, errno, "getplugin");
1076
1071
      goto fallback;
1077
1072
    }
1078
1073
    
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
1074
    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
 
1075
                                          -Wconversion */
1093
1076
    
1094
1077
    if(maxfd < new_plugin->fd){
1095
1078
      maxfd = new_plugin->fd;
1149
1132
          }
1150
1133
          
1151
1134
          /* 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
1135
          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
 
1136
                                          -Wconversion */
1166
1137
          
1167
1138
          /* Block signal while modifying process_list */
1168
1139
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1208
1179
      }
1209
1180
      
1210
1181
      /* 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
1182
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1218
1183
                                                         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
 
1184
                                                         -Wconversion */
1228
1185
        /* This process had nothing to say at this time */
1229
1186
        proc = proc->next;
1230
1187
        continue;
1231
1188
      }
1232
1189
      /* Before reading, make the process' data buffer large enough */
1233
1190
      if(proc->buffer_length + BUFFER_SIZE > proc->buffer_size){
1234
 
        char *new_buffer = realloc(proc->buffer, proc->buffer_size
1235
 
                                   + (size_t) BUFFER_SIZE);
1236
 
        if(new_buffer == NULL){
 
1191
        proc->buffer = realloc(proc->buffer, proc->buffer_size
 
1192
                               + (size_t) BUFFER_SIZE);
 
1193
        if(proc->buffer == NULL){
1237
1194
          error(0, errno, "malloc");
1238
1195
          exitstatus = EX_OSERR;
1239
1196
          goto fallback;
1240
1197
        }
1241
 
        proc->buffer = new_buffer;
1242
1198
        proc->buffer_size += BUFFER_SIZE;
1243
1199
      }
1244
1200
      /* Read from the process */