/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: 2009-10-22 00:05:01 UTC
  • Revision ID: teddy@fukt.bsnet.se-20091022000501-g792e99q5g1wkyet
Merge from release branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 */
24
24
 
25
25
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), getline(),
26
 
                                   asprintf() */
 
26
                                   asprintf(), O_CLOEXEC */
27
27
#include <stddef.h>             /* size_t, NULL */
28
28
#include <stdlib.h>             /* malloc(), exit(), EXIT_FAILURE,
29
29
                                   EXIT_SUCCESS, realloc() */
30
30
#include <stdbool.h>            /* bool, true, false */
31
31
#include <stdio.h>              /* perror, fileno(), fprintf(),
32
32
                                   stderr, STDOUT_FILENO */
33
 
#include <sys/types.h>          /* DIR, opendir(), stat(), struct
 
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(),
42
42
                                   WCOREDUMP() */
43
43
#include <sys/stat.h>           /* struct stat, stat(), S_ISREG() */
44
44
#include <iso646.h>             /* and, or, not */
45
 
#include <dirent.h>             /* DIR, struct dirent, opendir(),
 
45
#include <dirent.h>             /* DIR, struct dirent, fdopendir(),
46
46
                                   readdir(), closedir(), dirfd() */
47
47
#include <unistd.h>             /* struct stat, stat(), S_ISREG(),
48
48
                                   fcntl(), setuid(), setgid(),
111
111
  }
112
112
  /* Create a new plugin */
113
113
  plugin *new_plugin = NULL;
114
 
  do{
 
114
  do {
115
115
    new_plugin = malloc(sizeof(plugin));
116
 
  }while(new_plugin == NULL and errno == EINTR);
 
116
  } while(new_plugin == NULL and errno == EINTR);
117
117
  if(new_plugin == NULL){
118
118
    return NULL;
119
119
  }
120
120
  char *copy_name = NULL;
121
121
  if(name != NULL){
122
 
    do{
 
122
    do {
123
123
      copy_name = strdup(name);
124
 
    }while(copy_name == NULL and errno == EINTR);
 
124
    } while(copy_name == NULL and errno == EINTR);
125
125
    if(copy_name == NULL){
126
126
      free(new_plugin);
127
127
      return NULL;
133
133
                          .disabled = false,
134
134
                          .next = plugin_list };
135
135
  
136
 
  do{
 
136
  do {
137
137
    new_plugin->argv = malloc(sizeof(char *) * 2);
138
 
  }while(new_plugin->argv == NULL and errno == EINTR);
 
138
  } while(new_plugin->argv == NULL and errno == EINTR);
139
139
  if(new_plugin->argv == NULL){
140
140
    free(copy_name);
141
141
    free(new_plugin);
144
144
  new_plugin->argv[0] = copy_name;
145
145
  new_plugin->argv[1] = NULL;
146
146
  
147
 
  do{
 
147
  do {
148
148
    new_plugin->environ = malloc(sizeof(char *));
149
 
  }while(new_plugin->environ == NULL and errno == EINTR);
 
149
  } while(new_plugin->environ == NULL and errno == EINTR);
150
150
  if(new_plugin->environ == NULL){
151
151
    free(copy_name);
152
152
    free(new_plugin->argv);
164
164
static bool add_to_char_array(const char *new, char ***array,
165
165
                              int *len){
166
166
  /* Resize the pointed-to array to hold one more pointer */
167
 
  do{
 
167
  do {
168
168
    *array = realloc(*array, sizeof(char *)
169
169
                     * (size_t) ((*len) + 2));
170
 
  }while(*array == NULL and errno == EINTR);
 
170
  } while(*array == NULL and errno == EINTR);
171
171
  /* Malloc check */
172
172
  if(*array == NULL){
173
173
    return false;
174
174
  }
175
175
  /* Make a copy of the new string */
176
176
  char *copy;
177
 
  do{
 
177
  do {
178
178
    copy = strdup(new);
179
 
  }while(copy == NULL and errno == EINTR);
 
179
  } while(copy == NULL and errno == EINTR);
180
180
  if(copy == NULL){
181
181
    return false;
182
182
  }
209
209
      /* It already exists */
210
210
      if(replace){
211
211
        char *new;
212
 
        do{
 
212
        do {
213
213
          new = realloc(*e, strlen(def) + 1);
214
 
        }while(new == NULL and errno == EINTR);
 
214
        } while(new == NULL and errno == EINTR);
215
215
        if(new == NULL){
216
216
          return false;
217
217
        }
230
230
 | [[info:libc:Descriptor%20Flags][File Descriptor Flags]] |
231
231
 */
232
232
static int set_cloexec_flag(int fd){
233
 
  int ret = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0));
 
233
  int ret = (int)TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0));
234
234
  /* If reading the flags failed, return error indication now. */
235
235
  if(ret < 0){
236
236
    return ret;
237
237
  }
238
238
  /* Store modified flag word in the descriptor. */
239
 
  return TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, ret | FD_CLOEXEC));
 
