/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 plugbasedclient.c

Added optional parameters certdir, certkey and certfile that can be iven at start in the command line.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
1
27
#include <stdio.h>      /* popen, fileno */
2
28
#include <iso646.h>     /* and, or, not */
3
29
#include <sys/types.h>  /* DIR, opendir, stat, struct stat, waitpid,
7
33
#include <sys/stat.h>   /* stat, struct stat */
8
34
#include <unistd.h>     /* stat, struct stat, chdir */
9
35
#include <stdlib.h>     /* EXIT_FAILURE */
10
 
#include <sys/select.h> /* fd_set, select, FD_ZERO, FD_SET, FD_ISSET */
 
36
#include <sys/select.h> /* fd_set, select, FD_ZERO, FD_SET,
 
37
                           FD_ISSET */
11
38
#include <string.h>     /* strlen, strcpy, strcat */
12
39
#include <stdbool.h>    /* true */
13
40
#include <sys/wait.h>   /* waitpid, WIFEXITED, WEXITSTATUS */
14
41
#include <errno.h>      /* errno */
 
42
#include <argp.h>       /* argp */
15
43
 
16
44
struct process;
17
45
 
19
47
  pid_t pid;
20
48
  int fd;
21
49
  char *buffer;
22
 
  int buffer_size;
23
 
  int buffer_length;
 
50
  size_t buffer_size;
 
51
  size_t buffer_length;
24
52
  struct process *next;
25
53
} process;
26
54
 
 
55
typedef struct plugin{
 
56
  char *name;           /* can be "global" and any plugin name */
 
57
  char **argv;
 
58
  int argc;
 
59
  struct plugin *next;
 
60
} plugin;
 
61
 
 
62
plugin *getplugin(char *name, plugin **plugin_list){
 
63
  for (plugin *p = *plugin_list; p != NULL; p = p->next){
 
64
    if ((p->name == name)
 
65
        or (p->name and name and (strcmp(p->name, name) == 0))){
 
66
      return p;
 
67
    }
 
68
  }
 
69
  /* Create a new plugin */
 
70
  plugin *new_plugin = malloc(sizeof(plugin));
 
71
  if (new_plugin == NULL){
 
72
    perror("malloc");
 
73
    exit(EXIT_FAILURE);
 
74
  }
 
75
  new_plugin->name = name;
 
76
  new_plugin->argv = malloc(sizeof(char *) * 2);
 
77
  if (new_plugin->argv == NULL){
 
78
    perror("malloc");
 
79
    exit(EXIT_FAILURE);
 
80
  }
 
81
  new_plugin->argv[0] = name;
 
82
  new_plugin->argv[1] = NULL;
 
83
  new_plugin->argc = 1;
 
84
  /* Append the new plugin to the list */
 
85
  new_plugin->next = *plugin_list;
 
86
  *plugin_list = new_plugin;
 
87
  return new_plugin;
 
88
}
 
89
 
 
90
void addarguments(plugin *p, char *arg){
 
91
  p->argv[p->argc] = arg;
 
92
  p->argv = realloc(p->argv, sizeof(char *) * (size_t)(p->argc + 2));
 
93
  if (p->argv == NULL){
 
94
    perror("malloc");
 
95
    exit(EXIT_FAILURE);
 
96
  }
 
97
  p->argc++;
 
98
  p->argv[p->argc] = NULL;
 
99
}
 
100
        
27
101
#define BUFFER_SIZE 256
28
102
 
 
103
const char *argp_program_version =
 
104
  "plugbasedclient 0.9";
 
105
const char *argp_program_bug_address =
 
106
  "<mandos@fukt.bsnet.se>";
 
107
static char doc[] =
 
108
  "Mandos plugin runner -- Run Mandos plugins";
 
109
/* A description of the arguments we accept. */
 
110
static char args_doc[] = "";
 
111
 
