/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: 2016-06-03 17:27:03 UTC
  • Revision ID: teddy@recompile.se-20160603172703-mc6tjor6rhq4xy74
mandos: Bug fix: Do multiprocessing cleanup correctly on exit

* mandos (main): Save module "multiprocessing" and open file "wnull"
                 as scope variables accessible by function cleanup(),
                 since the module and global variable may not be
                 accessible when the cleanup() function is run as
                 scheduled by atexit().

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Mandos plugin runner - Run Mandos plugins
4
4
 *
5
 
 * Copyright © 2008-2014 Teddy Hogeborn
6
 
 * Copyright © 2008-2014 Björn Påhlsson
 
5
 * Copyright © 2008-2016 Teddy Hogeborn
 
6
 * Copyright © 2008-2016 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
37
37
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
38
38
                                   FD_SET(), FD_ISSET(), FD_CLR */
39
39
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
40
 
                                   WEXITSTATUS(), WTERMSIG(),
41
 
                                   WCOREDUMP() */
 
40
                                   WEXITSTATUS(), WTERMSIG() */
42
41
#include <sys/stat.h>           /* struct stat, fstat(), S_ISREG() */
43
42
#include <iso646.h>             /* and, or, not */
44
43
#include <dirent.h>             /* struct dirent, scandirat() */
76
75
#define BUFFER_SIZE 256
77
76
 
78
77
#define PDIR "/lib/mandos/plugins.d"
 
78
#define PHDIR "/lib/mandos/plugin-helpers"
79
79
#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
80
80
 
81
81
const char *argp_program_version = "plugin-runner " VERSION;
347
347
 
348
348
int main(int argc, char *argv[]){
349
349
  char *plugindir = NULL;
 
350
  char *pluginhelperdir = NULL;
350
351
  char *argfile = NULL;
351
352
  FILE *conffp;
352
353
  struct dirent **direntries = NULL;
414
415
      .doc = "Group ID the plugins will run as", .group = 3 },
415
416
    { .name = "debug", .key = 132,
416
417
      .doc = "Debug mode", .group = 4 },
 
418
    { .name = "plugin-helper-dir", .key = 133,
 
419
      .arg = "DIRECTORY",
 
420
      .doc = "Specify a different plugin helper directory",
 
421
      .group = 2 },
417
422
    /*
418
423
     * These reproduce what we would get without ARGP_NO_HELP
419
424
     */
545
550
    case 132:                   /* --debug */
546
551
      debug = true;
547
552
      break;
 
553
    case 133:                   /* --plugin-helper-dir */
 
554
      free(pluginhelperdir);
 
555
      pluginhelperdir = strdup(arg);
 
556
      if(pluginhelperdir != NULL){
 
557
        errno = 0;
 
558
      }
 
559
      break;
548
560
      /*
549
561
       * These reproduce what we would get without ARGP_NO_HELP
550
562
       */
601
613
    case 130:                   /* --userid */
602
614
    case 131:                   /* --groupid */
603
615
    case 132:                   /* --debug */
 
616
    case 133:                   /* --plugin-helper-dir */
604
617
    case '?':                   /* --help */
605
618
    case -3:                    /* --usage */
606
619
    case 'V':                   /* --version */
687
700
        custom_argc += 1;
688
701
        {
689
702
          char **new_argv = realloc(custom_argv, sizeof(char *)
690
 
                                    * ((unsigned int)
691
 
                                       custom_argc + 1));
 
703
                                    * ((size_t)custom_argc + 1));
692
704
          if(new_argv == NULL){
693
705
            error(0, errno, "realloc");
694
706
            exitstatus = EX_OSERR;
761
773
    goto fallback;
762
774
  }
763
775
  
 
776
  {
 
777
    char *pluginhelperenv;
 
778
    bool bret = true;
 
779
    ret = asprintf(&pluginhelperenv, "MANDOSPLUGINHELPERDIR=%s",
 
780
                   pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
781
    if(ret != -1){
 
782
      bret = add_environment(getplugin(NULL), pluginhelperenv, true);
 
783
    }
 
784
    if(ret == -1 or not bret){
 
785
      error(0, errno, "Failed to set MANDOSPLUGINHELPERDIR"
 
786
            " environment variable to \"%s\" for all plugins\n",
 
787
            pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
788
    }
 
789
    if(ret != -1){
 
790
      free(pluginhelperenv);
 
791
    }
 
792
  }
 
793
  
764
794
  if(debug){
765
795
    for(plugin *p = plugin_list; p != NULL; p=p->next){
766
796
      fprintf(stderr, "Plugin: %s has %d arguments\n",
795
825
          }
796
826
        }
797
827
      }
798
 
      TEMP_FAILURE_RETRY(close(plugindir_fd));
 
828
      close(plugindir_fd);
799
829
    }
800
830
  }
801
831
  
860
890
    return 1;
861
891
  }
862
892
  
863
 
#ifdef __GLIBC__
864
 
