/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk
21 by Teddy Hogeborn
* Makefile (CFLAGS): Changed to use $(WARN), $(DEBUG), $(COVERAGE) and
1
/*  -*- coding: utf-8 -*- */
2
/*
3
 * Mandos plugin runner - Run Mandos plugins
4
 *
5
 * Copyright © 2007-2008 Teddy Hogeborn and Björn Påhlsson.
6
 * 
7
 * This program is free software: you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License as
9
 * published by the Free Software Foundation, either version 3 of the
10
 * License, or (at your option) any later version.
11
 * 
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see
19
 * <http://www.gnu.org/licenses/>.
20
 * 
21
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
22
 * <https://www.fukt.bsnet.se/~teddy/>.
23
 */
24
25
#define _FORTIFY_SOURCE 2
26
13 by Björn Påhlsson
Added following support:
27
#include <stdio.h>	/* popen, fileno */
28
#include <iso646.h>	/* and, or, not */
29
#include <sys/types.h>	/* DIR, opendir, stat, struct stat, waitpid,
30
			   WIFEXITED, WEXITSTATUS, wait */
31
#include <sys/wait.h>	/* wait */
32
#include <dirent.h>	/* DIR, opendir */
33
#include <sys/stat.h>	/* stat, struct stat */
34
#include <unistd.h>	/* stat, struct stat, chdir */
35
#include <stdlib.h>	/* EXIT_FAILURE */
21 by Teddy Hogeborn
* Makefile (CFLAGS): Changed to use $(WARN), $(DEBUG), $(COVERAGE) and
36
#include <sys/select.h>	/* fd_set, select, FD_ZERO, FD_SET,
37
			   FD_ISSET */
