/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

  • Committer: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support:
Pluginbased client handler
rewritten Mandos client
       Avahi instead of udp server discovery
       openpgp encrypted key support
Passprompt stand alone application for direct console input
Added logging for Mandos server

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