/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() */
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>             /* strtok, 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
 
67
#define ARGFILE "/conf/conf.d/mandos/plugin-runner.conf"
68
68
 
69
 
const char *argp_program_version = "plugbasedclient 1.0";
 
69
const char *argp_program_version = "plugin-runner 1.0";
70
70
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
71
71
 
72
72
struct process;
87
87
  char *name;                   /* can be NULL or any plugin name */
88
88
  char **argv;
89
89
  int argc;
 
90
  char **environ;
 
91
  int envc;
90
92
  bool disabled;
91
93
  struct plugin *next;
92
94
} plugin;
101
103
  /* Create a new plugin */
102
104
  plugin *new_plugin = malloc(sizeof(plugin));
103
105
  if (new_plugin == NULL){
104
 
    perror("malloc");
105
 
    exit(EXIT_FAILURE);
 
106
    return NULL;
106
107
  }
107
 
  new_plugin->name = name;
 
108
  *new_plugin = (plugin) { .name = name,
 
109
                           .argc = 1,
 
110
                           .envc = 0,
 
111
                           .disabled = false,
 
112
                           .next = *plugin_list };
 
113
  
108
114
  new_plugin->argv = malloc(sizeof(char *) * 2);
109
115
  if (new_plugin->argv == NULL){
110
 
    perror("malloc");
111
 
    exit(EXIT_FAILURE);
 
116
    free(new_plugin);
 
117
    return NULL;
112
118
  }
113
119
  new_plugin->argv[0] = name;
114
120
  new_plugin->argv[1] = NULL;
115
 
  new_plugin->argc = 1;
116
 
  new_plugin->disabled = false;
117
 
  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;
118
129
  /* Append the new plugin to the list */
119
130
  *plugin_list = new_plugin;
120
131
  return new_plugin;
121
132
}
122
133
 
123
 
static void addargument(plugin *p, char *arg){
124
 
  p->argv[p->argc] = arg;
125
 
  p->argv = realloc(p->argv, sizeof(char *) * (size_t)(p->argc + 2));
126
 
  if (p->argv == NULL){
127
 
    perror("malloc");
128
 
    exit(EXIT_FAILURE);
129
 
  }
130
 
  p->argc++;
131
 
  p->argv[p->argc] = NULL;
132
 
}
 
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
 
133
173
 
134
174
/*
135
175
 * Based on the example in the GNU LibC manual chapter 13.13 "File
170
210
  proc->completed = true;
171
211
}
172
212
 
 
213
bool print_out_password(const char *buffer, size_t length){
 
214
  ssize_t ret;
 
215
  if(length>0 and buffer[length-1] == '\n'){
 
216
    length--;
 
217
  }
 
218
  for(size_t written = 0; written < length; written += (size_t)ret){
 
219
    ret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buffer + written,
 
220
                                   length - written));
 
221
    if(ret < 0){
 
222
      return false;
 
223
    }
 
224
  }
 
225
  return true;
 
226
}
 
227
 
 
228
char **add_to_argv(char **argv, int *argc, char *arg){
 
229
  if (argv == NULL){
 
230
    *argc = 1;
 
231
    argv = malloc(sizeof(char*) * 2);
 
232
    if(argv == NULL){
 
233
      return NULL;
 
234
    }
 
235
    argv[0] = NULL;     /* Will be set to argv[0] in main before parsing */
 
236
    argv[1] = NULL;
 
237
  }
 
238
  *argc += 1;
 
239
  argv = realloc(argv, sizeof(char *)
 
240
                  * ((unsigned int) *argc + 1));
 
241
  if(argv == NULL){
 
242
    return NULL;
 
243
  }
 
244
  argv[*argc-1] = arg;
 
245
  argv[*argc] = NULL;   
 
246
  return argv;
 
247
}
 
248
 