29
112
int main(int argc, char *argv[]){
30
113
  char plugindir[] = "plugins.d";
31
114
  size_t d_name_len, plugindir_len = sizeof(plugindir)-1;
36
119
  int ret, maxfd = 0;
37
120
  process *process_list = NULL;
38
121
  
 
122
  /* The options we understand. */
 
123
  struct argp_option options[] = {
 
124
    { .name = "global-options", .key = 'g',
 
125
      .arg = "option[,option[,...]]", .flags = 0,
 
126
      .doc = "Options effecting all plugins" },
 
127
    { .name = "options-for", .key = 'o',
 
128
      .arg = "plugin:option[,option[,...]]", .flags = 0,
 
129
      .doc = "Options effecting only specified plugins" },
 
130
    { .name = NULL }
 
131
  };
 
132
  
 
133
  error_t parse_opt (int key, char *arg, struct argp_state *state) {
 
134
       /* Get the INPUT argument from `argp_parse', which we
 
135
          know is a pointer to our arguments structure. */
 
136
    plugin **plugins = state->input;
 
137
    switch (key) {
 
138
    case 'g':
 
139
      if (arg != NULL){
 
140
        char *p = strtok(arg, ",");
 
141
        do{
 
142
          addarguments(getplugin(NULL, plugins), p);
 
143
          p = strtok(NULL, ",");
 
144
        } while (p);
 
145
      }
 
146
      break;
 
147
    case 'o':
 
148
      if (arg != NULL){
 
149
        char *name = strtok(arg, ":");
 
150
        char *p = strtok(NULL, ":");
 
151
        p = strtok(p, ",");
 
152
        do{
 
153
          addarguments(getplugin(name, plugins), p);
 
154
          p = strtok(NULL, ",");
 
155
        } while (p);
 
156
      }
 
157
      break;
 
158
    case ARGP_KEY_ARG:
 
159
      argp_usage (state);
 
160
      break;
 
161
    case ARGP_KEY_END:
 
162
      break;
 
163
    default:
 
164
      return ARGP_ERR_UNKNOWN;
 
165
    }
 
166
    return 0;
 
167
  }
 
168
 
 
169
  plugin *plugin_list = NULL;
 
170
  
 
171
  struct argp argp = { .options = options, .parser = parse_opt,
 
172
                       .args_doc = args_doc, .doc = doc };
 
173
 
 
174
  argp_parse (&argp, argc, argv, 0, 0, &plugin_list);
 
175
 
 
176
/*   for(plugin *p = plugin_list; p != NULL; p=p->next){ */
 
177
/*     fprintf(stderr, "Plugin: %s has %d arguments\n", p->name ? p->name : "Global", p->argc); */
 
178
/*     for(char **a = p->argv + 1; *a != NULL; a++){ */
 
179
/*       fprintf(stderr, "\tArg: %s\n", *a); */
 
180
/*     } */
 
181
/*   } */
 
182
  
 
183
/*   return 0; */
 
184
  
39
185
  dir = opendir(plugindir);
40
 
 
 
186
  
41
187
  if(dir == NULL){
42
188
    fprintf(stderr, "Can not open directory\n");
43
189
    return EXIT_FAILURE;
60
206
        or dirst->d_name[d_name_len - 1] == '~'){
61
207
      continue;
62
208
    }
63
 
    
64
 
    char *filename = malloc(d_name_len + plugindir_len + 1);
 
209
 
 
210
    char *filename = malloc(d_name_len + plugindir_len + 2);
65
211
    strcpy(filename, plugindir);
66
212
    strcat(filename, "/");
67
213
    strcat(filename, dirst->d_name);    
68
 
    
 
214
 
69
215
    stat(filename, &st);
70
216
 
71
217
    if (S_ISREG(st.st_mode) and (access(filename, X_OK) == 0)){
72
218
      // Starting a new process to be watched
73
219
      process *new_process = malloc(sizeof(process));
74
220
      int pipefd[2];
75
 
      pipe(pipefd);
 
221
      ret = pipe(pipefd);
 
222
      if (ret == -1){
 
223
        perror(argv[0]);
 
224
        goto end;
 
225
      }
76
226
      new_process->pid = fork();
77
227
      if(new_process->pid == 0){
78
228
        /* this is the child process */
79
229
        closedir(dir);
80
230
        close(pipefd[0]);       /* close unused read end of pipe */
81
231
        dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
82
 
        /* create a new modified argument list */
83
 
        char **new_argv = malloc(sizeof(char *) * argc + 1);
84
 
        new_argv[0] = filename;
85
 
        for(int i = 1; i < argc; i++){
86
 
          new_argv[i] = argv[i];
87
 
        }
88
 
        new_argv[argc] = NULL;
89
 
        if(execv(filename, new_argv) < 0){
 
232
        char *basename;
 
233
        basename = strrchr(filename, '/');
 
234
        if (basename == NULL){
 
235
          basename = filename;
 
236
        } else {
 
237
          basename++;
 
238
        }
 
239
        plugin *p = getplugin(basename, &plugin_list);
 
240
 
 
241
        plugin *g = getplugin(NULL, &plugin_list);
 
242
        for(char **a = g->argv + 1; *a != NULL; a++){
 
243
          addarguments(p, *a);
 
244
        }
 
245
        if(execv(filename, p->argv) < 0){
90
246
          perror(argv[0]);
91
247
          close(pipefd[1]);
92
248
          exit(EXIT_FAILURE);
131
287
               > process_itr->buffer_size){
132
288
                process_itr->buffer = realloc(process_itr->buffer,
133
289
                                              process_itr->buffer_size
134
 
                                              + BUFFER_SIZE);
 
290
                                              + (size_t) BUFFER_SIZE);
135
291
                if (process_itr->buffer == NULL){
136
292
                  perror(argv[0]);
137
293
                  goto end;
140
296
            }
141
297
            ret = read(process_itr->fd, process_itr->buffer
142
298
                       + process_itr->buffer_length, BUFFER_SIZE);
143
 
            process_itr->buffer_length+=ret;
 
299
            if(ret < 0){
 
300
              /* Read error from this process; ignore it */
 
301
              continue;
 
302
            }
 
303
            process_itr->buffer_length += (size_t) ret;
144
304
            if(ret == 0){
145
305
              /* got EOF */
146
306
              /* wait for process exit */
147
307
              int status;
148
308
              waitpid(process_itr->pid, &status, 0);
149
309
              if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
150
 
                write(STDOUT_FILENO, process_itr->buffer,
151
 
                      process_itr->buffer_length);
 
310
                for(size_t written = 0;
 
311
                    written < process_itr->buffer_length;){
 
312
                  ret = write(STDOUT_FILENO,
 
313
                              process_itr->buffer + written,
 
314
                              process_itr->buffer_length - written);
 
315
                  if(ret < 0){
 
316
                    perror(argv[0]);
 
317
                    goto end;
 
318
                  }
 
319
                  written += (size_t)ret;
 
320
                }
152
321
                goto end;
153
322
              } else {
154
323
                FD_CLR(process_itr->fd, &rfds_orig);