/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 plugin-runner.c

merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 * Contact the authors at <mandos@fukt.bsnet.se>.
22
22
 */
23
23
 
24
 
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY() */
25
 
 
 
24
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), getline(),
 
25
                                   asprintf() */
26
26
#include <stddef.h>             /* size_t, NULL */
27
27
#include <stdlib.h>             /* malloc(), exit(), EXIT_FAILURE,
28
28
                                   EXIT_SUCCESS, realloc() */
51
51
                                   close() */
52
52
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
53
53
                                   FD_CLOEXEC */
54
 
#include <string.h>             /* strsep, strlen(), strcpy(),
55
 
                                   strcat() */
 
54
#include <string.h>             /* strsep, strlen(), asprintf() */
56
55
#include <errno.h>              /* errno */
57
56
#include <argp.h>               /* struct argp_option, struct
58
57
                                   argp_state, struct argp,
65
64
#include <errno.h>              /* errno, EBADF */
66
65
 
67
66
#define BUFFER_SIZE 256
68
 
#define ARGFILE "/conf/conf.d/mandos/plugins.conf"
 
67
#define ARGFILE "/conf/conf.d/mandos/plugin-runner.conf"
69
68
 
70
69
const char *argp_program_version = "plugin-runner 1.0";
71
70
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
88
87
  char *name;                   /* can be NULL or any plugin name */
89
88
  char **argv;
90
89
  int argc;
 
90
  char **environ;
 
91
  int envc;
91
92
  bool disabled;
92
93
  struct plugin *next;
93
94
} plugin;
102
103
  /* Create a new plugin */
103
104
  plugin *new_plugin = malloc(sizeof(plugin));
104
105
  if (new_plugin == NULL){
105
 
    perror("malloc");
106
 
    exit(EXIT_FAILURE);
 
106
    return NULL;
107
107
  }
108
 
  new_plugin->name = name;
 
108
  *new_plugin = (plugin) { .name = name,
 
109
                           .argc = 1,
 
110
                           .envc = 0,
 
111
                           .disabled = false,
 
112
                           .next = *plugin_list };
 
113
  
109
114
  new_plugin->argv = malloc(sizeof(char *) * 2);
110
115
  if (new_plugin->argv == NULL){
111
 
    perror("malloc");
112
 
    exit(EXIT_FAILURE);
 
116
    free(new_plugin);
 
117
    return NULL;
113
118
  }
114
119
  new_plugin->argv[0] = name;
115
120
  new_plugin->argv[1] = NULL;
116
 
  new_plugin->argc = 1;
117
 
  new_plugin->disabled = false;
118
 
  new_plugin->next = *plugin_list;
 
121
 
 
122
  new_plugin->environ = malloc(sizeof(char *));
 
123
  if(new_plugin->environ == NULL){
 
124
    free(new_plugin->argv);
 
125
    free(new_plugin);
 
126
    return NULL;
 
127
  }
 
128
  new_plugin->environ[0] = NULL;
119
129
  /* Append the new plugin to the list */
120
130
  *plugin_list = new_plugin;
121
131
  return new_plugin;
122
132
}
123
133
 
124
 
static void addargument(plugin *p, char *arg){
125
 
  p->argv[p->argc] = arg;
126
 
  p->argv = realloc(p->argv, sizeof(char *) * (size_t)(p->argc + 2));
127
 
  if (p->argv == NULL){
128
 
    perror("malloc");
129
 
    exit(EXIT_FAILURE);
130
 
  }
131
 
  p->argc++;
132
 
  p->argv[p->argc] = NULL;
133
 
}
 
134
/* Helper function for add_argument and add_environment */
 
135
static bool add_to_char_array(const char *new, char ***array,
 
136
                              int *len){
 
137
  /* Resize the pointed-to array to hold one more pointer */
 
138
  *array = realloc(*array, sizeof(char *)
 
139
                   * (size_t) ((*len) + 2));
 
140
  /* Malloc check */
 
141
  if(*array == NULL){
 
142
    return false;
 
143
  }
 
144
  /* Make a copy of the new string */
 
145
  char *copy = strdup(new);
 
146
  if(copy == NULL){
 
147
    return false;
 
148
  }
 
149
  /* Insert the copy */
 
150
  (*array)[*len] = copy;
 
151
  (*len)++;
 
152
  /* Add a new terminating NULL pointer to the last element */
 
153
  (*array)[*len] = NULL;
 
154
  return true;
 
155
}
 
156
 
 
157
/* Add to a plugin's argument vector */
 
158
static bool add_argument(plugin *p, const char *arg){
 
159
  if(p == NULL){
 
160
    return false;
 
161
  }
 
162
  return add_to_char_array(arg, &(p->argv), &(p->argc));
 
163
}
 
164
 
 
165
/* Add to a plugin's environment */
 
166
static bool add_environment(plugin *p, const char *def){
 
167
  if(p == NULL){
 
168
    return false;
 
169
  }
 
170
  return add_to_char_array(def, &(p->environ), &(p->envc));
 
171
}
 