173
249
int main(int argc, char *argv[]){
174
 
  const char *plugindir = "/conf/conf.d/mandos/plugins.d";
 
250
  const char *plugindir = "/lib/mandos/plugins.d";
 
251
  const char *argfile = ARGFILE;
 
252
  FILE *conffp;
175
253
  size_t d_name_len;
176
254
  DIR *dir = NULL;
177
255
  struct dirent *dirst;
185
263
  struct sigaction old_sigchld_action;
186
264
  struct sigaction sigchld_action = { .sa_handler = handle_sigchld,
187
265
                                      .sa_flags = SA_NOCLDSTOP };
188
 
  char *plus_options = NULL;
189
 
  char **plus_argv = NULL;
 
266
  char **custom_argv = NULL;
 
267
  int custom_argc = 0;
190
268
  
191
269
  /* Establish a signal handler */
192
270
  sigemptyset(&sigchld_action.sa_mask);
206
284
    { .name = "global-options", .key = 'g',
207
285
      .arg = "OPTION[,OPTION[,...]]",
208
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" },
209
290
    { .name = "options-for", .key = 'o',
210
291
      .arg = "PLUGIN:OPTION[,OPTION[,...]]",
211
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" },
212
296
    { .name = "disable", .key = 'd',
213
297
      .arg = "PLUGIN",
214
298
      .doc = "Disable a specific plugin", .group = 1 },
233
317
    switch (key) {
234
318
    case 'g':
235
319
      if (arg != NULL){
236
 
        char *p = strtok(arg, ",");
237
 
        do{
238
 
          addargument(getplugin(NULL, plugins), p);
239
 
          p = strtok(NULL, ",");
240
 
        } while (p != NULL);
 
320
        char *p;
 
321
        while((p = strsep(&arg, ",")) != NULL){
 
322
          if(p[0] == '\0'){
 
323
            continue;
 
324
          }
 
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");
 
343
        }
241
344
      }
242
345
      break;
243
346
    case 'o':
244
347
      if (arg != NULL){
245
 
        char *name = strtok(arg, ":");
246
 
        char *p = strtok(NULL, ":");
247
 
        if(p != NULL){
248
 
          p = strtok(p, ",");
249
 
          do{
250
 
            addargument(getplugin(name, plugins), p);
251
 
            p = strtok(NULL, ",");
252
 
          } while (p != NULL);
 
348
        char *p_name = strsep(&arg, ":");
 
349
        if(p_name[0] == '\0'){
 
350
          break;
 
351
        }
 
352
        char *opt = strsep(&arg, ":");
 
353
        if(opt[0] == '\0'){
 
354
          break;
 
355
        }
 
356
        if(opt != NULL){
 
357
          char *p;
 
358
          while((p = strsep(&opt, ",")) != NULL){
 
359
            if(p[0] == '\0'){
 
360
              continue;
 
361
            }
 
362
            if(not add_argument(getplugin(p_name, plugins), p)){
 
363
              perror("add_argument");
 
364
              return ARGP_ERR_UNKNOWN;
 
365
            }
 
366
          }
 
367
        }
 
368
      }
 
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");
253
386
        }
254
387
      }
255
388
      break;
256
389
    case 'd':
257
390
      if (arg != NULL){
258
 
        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;
259
396
      }
260
397
      break;
261
398
    case 128:
271
408
      debug = true;
272
409
      break;
273
410
    case ARGP_KEY_ARG:
274
 
      if(plus_options != NULL or arg == NULL or arg[0] != '+'){
275
 
        argp_usage (state);
276
 
      }
277
 
      plus_options = arg;
 
411
      fprintf(stderr, "Ignoring unknown argument \"%s\"\n", arg);
278
412
      break;
279
413
    case ARGP_KEY_END:
280
414
      break;
292
426
  
293
427
  ret = argp_parse (&argp, argc, argv, 0, 0, &plugin_list);
294
428
  if (ret == ARGP_ERR_UNKNOWN){
295
 
    fprintf(stderr, "Unkown error while parsing arguments\n");
 
429
    fprintf(stderr, "Unknown error while parsing arguments\n");
296
430
    exitstatus = EXIT_FAILURE;
297
431
    goto end;
298
432
  }
299
 
  
300
 
  if(plus_options){
301
 
    /* This is a mangled argument in the form of
302
 
     "+--option+--other-option=parameter+--yet-another-option", etc */
303
 
    /* Make new argc and argv vars, and call argp_parse() again. */
304
 
    plus_options++;             /* skip the first '+' character */
305
 
    const char delims[] = "+";
306
 
    char *arg;
307
 
    int new_argc = 1;
308
 
    plus_argv = malloc(sizeof(char*) * 2);
309
 
    if(plus_argv == NULL){
310
 
      perror("malloc");
 
433
 
 
434
  conffp = fopen(argfile, "r");
 
435
  if(conffp != NULL){
 
436
    char *org_line = NULL;
 
437
    size_t size = 0;
 
438
    ssize_t sret;
 
439
    char *p, *arg, *new_arg, *line;
 
440
    const char whitespace_delims[] = " \r\t\f\v\n";
 
441
    const char comment_delim[] = "#";
 
442
 
 
443
    while(true){
 
444
      sret = getline(&org_line, &size, conffp);
 
445
      if(sret == -1){
 
446
        break;
 
447
      }
 
448
 
 
449
      line = org_line;
 
450
      arg = strsep(&line, comment_delim);
 
451
      while((p = strsep(&arg, whitespace_delims)) != NULL){
 
452
        if(p[0] == '\0'){
 
453
          continue;
 
454
        }
 
455
        new_arg = strdup(p);
 
456
        custom_argv = add_to_argv(custom_argv, &custom_argc, new_arg);
 
457
        if (custom_argv == NULL){
 
458
          perror("add_to_argv");
 
459
          exitstatus = EXIT_FAILURE;
 
460
          goto end;
 
461
        }
 
462
      }
 
463
    }
 
464
    free(org_line);
 
465
  } else{
 
466
    /* Check for harmful errors and go to fallback. Other errors might
 
467
       not affect opening plugins */
 
468
    if (errno == EMFILE or errno == ENFILE or errno == ENOMEM){
 
469
      perror("fopen");
311
470
      exitstatus = EXIT_FAILURE;
312
471
      goto end;
313
472
    }
314
 
    plus_argv[0] = argv[0];
315
 
    plus_argv[1] = NULL;
316
 
    arg = strtok(plus_options, delims); /* Get first argument */
317
 
    while(arg != NULL){
318
 
      new_argc++;
319
 
      plus_argv = realloc(plus_argv, sizeof(char *)
320
 
                         * ((unsigned int) new_argc + 1));
321
 
      if(plus_argv == NULL){
322
 
        perror("realloc");
323
 
        exitstatus = EXIT_FAILURE;
324
 
        goto end;
325
 
      }
326
 
      plus_argv[new_argc-1] = arg;
327
 
      plus_argv[new_argc] = NULL;
328
 
      arg = strtok(NULL, delims); /* Get next argument */
329
 
    }
330
 
    ret = argp_parse (&argp, new_argc, plus_argv, 0, 0, &plugin_list);
 
473
  }
 
474
 
 
475
  if(custom_argv != NULL){
 
476
    custom_argv[0] = argv[0];
 
477
    ret = argp_parse (&argp, custom_argc, custom_argv, 0, 0, &plugin_list);
331
478
    if (ret == ARGP_ERR_UNKNOWN){
332
 
      fprintf(stderr, "Unkown error while parsing arguments\n");
 
479
      fprintf(stderr, "Unknown error while parsing arguments\n");
333
480
      exitstatus = EXIT_FAILURE;
334
481
      goto end;
335
482
    }
342
489
      for(char **a = p->argv; *a != NULL; a++){
343
490
        fprintf(stderr, "\tArg: %s\n", *a);
344
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
      }
345
496
    }
346
497
  }
347
498
  
436
587
        continue;
437
588
      }
438
589
    }
439
 
    
440
 
    char *filename = malloc(d_name_len + strlen(plugindir) + 2);
441
 
    if (filename == NULL){
442
 
      perror("malloc");
443
 
      exitstatus = EXIT_FAILURE;
444
 
      goto end;
 
590
 
 
591
    char *filename;
 
592
    ret = asprintf(&filename, "%s/%s", plugindir, dirst->d_name);
 
593
    if(ret < 0){
 
594
      perror("asprintf");
 
595
      continue;
445
596
    }
446
 
    strcpy(filename, plugindir); /* Spurious warning */
447
 
    strcat(filename, "/");      /* Spurious warning */
448
 
    strcat(filename, dirst->d_name); /* Spurious warning */
449
597
    
450
598
    ret = stat(filename, &st);
451
599
    if (ret == -1){
452
600
      perror("stat");
453
 
      exitstatus = EXIT_FAILURE;
454
 
      goto end;
 
601
      free(filename);
 
602
      continue;
455
603
    }
456
604
    
457
605
    if (not S_ISREG(st.st_mode) or (access(filename, X_OK) != 0)){
462
610
      free(filename);
463
611
      continue;
464
612
    }
465
 
    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){
466
620
      if(debug){
467
621
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
468
622
                dirst->d_name);
470
624
      free(filename);
471
625
      continue;
472
626
    }
473
 
    plugin *p = getplugin(dirst->d_name, &plugin_list);
474
627
    {
475
628
      /* Add global arguments to argument list for this plugin */
476
629
      plugin *g = getplugin(NULL, &plugin_list);
477
 
      for(char **a = g->argv + 1; *a != NULL; a++){
478
 
        addargument(p, *a);
479
 
      }
480
 
    }
 
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
    
481
660
    int pipefd[2]; 
482
661
    ret = pipe(pipefd);
483
662
    if (ret == -1){
506
685
    }
507
686
    // Starting a new process to be watched
508
687
    pid_t pid = fork();
 
688
    if(pid == -1){
 
689
      perror("fork");
 
690
      exitstatus = EXIT_FAILURE;
 
691
      goto end;
 
692
    }
509
693
    if(pid == 0){
510
694
      /* this is the child process */
511
695
      ret = sigaction(SIGCHLD, &old_sigchld_action, NULL);
530
714
           above and must now close it manually here. */
531
715
        closedir(dir);
532
716
      }
533
 
      if(execv(filename, p->argv) < 0){
534
 
        perror("execv");
535
 
        _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
        }
536
727
      }
537
728
      /* no return */
538
729
    }
