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