172
 
134
173
 
135
174
/*
136
175
 * Based on the example in the GNU LibC manual chapter 13.13 "File
186
225
  return true;
187
226
}
188
227
 
189
 
char ** addcustomargument(char **argv, int *argc, char *arg){
190
 
 
 
228
char **add_to_argv(char **argv, int *argc, char *arg){
191
229
  if (argv == NULL){
192
230
    *argc = 1;
193
231
    argv = malloc(sizeof(char*) * 2);
246
284
    { .name = "global-options", .key = 'g',
247
285
      .arg = "OPTION[,OPTION[,...]]",
248
286
      .doc = "Options passed to all plugins" },
 
287
    { .name = "global-envs", .key = 'e',
 
288
      .arg = "VAR=value",
 
289
      .doc = "Environment variable passed to all plugins" },
249
290
    { .name = "options-for", .key = 'o',
250
291
      .arg = "PLUGIN:OPTION[,OPTION[,...]]",
251
292
      .doc = "Options passed only to specified plugin" },
 
293
    { .name = "envs-for", .key = 'f',
 
294
      .arg = "PLUGIN:ENV=value",
 
295
      .doc = "Environment variable passed to specified plugin" },
252
296
    { .name = "disable", .key = 'd',
253
297
      .arg = "PLUGIN",
254
298
      .doc = "Disable a specific plugin", .group = 1 },
278
322
          if(p[0] == '\0'){
279
323
            continue;
280
324
          }
281
 
          addargument(getplugin(NULL, plugins), p);
 
325
          if(not add_argument(getplugin(NULL, plugins), p)){
 
326
            perror("add_argument");
 
327
            return ARGP_ERR_UNKNOWN;
 
328
          }
 
329
        }
 
330
      }
 
331
      break;
 
332
    case 'e':
 
333
      if(arg == NULL){
 
334
        break;
 
335
      }
 
336
      {
 
337
        char *envdef = strdup(arg);
 
338
        if(envdef == NULL){
 
339
          break;
 
340
        }
 
341
        if(not add_environment(getplugin(NULL, plugins), envdef)){
 
342
          perror("add_environment");
282
343
        }
283
344
      }
284
345
      break;
285
346
    case 'o':
286
347
      if (arg != NULL){
287
 
        char *name = strsep(&arg, ":");
288
 
        if(name[0] == '\0'){
 
348
        char *p_name = strsep(&arg, ":");
 
349
        if(p_name[0] == '\0'){
289
350
          break;
290
351
        }
291
352
        char *opt = strsep(&arg, ":");
298
359
            if(p[0] == '\0'){
299
360
              continue;
300
361
            }
301
 
            addargument(getplugin(name, plugins), p);
 
362
            if(not add_argument(getplugin(p_name, plugins), p)){
 
363
              perror("add_argument");
 
364
              return ARGP_ERR_UNKNOWN;
 
365
            }
302
366
          }
303
367
        }
304
368
      }
305
369
      break;
 
370
    case 'f':
 
371
      if(arg == NULL){
 
372
        break;
 
373
      }
 
374
      {
 
375
        char *envdef = strchr(arg, ':');
 
376
        if(envdef == NULL){
 
377
          break;
 
378
        }
 
379
        char *p_name = strndup(arg, (size_t) (envdef-arg));
 
380
        if(p_name == NULL){
 
381
          break;
 
382
        }
 
383
        envdef++;
 
384
        if(not add_environment(getplugin(p_name, plugins), envdef)){
 
385
          perror("add_environment");
 
386
        }
 
387
      }
 
388
      break;
306
389
    case 'd':
307
390
      if (arg != NULL){
308
 
        getplugin(arg, plugins)->disabled = true;
 
391
        plugin *p = getplugin(arg, plugins);
 
392
        if(p == NULL){
 
393
          return ARGP_ERR_UNKNOWN;
 
394
        }
 
395
        p->disabled = true;
309
396
      }
310
397
      break;
311
398
    case 128:
321
408
      debug = true;
322
409
      break;
323
410
    case ARGP_KEY_ARG:
324
 
      fprintf(stderr, "Ignoring unknown argument \"%s\"\n", arg); 
 
411
      fprintf(stderr, "Ignoring unknown argument \"%s\"\n", arg);
325
412
      break;
326
413
    case ARGP_KEY_END:
327
414
      break;
366
453
          continue;
367
454
        }
368
455
        new_arg = strdup(p);
369
 
        custom_argv = addcustomargument(custom_argv, &custom_argc, new_arg);
 
456
        custom_argv = add_to_argv(custom_argv, &custom_argc, new_arg);
370
457
        if (custom_argv == NULL){
371
 
          perror("addcustomargument");
 
458
          perror("add_to_argv");
372
459
          exitstatus = EXIT_FAILURE;
373
460
          goto end;
374
461
        }
402
489
      for(char **a = p->argv; *a != NULL; a++){
403
490
        fprintf(stderr, "\tArg: %s\n", *a);
404
491
      }
 
492
      fprintf(stderr, "...and %u environment variables\n", p->envc);
 
493
      for(char **a = p->environ; *a != NULL; a++){
 
494
        fprintf(stderr, "\t%s\n", *a);
 
495
      }
405
496
    }
406
497
  }
407
498
  
496
587
        continue;
497
588
      }
498
589
    }
499
 
    
500
 
    char *filename = malloc(d_name_len + strlen(plugindir) + 2);
501
 
    if (filename == NULL){
502
 
      perror("malloc");
 
590
 
 
591
    char *filename;
 
592
    ret = asprintf(&filename, "%s/%s", plugindir, dirst->d_name);
 
593
    if(ret < 0){
 
594
      perror("asprintf");
503
595
      continue;
504
596
    }
505
 
    strcpy(filename, plugindir); /* Spurious warning */