576
767
  for(plugin *next; plugin_list != NULL; plugin_list = next){
577
768
    next = plugin_list->next;
578
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
    }
579
775
    free(plugin_list);
580
776
  }
581
777
  
583
779
  dir = NULL;
584
780
    
585
781
  if (process_list == NULL){
586
 
    fprintf(stderr, "No plugin processes started, exiting\n");
587
 
    exitstatus = EXIT_FAILURE;
588
 
    goto end;
 
782
    fprintf(stderr, "No plugin processes started. Incorrect plugin"
 
783
            " directory?\n");
 
784
    process_list = NULL;
589
785
  }
590
786
  while(process_list){
591
787
    fd_set rfds = rfds_all;
606
802
          /* Bad exit by plugin */
607
803
          if(debug){
608
804
            if(WIFEXITED(proc->status)){
609
 
              fprintf(stderr, "Plugin %d exited with status %d\n",
610
 
                      proc->pid, WEXITSTATUS(proc->status));
 
805
              fprintf(stderr, "Plugin %u exited with status %d\n",
 
806
                      (unsigned int) (proc->pid),
 
807
                      WEXITSTATUS(proc->status));
611
808
            } else if(WIFSIGNALED(proc->status)) {
612
 
              fprintf(stderr, "Plugin %d killed by signal %d\n",
613
 
                      proc->pid, WTERMSIG(proc->status));
 
809
              fprintf(stderr, "Plugin %u killed by signal %d\n",
 
810
                      (unsigned int) (proc->pid),
 
811
                      WTERMSIG(proc->status));
614
812
            } else if(WCOREDUMP(proc->status)){
615
 
              fprintf(stderr, "Plugin %d dumped core\n", proc->pid);
 
813
              fprintf(stderr, "Plugin %d dumped core\n",
 
814
                      (unsigned int) (proc->pid));
616
815
            }
617
816
          }
618
817
          /* Remove the plugin */
651
850
          break;
652
851
        }