239
  return (int)TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD,
 
240
                                       ret | FD_CLOEXEC));
240
241
}
241
242
 
242
243
 
634
635
        custom_argv[custom_argc] = NULL;
635
636
      }
636
637
    }
637
 
    do{
 
638
    do {
638
639
      ret = fclose(conffp);
639
 
    }while(ret == EOF and errno == EINTR);
 
640
    } while(ret == EOF and errno == EINTR);
640
641
    if(ret == EOF){
641
642
      perror("fclose");
642
643
      exitstatus = EXIT_FAILURE;
697
698
    perror("setuid");
698
699
  }
699
700
  
700
 
  if(plugindir == NULL){
701
 
    dir = opendir(PDIR);
702
 
  } else {
703
 
    dir = opendir(plugindir);
704
 
  }
705
 
  
706
 
  if(dir == NULL){
707
 
    perror("Could not open plugin dir");
708
 
    exitstatus = EXIT_FAILURE;
709
 
    goto fallback;
710
 
  }
711
 
  
712
 
  /* Set the FD_CLOEXEC flag on the directory, if possible */
 
701
  /* Open plugin directory with close_on_exec flag */
713
702
  {
714
 
    int dir_fd = dirfd(dir);
715
 
    if(dir_fd >= 0){
716
 
      ret = set_cloexec_flag(dir_fd);
717
 
      if(ret < 0){
718
 
        perror("set_cloexec_flag");
719
 
        exitstatus = EXIT_FAILURE;
720
 
        goto fallback;
721
 
      }
 
703
    int dir_fd = -1;
 
704
    if(plugindir == NULL){
 
705
      dir_fd = open(PDIR, O_RDONLY |
 
706
#ifdef O_CLOEXEC
 
707
                    O_CLOEXEC
 
708
#else  /* not O_CLOEXEC */
 
709
                    0
 
710
#endif  /* not O_CLOEXEC */
 
711
                    );
 
712
    } else {
 
713
      dir_fd = open(plugindir, O_RDONLY |
 
714
#ifdef O_CLOEXEC
 
715
                    O_CLOEXEC
 
716
#else  /* not O_CLOEXEC */
 
717
                    0
 
718
#endif  /* not O_CLOEXEC */
 
719
                    );
 
720
    }
 
721
    if(dir_fd == -1){
 
722
      perror("Could not open plugin dir");
 
723
      exitstatus = EXIT_FAILURE;
 
724
      goto fallback;
 
725
    }
 
726
    
 
727
#ifndef O_CLOEXEC
 
728
  /* Set the FD_CLOEXEC flag on the directory */
 
729
    ret = set_cloexec_flag(dir_fd);
 
730
    if(ret < 0){
 
731
      perror("set_cloexec_flag");
 
732
      TEMP_FAILURE_RETRY(close(dir_fd));
 
733
      exitstatus = EXIT_FAILURE;
 
734
      goto fallback;
 
735
    }
 
736
#endif  /* O_CLOEXEC */
 
737
    
 
738
    dir = fdopendir(dir_fd);
 
739
    if(dir == NULL){
 
740
      perror("Could not open plugin dir");
 
741
      TEMP_FAILURE_RETRY(close(dir_fd));
 
742
      exitstatus = EXIT_FAILURE;
 
743
      goto fallback;
722
744
    }
723
745
  }
724
746
  
726
748
  
727
749
  /* Read and execute any executable in the plugin directory*/
728
750
  while(true){
729
 
    do{
 
751
    do {
730
752
      dirst = readdir(dir);
731
 
    }while(dirst == NULL and errno == EINTR);
 
753
    } while(dirst == NULL and errno == EINTR);
732
754
    
733
755
    /* All directory entries have been processed */
734
756
    if(dirst == NULL){
788
810
    
789
811
    char *filename;
790
812
    if(plugindir == NULL){
791
 
      ret = TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s",
792
 
                                        dirst->d_name));
 
813
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s",
 
814
                                             dirst->d_name));
793
815
    } else {
794
 
      ret = TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s", plugindir,
795
 
                                        dirst->d_name));
 
816
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s",
 
817
                                             plugindir,
 
818
                                             dirst->d_name));
796
819
    }
797
820
    if(ret < 0){
798
821
      perror("asprintf");
799
822
      continue;
800
823
    }
801
824
    
802
 
    ret = TEMP_FAILURE_RETRY(stat(filename, &st));
 