13 by Björn Påhlsson
Added following support:
38
#include <string.h>	/* strlen, strcpy, strcat */
39
#include <stdbool.h>	/* true */
40
#include <sys/wait.h>	/* waitpid, WIFEXITED, WEXITSTATUS */
41
#include <errno.h>	/* errno */
42
43
struct process;
44
45
typedef struct process{
46
  pid_t pid;
47
  int fd;
48
  char *buffer;
21 by Teddy Hogeborn
* Makefile (CFLAGS): Changed to use $(WARN), $(DEBUG), $(COVERAGE) and
49
  size_t buffer_size;
50
  size_t buffer_length;
13 by Björn Påhlsson
Added following support:
51
  struct process *next;
52
} process;
53
54
#define BUFFER_SIZE 256
55
56
int main(int argc, char *argv[]){
57
  char plugindir[] = "plugins.d";
58
  size_t d_name_len, plugindir_len = sizeof(plugindir)-1;
59
  DIR *dir;
60
  struct dirent *dirst;
61
  struct stat st;
62
  fd_set rfds_orig;
63
  int ret, maxfd = 0;
64
  process *process_list = NULL;
65
  
66
  dir = opendir(plugindir);
67
68
  if(dir == NULL){
69
    fprintf(stderr, "Can not open directory\n");
70
    return EXIT_FAILURE;
71
  }
72
  
73
  FD_ZERO(&rfds_orig);
74
  
75
  while(true){
76
    dirst = readdir(dir);
77
    
78
    // All directory entries have been processed
79
    if(dirst == NULL){
80
      break;
81
    }
82
    
83
    d_name_len = strlen(dirst->d_name);
84
    
85
    // Ignore dotfiles and backup files
86
    if (dirst->d_name[0] == '.'
87
	or dirst->d_name[d_name_len - 1] == '~'){
88
      continue;
89
    }
14 by Björn Påhlsson
Fixed a overbufferflow bug, thanks to a forgotten \0
90
91
    char *filename = malloc(d_name_len + plugindir_len + 2);
13 by Björn Påhlsson
Added following support:
92
    strcpy(filename, plugindir);
93
    strcat(filename, "/");
94
    strcat(filename, dirst->d_name);    
14 by Björn Påhlsson
Fixed a overbufferflow bug, thanks to a forgotten \0
95
13 by Björn Påhlsson
Added following support:
96
    stat(filename, &st);
97
98
    if (S_ISREG(st.st_mode) and (access(filename, X_OK) == 0)){
99
      // Starting a new process to be watched
100
      process *new_process = malloc(sizeof(process));
101
      int pipefd[2];
102
      pipe(pipefd);
103
      new_process->pid = fork();
104
      if(new_process->pid == 0){
105
	/* this is the child process */
106
	closedir(dir);
107
	close(pipefd[0]);	/* close unused read end of pipe */
108
	dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
109
	/* create a new modified argument list */
21 by Teddy Hogeborn
* Makefile (CFLAGS): Changed to use $(WARN), $(DEBUG), $(COVERAGE) and
110
	char **new_argv = malloc(sizeof(char *)
111
				 * ((unsigned int) argc + 1));
13 by Björn Påhlsson
Added following support:
112
	new_argv[0] = filename;
113
	for(int i = 1; i < argc; i++){
114
	  new_argv[i] = argv[i];
115
	}
116
	new_argv[argc] = NULL;
117
	if(execv(filename, new_argv) < 0){
118
	  perror(argv[0]);
119
	  close(pipefd[1]);
120
	  exit(EXIT_FAILURE);
121
	}
122
	/* no return */
123
      }
124
      close(pipefd[1]);		/* close unused write end of pipe */
125
      new_process->fd = pipefd[0];
126
      new_process->buffer = malloc(BUFFER_SIZE);
127
      if (new_process->buffer == NULL){
128
	perror(argv[0]);
129
	goto end;
130
      }
131
      new_process->buffer_size = BUFFER_SIZE;
132
      new_process->buffer_length = 0;
133
      FD_SET(new_process->fd, &rfds_orig);
134
      
135
      if (maxfd < new_process->fd){
136
	maxfd = new_process->fd;
137
      }
138
      
139
      //List handling
140
      new_process->next = process_list;
141
      process_list = new_process;
142
    }
143
  }
144
  
145
  closedir(dir);
146
  
147
  if (process_list != NULL){
148
    while(true){
149
      fd_set rfds = rfds_orig;
150
      int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
151
      if (select_ret == -1){
152
	perror(argv[0]);
153
	goto end;
154
      }else{	
155
	for(process *process_itr = process_list; process_itr != NULL;
156
	    process_itr = process_itr->next){
157
	  if(FD_ISSET(process_itr->fd, &rfds)){
158
	    if(process_itr->buffer_length + BUFFER_SIZE
159
	       > process_itr->buffer_size){
160
		process_itr->buffer = realloc(process_itr->buffer,
161
					      process_itr->buffer_size
21 by Teddy Hogeborn
* Makefile (CFLAGS): Changed to use $(WARN), $(DEBUG), $(COVERAGE) and
162
					      + (size_t) BUFFER_SIZE);
13 by Björn Påhlsson
Added following support:
163
		if (process_itr->buffer == NULL){
164
		  perror(argv[0]);
165
		  goto end;
166
		}
167
		process_itr->buffer_size += BUFFER_SIZE;
168
	    }
169
	    ret = read(process_itr->fd, process_itr->buffer
170
		       + process_itr->buffer_length, BUFFER_SIZE);
21 by Teddy Hogeborn
* Makefile (CFLAGS): Changed to use $(WARN), $(DEBUG), $(COVERAGE) and
171
	    if(ret < 0){
172
	      /* Read error from this process; ignore it */
173
	      continue;
174
	    }
175
	    process_itr->buffer_length += (size_t) ret;
13 by Björn Påhlsson
Added following support:
176
	    if(ret == 0){
177
	      /* got EOF */
178
	      /* wait for process exit */
179
	      int status;
180
	      waitpid(process_itr->pid, &status, 0);
181
	      if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
182
		write(STDOUT_FILENO, process_itr->buffer,
183
		      process_itr->buffer_length);
184
		goto end;
185
	      } else {
186
		FD_CLR(process_itr->fd, &rfds_orig);
187
	      }
188
	    }
189
	  }
190
	}
191
      }
192
    }
193
  }
194
  
195
 end:
196
  for(process *process_itr = process_list; process_itr != NULL;
197
      process_itr = process_itr->next){
198
    close(process_itr->fd);
199
    kill(process_itr->pid, SIGTERM);
200
    free(process_itr->buffer);
201
  }
202
  
203
  while(true){
204
    int status;
205
    ret = wait(&status);
206
    if (ret == -1){
207
      if(errno != ECHILD){
208
	perror("wait");
209
      }
210
      break;
211
    }
212
  }  
213
  return EXIT_SUCCESS;
214
}