/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
 
  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;
206
60
        or dirst->d_name[d_name_len - 1] == '~'){
207
61
      continue;
208
62
    }
209
 
 
210
 
    char *filename = malloc(d_name_len + plugindir_len + 2);
 
63
    
 
64
    char *filename = malloc(d_name_len + plugindir_len + 1);
211
65
    strcpy(filename, plugindir);
212
66
    strcat(filename, "/");
213
67
    strcat(filename, dirst->d_name);    
214
 
 
 
68
    
215
69
    stat(filename, &st);
216
70
 
217
71
    if (S_ISREG(st.st_mode) and (access(filename, X_OK) == 0)){
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);