/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
 
  uid_t uid = 65534;
124
 
  gid_t gid = 65534;
125
 
  /* The options we understand. */
126
 
  struct argp_option options[] = {
127
 
    { .name = "global-options", .key = 'g',
128
 
      .arg = "option[,option[,...]]", .flags = 0,
129
 
      .doc = "Options effecting all plugins" },
130
 
    { .name = "options-for", .key = 'o',
131
 
      .arg = "plugin:option[,option[,...]]", .flags = 0,
132
 
      .doc = "Options effecting only specified plugins" },
133
 
    { .name = "disable-plugin", .key = 'd',
134
 
      .arg = "Plugin[,Plugin[,...]]", .flags = 0,
135
 
      .doc = "Option to disable specififed plugins" },
136
 
    { .name = "plugin-dir", .key = 128,
137
 
      .arg = "Directory", .flags = 0,
138
 
      .doc = "Option to change directory to search for plugins" },
139
 
    { .name = "userid", .key = 129,
140
 
      .arg = "Id", .flags = 0,
141
 
      .doc = "Option to change which user id the plugins will run as" },
142
 
    { .name = "groupid", .key = 130,
143
 
      .arg = "Id", .flags = 0,
144
 
      .doc = "Option to change which group id the plugins will run as" },
145
 
    { .name = NULL }
146
 
  };
147
 
  
148
 
  error_t parse_opt (int key, char *arg, struct argp_state *state) {
149
 
       /* Get the INPUT argument from `argp_parse', which we
150
 
          know is a pointer to our arguments structure. */
151
 
    plugin **plugins = state->input;
152
 
    switch (key) {
153
 
    case 'g':
154
 
      if (arg != NULL){
155
 
        char *p = strtok(arg, ",");
156
 
        do{
157
 
          addarguments(getplugin(NULL, plugins), p);
158
 
          p = strtok(NULL, ",");
159
 
        } while (p);
160
 
      }
161
 
      break;
162
 
    case 'o':
163
 
      if (arg != NULL){
164
 
        char *name = strtok(arg, ":");
165
 
        char *p = strtok(NULL, ":");
166
 
        p = strtok(p, ",");
167
 
        do{
168
 
          addarguments(getplugin(name, plugins), p);
169
 
          p = strtok(NULL, ",");
170
 
        } while (p);
171
 
      }
172
 
      break;
173
 
    case 'd':
174
 
      if (arg != NULL){
175
 
        char *p = strtok(arg, ",");
176
 
        do{
177
 
          getplugin(p, plugins)->disable = true;
178
 
          p = strtok(NULL, ",");
179
 
        } while (p);
180
 
      }
181
 
      break;
182
 
    case 128:
183
 
      plugindir = arg;
184
 
      break;
185
 
    case 129:
186
 
      uid = (uid_t)strtol(arg, NULL, 10);
187
 
      break;
188
 
    case 130:
189
 
      gid = (gid_t)strtol(arg, NULL, 10);
190
 
      break;
191
 
    case ARGP_KEY_ARG:
192
 
      argp_usage (state);
193
 
      break;
194
 
    case ARGP_KEY_END:
195
 
      break;
196
 
    default:
197
 
      return ARGP_ERR_UNKNOWN;
198
 
    }
199
 
    return 0;
200
 
  }
201
 
 
202
 
  plugin *plugin_list = NULL;
203
 
  
204
 
  struct argp argp = { .options = options, .parser = parse_opt,
205
 
                       .args_doc = args_doc, .doc = doc };
206
 
 
207
 
  argp_parse (&argp, argc, argv, 0, 0, &plugin_list);
208
 
 
209
 
/*   for(plugin *p = plugin_list; p != NULL; p=p->next){ */
210
 
/*     fprintf(stderr, "Plugin: %s has %d arguments\n", p->name ? p->name : "Global", p->argc); */
211
 
/*     for(char **a = p->argv + 1; *a != NULL; a++){ */
212
 
/*       fprintf(stderr, "\tArg: %s\n", *a); */
213
 
/*     } */
214
 
/*   } */
215
 
  
216
 
/*   return 0; */
217
 
 
218
 
  ret = setuid(uid);