#if __GLIBC_PREREQ(2, 15)
865
893
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
866
894
                             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__ */
875
895
  if(numplugins == -1){
876
896
    error(0, errno, "Could not scan plugin dir");
877
897
    direntries = NULL;
893
913
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
894
914
    if(ret == -1){
895
915
      error(0, errno, "stat");
896
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
916
      close(plugin_fd);
897
917
      free(direntries[i]);
898
918
      continue;
899
919
    }
908
928
                plugindir != NULL ? plugindir : PDIR,
909
929
                direntries[i]->d_name);
910
930
      }
911
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
931
      close(plugin_fd);
912
932
      free(direntries[i]);
913
933
      continue;
914
934
    }
916
936
    plugin *p = getplugin(direntries[i]->d_name);
917
937
    if(p == NULL){
918
938
      error(0, errno, "getplugin");
919
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
939
      close(plugin_fd);
920
940
      free(direntries[i]);
921
941
      continue;
922
942
    }
925
945
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
926
946
                direntries[i]->d_name);
927
947
      }
928
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
948
      close(plugin_fd);
929
949
      free(direntries[i]);
930
950
      continue;
931
951
    }
971
991
    if(pipefd[0] >= FD_SETSIZE){
972
992
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
973
993
              FD_SETSIZE);
974
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
975
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
994
      close(pipefd[0]);
 
995
      close(pipefd[1]);
976
996
      exitstatus = EX_OSERR;
977
997
      free(direntries[i]);
978
998
      goto fallback;
982
1002
    ret = set_cloexec_flag(pipefd[0]);
983
1003
    if(ret < 0){
984
1004
      error(0, errno, "set_cloexec_flag");
985
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
986
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1005
      close(pipefd[0]);
 
1006
      close(pipefd[1]);
987
1007
      exitstatus = EX_OSERR;
988
1008
      free(direntries[i]);
989
1009
      goto fallback;
991
1011
    ret = set_cloexec_flag(pipefd[1]);
992
1012
    if(ret < 0){
993
1013
      error(0, errno, "set_cloexec_flag");
994
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
995
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1014
      close(pipefd[0]);
 
1015
      close(pipefd[1]);
996
1016
      exitstatus = EX_OSERR;
997
1017
      free(direntries[i]);
998
1018
      goto fallback;
1017
1037
      error(0, errno, "fork");
1018
1038
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1019
1039
                                     &sigchld_action.sa_mask, NULL));
1020
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
1021
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1040
      close(pipefd[0]);
 
1041
      close(pipefd[1]);
1022
1042
      exitstatus = EX_OSERR;
1023
1043
      free(direntries[i]);
1024
1044
      goto fallback;
1052
1072
      /* no return */
1053
1073
    }
1054
1074
    /* Parent process */
1055
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1056
 
                                             pipe */
1057
 
    TEMP_FAILURE_RETRY(close(plugin_fd));
 
1075
    close(pipefd[1]);           /* Close unused write end of pipe */
 
1076
    close(plugin_fd);
1058
1077
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1059
1078
    if(new_plugin == NULL){
1060
1079
      error(0, errno, "getplugin");
1084
1103
      goto fallback;
1085
1104
    }
1086
1105
    
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
 
1106
    FD_SET(new_plugin->fd, &rfds_all);
1101
1107
    
1102
1108
    if(maxfd < new_plugin->fd){
1103
1109
      maxfd = new_plugin->fd;
1106
1112
  
1107
1113
  free(direntries);
1108
1114
  direntries = NULL;
1109
 
  TEMP_FAILURE_RETRY(close(dir_fd));
 
1115
  close(dir_fd);
1110
1116
  dir_fd = -1;
1111
1117
  free_plugin(getplugin(NULL));
1112
1118
  
1152
1158
                      (intmax_t) (proc->pid),
1153
1159
                      WTERMSIG(proc->status),
1154
1160
                      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));
1158
1161
            }
1159
1162
          }
1160
1163
          
1161
1164
          /* Remove the plugin */
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
 
1165
          FD_CLR(proc->fd, &rfds_all);
1176
1166
          
1177
1167
          /* Block signal while modifying process_list */
1178
1168
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1218
1208
      }
1219
1209
      
1220
1210
      /* This process has not completed.  Does it have any output? */
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
 
1211
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1238
1212
        /* This process had nothing to say at this time */
1239
1213
        proc = proc->next;
1240
1214
        continue;
1310
1284
  free(direntries);
1311
1285
  
1312
1286
  if(dir_fd != -1){
1313
 
    TEMP_FAILURE_RETRY(close(dir_fd));
 
1287
    close(dir_fd);
1314
1288
  }
1315
1289
  
1316
1290
  /* Kill the processes */
1336
1310
  free_plugin_list();
1337
1311
  
1338
1312
  free(plugindir);
 
1313
  free(pluginhelperdir);
1339
1314
  free(argfile);
1340
1315
  
1341
1316
  return exitstatus;