/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: Teddy Hogeborn
  • Date: 2008-07-20 06:33:48 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080720063348-jscgy5p0itrgvlo8
* mandos-clients.conf ([foo]): Uncommented.
  ([foo]/secret): New.
  ([foo]/secfile): Commented out.
  ([foo]/checker): Changed to "fping -q -- %%(fqdn)s".
  ([foo]/timeout): New.

* server.py: New modeline for Python and Emacs.  Set a logging format.
  (Client.__init__): Bug fix: Choose either the value from the options
                     object or pass the argument through string_to_delta
                     for both "timeout" and "interval".
  (Client.checker_callback): Bug fix: Do not log spurious "Checker for
                             <foo> failed" messages.
  (Client.start_checker): Moved "Starting checker" log message down to
                          just before actually starting the subprocess.
                          Do not redirect the subprocesses' stdout to a
                          pipe.
  (peer_certificate, fingerprint): Added docstrings.
  (entry_group_state_changed): Call "killme()" instead of
                               "main_loop.quit()".
  (daemon, killme): New functions.
  (exitstatus, main_loop_started): New global variables.
  (__main__): Removed the "--cert", "--key", "--ca", and "--crl"
              options.  Removed the sleep command from the default
              checker.  Add a console logger in debug mode.  Call
              "killme()" instead of "main_loop.quit()" when there are no
              more clients.  Call "daemon()" if not in debug mode.
              Register "cleanup()" to run at exit.  Ignore some
              signals.  Catch DBusException to detect another running
              server and exit cleanly.  Exit with "exitstatus".
  (cleanup): New function.

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
 
  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
 
        
101
27
#define BUFFER_SIZE 256
102
28
 
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
 
 
112
29
int main(int argc, char *argv[]){
113
30
  char plugindir[] = "plugins.d";
114
31
  size_t d_name_len, plugindir_len = sizeof(plugindir)-1;
119
36
  int ret, maxfd = 0;
120
37
  process *process_list = NULL;
121
38
  
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
 
  
185
39
  dir = opendir(plugindir);
186
 
  
 
40
 
187
41
  if(dir == NULL){
188
42
    fprintf(stderr, "Can not open directory\n");
189
43
    return EXIT_FAILURE;
218
72
      // Starting a new process to be watched
219
73
      process *new_process = malloc(sizeof(process));
220
74
      int pipefd[2];
221
 
      ret = pipe(pipefd);
222
 
      if (ret == -1){
223
 
        perror(argv[0]);
224
 
        goto end;
225
 
      }
 
75
      pipe(pipefd);
226
76
      new_process->pid = fork();
227
77
      if(new_process->pid == 0){
228
78
        /* this is the child process */
229
79
        closedir(dir);
230
80
        close(pipefd[0]);       /* close unused read end of pipe */
231
81
        dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
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){
 
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){
246
90
          perror(argv[0]);
247
91
          close(pipefd[1]);
248
92
          exit(EXIT_FAILURE);
287
131
               > process_itr->buffer_size){
288
132
                process_itr->buffer = realloc(process_itr->buffer,
289
133
                                              process_itr->buffer_size
290
 
                                              + (size_t) BUFFER_SIZE);
 
134
                                              + BUFFER_SIZE);
291
135
                if (process_itr->buffer == NULL){
292
136
                  perror(argv[0]);
293
137
                  goto end;
296
140
            }
297
141
            ret = read(process_itr->fd, process_itr->buffer
298
142
                       + process_itr->buffer_length, BUFFER_SIZE);
299
 
            if(ret < 0){
300
 
              /* Read error from this process; ignore it */
301
 
              continue;
302
 
            }
303
 
            process_itr->buffer_length += (size_t) ret;
 
143
            process_itr->buffer_length+=ret;
304
144
            if(ret == 0){
305
145
              /* got EOF */
306
146
              /* wait for process exit */
307
147
              int status;
308
148
              waitpid(process_itr->pid, &status, 0);
309
149
              if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
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
 
                }
 
150
                write(STDOUT_FILENO, process_itr->buffer,
 
151
                      process_itr->buffer_length);
321
152
                goto end;
322
153
              } else {
323
154
                FD_CLR(process_itr->fd, &rfds_orig);