825
    ret = (int)TEMP_FAILURE_RETRY(stat(filename, &st));
803
826
    if(ret == -1){
804
827
      perror("stat");
805
828
      free(filename);
860
883
    }
861
884
    
862
885
    int pipefd[2];
863
 
    ret = TEMP_FAILURE_RETRY(pipe(pipefd));
 
886
    ret = (int)TEMP_FAILURE_RETRY(pipe(pipefd));
864
887
    if(ret == -1){
865
888
      perror("pipe");
866
889
      exitstatus = EXIT_FAILURE;
880
903
      goto fallback;
881
904
    }
882
905
    /* Block SIGCHLD until process is safely in process list */
883
 
    ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK,
884
 
                                         &sigchld_action.sa_mask,
885
 
                                         NULL));
 
906
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK,
 
907
                                              &sigchld_action.sa_mask,
 
908
                                              NULL));
886
909
    if(ret < 0){
887
910
      perror("sigprocmask");
888
911
      exitstatus = EXIT_FAILURE;
890
913
    }
891
914
    /* Starting a new process to be watched */
892
915
    pid_t pid;
893
 
    do{
 
916
    do {
894
917
      pid = fork();
895
 
    }while(pid == -1 and errno == EINTR);
 
918
    } while(pid == -1 and errno == EINTR);
896
919
    if(pid == -1){
897
920
      perror("fork");
898
921
      exitstatus = EXIT_FAILURE;
942
965
    plugin *new_plugin = getplugin(dirst->d_name);
943
966
    if(new_plugin == NULL){
944
967
      perror("getplugin");
945
 
      ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
946
 
                                           &sigchld_action.sa_mask,
947
 
                                           NULL));
 
968
      ret = (int)(TEMP_FAILURE_RETRY
 
969
                  (sigprocmask(SIG_UNBLOCK, &sigchld_action.sa_mask,
 
970
                               NULL)));
948
971
      if(ret < 0){
949
972
        perror("sigprocmask");
950
973
      }
957
980
    
958
981
    /* Unblock SIGCHLD so signal handler can be run if this process
959
982
       has already completed */
960
 
    ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
961
 
                                         &sigchld_action.sa_mask,
962
 
                                         NULL));
 
983
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
 
984
                                              &sigchld_action.sa_mask,
 
985
                                              NULL));
963
986
    if(ret < 0){
964
987
      perror("sigprocmask");
965
988
      exitstatus = EXIT_FAILURE;
966
989
      goto fallback;
967
990
    }
968
991
    
969
 
    FD_SET(new_plugin->fd, &rfds_all);
 
992
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
 
993
                                          -Wconversion */
970
994
    
971
995
    if(maxfd < new_plugin->fd){
972
996
      maxfd = new_plugin->fd;
1026
1050
          }
1027
1051
          
1028
1052
          /* Remove the plugin */
1029
 
          FD_CLR(proc->fd, &rfds_all);
 
1053
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
 
1054
                                          -Wconversion */
1030
1055
          
1031
1056
          /* Block signal while modifying process_list */
1032
 
          ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK,
1033
 
                                               &sigchld_action.sa_mask,
1034
 
                                               NULL));
 
1057
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
 
1058
                                        (SIG_BLOCK,
 
1059
                                         &sigchld_action.sa_mask,
 
1060
                                         NULL));
1035
1061
          if(ret < 0){
1036
1062
            perror("sigprocmask");
1037
1063
            exitstatus = EXIT_FAILURE;
1043
1069
          proc = next_plugin;
1044
1070
          
1045
1071
          /* We are done modifying process list, so unblock signal */
1046
 
          ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1047
 
                                               &sigchld_action.sa_mask,
1048
 
                                               NULL));
 
1072
          ret = (int)(TEMP_FAILURE_RETRY
 
1073
                      (sigprocmask(SIG_UNBLOCK,
 
1074
                                   &sigchld_action.sa_mask, NULL)));
1049
1075
          if(ret < 0){
1050
1076
            perror("sigprocmask");
1051
1077
            exitstatus = EXIT_FAILURE;
1071
1097
      }
1072
1098
      
1073
1099
      /* This process has not completed.  Does it have any output? */
1074
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
 
1100
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
 
1101
                                                         warning from
 
1102
                                                         -Wconversion */
1075
1103
        /* This process had nothing to say at this time */
1076
1104
        proc = proc->next;
1077
1105
        continue;
1159
1187
  }
1160
1188
  
1161
1189
  /* Wait for any remaining child processes to terminate */
1162
 
  do{
 
1190
  do {
1163
1191
    ret = wait(NULL);
1164
1192
  } while(ret >= 0);
1165
1193
  if(errno != ECHILD){