/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

  • Committer: Teddy Hogeborn
  • Date: 2008-08-16 03:29:08 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080816032908-ihw7c05r2mnyk389
Add feature to specify custom environment variables for plugins.

* plugin-runner.c (plugin): New members "environ" and "envc" to
                            contain possible custom environment.
  (getplugin): Return NULL on failure instead of doing exit(); all
               callers changed.
  (add_to_char_array): New helper function for "add_argument" and
                       "add_environment".
  (addargument): Renamed to "add_argument".  Return bool.  Call
                 "add_to_char_array" to actually do things.
  (add_environment): New; analogous to "add_argument".
  (addcustomargument): Renamed to "add_to_argv" to avoid confusion
                       with "add_argument".
  (main): New options "--global-envs" and "--envs-for" to specify
          custom environment for plugins.  Print environment for
          plugins in debug mode.  Use asprintf instead of strcpy and
          strcat.  Use execve() for plugins with custom environments.
          Free environment for plugin when freeing plugin list.

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(), getline() */
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,
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