506
 
    strcat(filename, "/");      /* Spurious warning */
507
 
    strcat(filename, dirst->d_name); /* Spurious warning */
508
597
    
509
598
    ret = stat(filename, &st);
510
599
    if (ret == -1){
521
610
      free(filename);
522
611
      continue;
523
612
    }
524
 
    if(getplugin(dirst->d_name, &plugin_list)->disabled){
 
613
    plugin *p = getplugin(dirst->d_name, &plugin_list);
 
614
    if(p == NULL){
 
615
      perror("getplugin");
 
616
      free(filename);
 
617
      continue;
 
618
    }
 
619
    if(p->disabled){
525
620
      if(debug){
526
621
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
527
622
                dirst->d_name);
529
624
      free(filename);
530
625
      continue;
531
626
    }
532
 
    plugin *p = getplugin(dirst->d_name, &plugin_list);
533
627
    {
534
628
      /* Add global arguments to argument list for this plugin */
535
629
      plugin *g = getplugin(NULL, &plugin_list);
536
 
      for(char **a = g->argv + 1; *a != NULL; a++){
537
 
        addargument(p, *a);
538
 
      }
539
 
    }
 
630
      if(g != NULL){
 
631
        for(char **a = g->argv + 1; *a != NULL; a++){
 
632
          if(not add_argument(p, *a)){
 
633
            perror("add_argument");
 
634
          }
 
635
        }
 
636
        /* Add global environment variables */
 
637
        for(char **e = g->environ; *e != NULL; e++){
 
638
          if(not add_environment(p, *e)){
 
639
            perror("add_environment");
 
640
          }
 
641
        }
 
642
      }
 
643
    }
 
644
    /* If this plugin has any environment variables, we will call
 
645
       using execve and need to duplicate the environment from this
 
646
       process, too. */
 
647
    if(p->environ[0] != NULL){
 
648
      for(char **e = environ; *e != NULL; e++){
 
649
        char *copy = strdup(*e);
 
650
        if(copy == NULL){
 
651
          perror("strdup");
 
652
          continue;
 
653
        }
 
654
        if(not add_environment(p, copy)){
 
655
          perror("add_environment");
 
656
        }
 
657
      }
 
658
    }
 
659
    
540
660
    int pipefd[2]; 
541
661
    ret = pipe(pipefd);
542
662
    if (ret == -1){
594
714
           above and must now close it manually here. */
595
715
        closedir(dir);
596
716
      }
597
 
      if(execv(filename, p->argv) < 0){
598
 
        perror("execv");
599
 
        _exit(EXIT_FAILURE);
 
717
      if(p->environ[0] == NULL){
 
718
        if(execv(filename, p->argv) < 0){
 
719
          perror("execv");
 
720
          _exit(EXIT_FAILURE);
 
721
        }
 
722
      } else {
 
723
        if(execve(filename, p->argv, p->environ) < 0){
 
724
          perror("execve");
 
725
          _exit(EXIT_FAILURE);
 
726
        }
600
727
      }
601
728
      /* no return */
602
729
    }
640
767
  for(plugin *next; plugin_list != NULL; plugin_list = next){
641
768
    next = plugin_list->next;
642
769
    free(plugin_list->argv);
 
770
    if(plugin_list->environ[0] != NULL){
 
771
      for(char **e = plugin_list->environ; *e != NULL; e++){
 
772
        free(*e);
 
773
      }
 
774
    }
643
775
    free(plugin_list);
644
776
  }
645
777
  
783
915
  for(plugin *next; plugin_list != NULL; plugin_list = next){
784
916
    next = plugin_list->next;
785
917
    free(plugin_list->argv);
 
918
    if(plugin_list->environ[0] != NULL){
 
919
      for(char **e = plugin_list->environ; *e != NULL; e++){
 
920
        free(*e);
 
921
      }
 
922
    }
 
923
    free(plugin_list->environ);
786
924
    free(plugin_list);
787
925
  }
788
926