219
 
  if (ret == -1){
220
 
    perror("setuid");
221
 
  }
222
 
 
223
 
  setgid(gid);
224
 
  if (ret == -1){
225
 
    perror("setuid");
226
 
  }
227
38
  
228
39
  dir = opendir(plugindir);
229
 
  
 
40
 
230
41
  if(dir == NULL){
231
42
    fprintf(stderr, "Can not open directory\n");
232
43
    return EXIT_FAILURE;
249
60
        or dirst->d_name[d_name_len - 1] == '~'){
250
61
      continue;
251
62
    }
252
 
 
253
 
    char *filename = malloc(d_name_len + strlen(plugindir) + 2);
 
63
    
 
64
    char *filename = malloc(d_name_len + plugindir_len + 1);
254
65
    strcpy(filename, plugindir);
255
66
    strcat(filename, "/");
256
67
    strcat(filename, dirst->d_name);    
257
 
 
 
68
    
258
69
    stat(filename, &st);
259
70
 
260
 
    if (S_ISREG(st.st_mode)
261
 
        and (access(filename, X_OK) == 0)
262
 
        and not (getplugin(dirst->d_name, &plugin_list)->disable)){
 
71
    if (S_ISREG(st.st_mode) and (access(filename, X_OK) == 0)){
263
72
      // Starting a new process to be watched
264
73
      process *new_process = malloc(sizeof(process));
265
 
      int pipefd[2]; 
266
 
      ret = pipe(pipefd);
267
 
      if (ret == -1){
268
 
        perror(argv[0]);
269
 
        goto end;
270
 
      }
 
74
      int pipefd[2];
 
75
      pipe(pipefd);
271
76
      new_process->pid = fork();
272
77
      if(new_process->pid == 0){
273
78
        /* this is the child process */
274
79
        closedir(dir);
275
80
        close(pipefd[0]);       /* close unused read end of pipe */
276
81
        dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
277
 
 
278
 
        plugin *p = getplugin(dirst->d_name, &plugin_list);
279
 
        plugin *g = getplugin(NULL, &plugin_list);
280
 
        for(char **a = g->argv + 1; *a != NULL; a++){
281
 
          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];
282
87
        }
283
 
        if(execv(filename, p->argv) < 0){
 
88
        new_argv[argc] = NULL;
 
89
        if(execv(filename, new_argv) < 0){
284
90
          perror(argv[0]);
285
91
          close(pipefd[1]);
286
92
          exit(EXIT_FAILURE);
325
131
               > process_itr->buffer_size){
326
132
                process_itr->buffer = realloc(process_itr->buffer,
327
133
                                              process_itr->buffer_size
328
 
                                              + (size_t) BUFFER_SIZE);
 
134
                                              + BUFFER_SIZE);
329
135
                if (process_itr->buffer == NULL){
330
136
                  perror(argv[0]);
331
137
                  goto end;
334
140
            }
335
141
            ret = read(process_itr->fd, process_itr->buffer
336
142
                       + process_itr->buffer_length, BUFFER_SIZE);
337
 
            if(ret < 0){
338
 
              /* Read error from this process; ignore it */
339
 
              continue;
340
 
            }
341
 
            process_itr->buffer_length += (size_t) ret;
 
143
            process_itr->buffer_length+=ret;
342
144
            if(ret == 0){
343
145
              /* got EOF */
344
146
              /* wait for process exit */
345
147
              int status;
346
148
              waitpid(process_itr->pid, &status, 0);
347
149
              if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
348
 
                for(size_t written = 0;
349
 
                    written < process_itr->buffer_length;){
350
 
                  ret = write(STDOUT_FILENO,
351
 
                              process_itr->buffer + written,
352
 
                              process_itr->buffer_length - written);
353
 
                  if(ret < 0){
354
 
                    perror(argv[0]);
355
 
                    goto end;
356
 
                  }
357
 
                  written += (size_t)ret;
358
 
                }
 
150
                write(STDOUT_FILENO, process_itr->buffer,
 
151
                      process_itr->buffer_length);
359
152
                goto end;
360
153
              } else {
361
154
                FD_CLR(process_itr->fd, &rfds_orig);