653
852
        /* This process exited nicely, so print its buffer */
654
 
        for(size_t written = 0; written < proc->buffer_length;
655
 
            written += (size_t)ret){
656
 
          ret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO,
657
 
                                         proc->buffer + written,
658
 
                                         proc->buffer_length
659
 
                                         - written));
660
 
          if(ret < 0){
661
 
            perror("write");
662
 
            exitstatus = EXIT_FAILURE;
663
 
            goto end;
664
 
          }
 
853
 
 
854
        bool bret = print_out_password(proc->buffer, proc->buffer_length);
 
855
        if(not bret){
 
856
          perror("print_out_password");
 
857
          exitstatus = EXIT_FAILURE;
665
858
        }
666
859
        goto end;
667
860
      }
696
889
      }
697
890
    }
698
891
  }
699
 
  if(process_list == NULL){
700
 
    fprintf(stderr, "All plugin processes failed, exiting\n");
701
 
    exitstatus = EXIT_FAILURE;
702
 
  }
703
 
  
 
892
 
 
893
 
704
894
 end:
 
895
  
 
896
  if(process_list == NULL or exitstatus != EXIT_SUCCESS){
 
897
    /* Fallback if all plugins failed, none are found or an error occured */
 
898
    bool bret;
 
899
    fprintf(stderr, "Going to fallback mode using getpass(3)\n");
 
900
    char *passwordbuffer = getpass("Password: ");
 
901
    bret = print_out_password(passwordbuffer, strlen(passwordbuffer));
 
902
    if(not bret){
 
903
      perror("print_out_password");
 
904
      exitstatus = EXIT_FAILURE;
 
905
      goto end;
 
906
    }
 
907
  }
 
908
  
705
909
  /* Restore old signal handler */
706
910
  sigaction(SIGCHLD, &old_sigchld_action, NULL);
707
911
  
708
 
  free(plus_argv);
 
912
  free(custom_argv);
709
913
  
710
914
  /* Free the plugin list */
711
915
  for(plugin *next; plugin_list != NULL; plugin_list = next){
712
916
    next = plugin_list->next;
713
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);
714
924
    free(plugin_list);
715
925
  }
716
926