/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

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