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

First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Mandos plugin runner - Run Mandos plugins
4
4
 *
5
 
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
5
 * Copyright © 2008 Teddy Hogeborn
 
6
 * Copyright © 2008 Björn Påhlsson
6
7
 * 
7
8
 * This program is free software: you can redistribute it and/or
8
9
 * modify it under the terms of the GNU General Public License as
27
28
#include <stdlib.h>             /* malloc(), exit(), EXIT_FAILURE,
28
29
                                   EXIT_SUCCESS, realloc() */
29
30
#include <stdbool.h>            /* bool, true, false */
30
 
#include <stdio.h>              /* perror, popen(), fileno(),
31
 
                                   fprintf(), stderr, STDOUT_FILENO */
 
31
#include <stdio.h>              /* perror, fileno(), fprintf(),
 
32
                                   stderr, STDOUT_FILENO */
32
33
#include <sys/types.h>          /* DIR, opendir(), stat(), struct
33
34
                                   stat, waitpid(), WIFEXITED(),
34
35
                                   WEXITSTATUS(), wait(), pid_t,
46
47
                                   fcntl(), setuid(), setgid(),
47
48
                                   F_GETFD, F_SETFD, FD_CLOEXEC,
48
49
                                   access(), pipe(), fork(), close()
49
 
                                   dup2, STDOUT_FILENO, _exit(),
 
50
                                   dup2(), STDOUT_FILENO, _exit(),
50
51
                                   execv(), write(), read(),
51
52
                                   close() */
52
53
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
69
70
#define PDIR "/lib/mandos/plugins.d"
70
71
#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
71
72
 
72
 
const char *argp_program_version = "plugin-runner 1.0";
 
73
const char *argp_program_version = "plugin-runner " VERSION;
73
74
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
74
75
 
75
 
struct plugin;
76
 
 
77
76
typedef struct plugin{
78
77
  char *name;                   /* can be NULL or any plugin name */
79
78
  char **argv;
96
95
 
97
96
static plugin *plugin_list = NULL;
98
97
 
99
 
/* Gets a existing plugin based on name,
 
98
/* Gets an existing plugin based on name,
100
99
   or if none is found, creates a new one */
101
100
static plugin *getplugin(char *name){
102
101
  /* Check for exiting plugin with that name */
118
117
      return NULL;
119
118
    }
120
119
  }
121
 
 
 
120
  
122
121
  *new_plugin = (plugin) { .name = copy_name,
123
122
                           .argc = 1,
124
123
                           .disabled = false,
179
178
}
180
179
 
181
180
/* Add to a plugin's environment */
182
 
static bool add_environment(plugin *p, const char *def){
 
181
static bool add_environment(plugin *p, const char *def, bool replace){
183
182
  if(p == NULL){
184
183
    return false;
185
184
  }
187
186
  size_t namelen = (size_t)(strchrnul(def, '=') - def);
188
187
  /* Search for this environment variable */
189
188
  for(char **e = p->environ; *e != NULL; e++){
190
 
    if(strncmp(*e, def, namelen+1) == 0){
191
 
      /* Refuse to add an existing variable */
 
189
    if(strncmp(*e, def, namelen + 1) == 0){
 
190
      /* It already exists */
 
191
      if(replace){
 
192
        char *new = realloc(*e, strlen(def) + 1);
 
193
        if(new == NULL){
 
194
          return false;
 
195
        }
 
196
        *e = new;
 
197
        strcpy(*e, def);
 
198
      }
192
199
      return true;
193
200
    }
194
201
  }
200
207
 * Descriptor Flags".
201
208
 * *Note File Descriptor Flags:(libc)Descriptor Flags.
202
209
 */
203
 
static int set_cloexec_flag(int fd)
204
 
{
 
210
static int set_cloexec_flag(int fd){
205
211
  int ret = fcntl(fd, F_GETFD, 0);
206
212
  /* If reading the flags failed, return error indication now. */
207
213
  if(ret < 0){
214
220
 
215
221
/* Mark processes as completed when they exit, and save their exit
216
222
   status. */
217
 
void handle_sigchld(__attribute__((unused)) int sig){
 
223
static void handle_sigchld(__attribute__((unused)) int sig){
218
224
  while(true){
219
225
    plugin *proc = plugin_list;
220
226
    int status;
230
236
      /* No child processes */
231
237
      break;
232
238
    }
233
 
 
 
239
    
234
240
    /* A child exited, find it in process_list */
235
241
    while(proc != NULL and proc->pid != pid){
236
242
      proc = proc->next;
245
251
}
246
252
 
247
253
/* Prints out a password to stdout */
248
 
bool print_out_password(const char *buffer, size_t length){
 
254
static bool print_out_password(const char *buffer, size_t length){
249
255
  ssize_t ret;
250
 
  if(length>0 and buffer[length-1] == '\n'){
251
 
    length--;
252
 
  }
253
256
  for(size_t written = 0; written < length; written += (size_t)ret){
254
257
    ret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buffer + written,
255
258
                                   length - written));
336
339
    { .name = "global-options", .key = 'g',
337
340
      .arg = "OPTION[,OPTION[,...]]",
338
341
      .doc = "Options passed to all plugins" },
339
 
    { .name = "global-env", .key = 'e',
 
342
    { .name = "global-env", .key = 'G',
340
343
      .arg = "VAR=value",
341
344
      .doc = "Environment variable passed to all plugins" },
342
345
    { .name = "options-for", .key = 'o',
343
346
      .arg = "PLUGIN:OPTION[,OPTION[,...]]",
344
347
      .doc = "Options passed only to specified plugin" },
345
 
    { .name = "env-for", .key = 'f',
 
348
    { .name = "env-for", .key = 'E',
346
349
      .arg = "PLUGIN:ENV=value",
347
350
      .doc = "Environment variable passed to specified plugin" },
348
351
    { .name = "disable", .key = 'd',
349
352
      .arg = "PLUGIN",
350
353
      .doc = "Disable a specific plugin", .group = 1 },
 
354
    { .name = "enable", .key = 'e',
 
355
      .arg = "PLUGIN",
 
356
      .doc = "Enable a specific plugin", .group = 1 },
351
357
    { .name = "plugin-dir", .key = 128,
352
358
      .arg = "DIRECTORY",
353
359
      .doc = "Specify a different plugin directory", .group = 2 },
367
373
  
368
374
  error_t parse_opt (int key, char *arg, __attribute__((unused))
369
375
                     struct argp_state *state) {
370
 
    /* Get the INPUT argument from `argp_parse', which we know is a
371
 
       pointer to our plugin list pointer. */
372
376
    switch (key) {
373
377
    case 'g':                   /* --global-options */
374
378
      if (arg != NULL){
384
388
        }
385
389
      }
386
390
      break;
387
 
    case 'e':                   /* --global-env */
 
391
    case 'G':                   /* --global-env */
388
392
      if(arg == NULL){
389
393
        break;
390
394
      }
391
 
      {
392
 
        char *envdef = strdup(arg);
393
 
        if(envdef == NULL){
394
 
          break;
395
 
        }
396
 
        if(not add_environment(getplugin(NULL), envdef)){
397
 
          perror("add_environment");
398
 
        }
 
395
      if(not add_environment(getplugin(NULL), arg, true)){
 
396
        perror("add_environment");
399
397
      }
400
398
      break;
401
399
    case 'o':                   /* --options-for */
402
400
      if (arg != NULL){
403
401
        char *p_name = strsep(&arg, ":");
404
 
        if(p_name[0] == '\0'){
 
402
        if(p_name[0] == '\0' or arg == NULL){
405
403
          break;
406
404
        }
407
405
        char *opt = strsep(&arg, ":");
408
 
        if(opt[0] == '\0'){
 
406
        if(opt[0] == '\0' or opt == NULL){
409
407
          break;
410
408
        }
411
 
        if(opt != NULL){
412
 
          char *p;
413
 
          while((p = strsep(&opt, ",")) != NULL){
414
 
            if(p[0] == '\0'){
415
 
              continue;
416
 
            }
417
 
            if(not add_argument(getplugin(p_name), p)){
418
 
              perror("add_argument");
419
 
              return ARGP_ERR_UNKNOWN;
420
 
            }
 
409
        char *p;
 
410
        while((p = strsep(&opt, ",")) != NULL){
 
411
          if(p[0] == '\0'){
 
412
            continue;
 
413
          }
 
414
          if(not add_argument(getplugin(p_name), p)){
 
415
            perror("add_argument");
 
416
            return ARGP_ERR_UNKNOWN;
421
417
          }
422
418
        }
423
419
      }
424
420
      break;
425
 
    case 'f':                   /* --env-for */
 
421
    case 'E':                   /* --env-for */
426
422
      if(arg == NULL){
427
423
        break;
428
424
      }
431
427
        if(envdef == NULL){
432
428
          break;
433
429
        }
434
 
        char *p_name = strndup(arg, (size_t) (envdef-arg));
435
 
        if(p_name == NULL){
436
 
          break;
437
 
        }
438
 
        envdef++;
439
 
        if(not add_environment(getplugin(p_name), envdef)){
 
430
        *envdef = '\0';
 
431
        if(not add_environment(getplugin(arg), envdef+1, true)){
440
432
          perror("add_environment");
441
433
        }
442
434
      }
450
442
        p->disabled = true;
451
443
      }
452
444
      break;
 
445
    case 'e':                   /* --enable */
 
446
      if (arg != NULL){
 
447
        plugin *p = getplugin(arg);
 
448
        if(p == NULL){
 
449
          return ARGP_ERR_UNKNOWN;
 
450
        }
 
451
        p->disabled = false;
 
452
      }
 
453
      break;
453
454
    case 128:                   /* --plugin-dir */
 
455
      free(plugindir);
454
456
      plugindir = strdup(arg);
455
457
      if(plugindir == NULL){
456
458
        perror("strdup");
457
459
      }      
458
460
      break;
459
461
    case 129:                   /* --config-file */
 
462
      /* This is already done by parse_opt_config_file() */
 
463
      break;
 
464
    case 130:                   /* --userid */
 
465
      uid = (uid_t)strtol(arg, NULL, 10);
 
466
      break;
 
467
    case 131:                   /* --groupid */
 
468
      gid = (gid_t)strtol(arg, NULL, 10);
 
469
      break;
 
470
    case 132:                   /* --debug */
 
471
      debug = true;
 
472
      break;
 
473
    case ARGP_KEY_ARG:
 
474
      /* Cryptsetup always passes an argument, which is an empty
 
475
         string if "none" was specified in /etc/crypttab.  So if
 
476
         argument was empty, we ignore it silently. */
 
477
      if(arg[0] != '\0'){
 
478
        fprintf(stderr, "Ignoring unknown argument \"%s\"\n", arg);
 
479
      }
 
480
      break;
 
481
    case ARGP_KEY_END:
 
482
      break;
 
483
    default:
 
484
      return ARGP_ERR_UNKNOWN;
 
485
    }
 
486
    return 0;
 
487
  }
 
488
  
 
489
  /* This option parser is the same as parse_opt() above, except it
 
490
     ignores everything but the --config-file option. */
 
491
  error_t parse_opt_config_file (int key, char *arg,
 
492
                                 __attribute__((unused))
 
493
                                 struct argp_state *state) {
 
494
    switch (key) {
 
495
    case 'g':                   /* --global-options */
 
496
    case 'G':                   /* --global-env */
 
497
    case 'o':                   /* --options-for */
 
498
    case 'E':                   /* --env-for */
 
499
    case 'd':                   /* --disable */
 
500
    case 'e':                   /* --enable */
 
501
    case 128:                   /* --plugin-dir */
 
502
      break;
 
503
    case 129:                   /* --config-file */
 
504
      free(argfile);
460
505
      argfile = strdup(arg);
461
506
      if(argfile == NULL){
462
507
        perror("strdup");
463
508
      }
464
509
      break;      
465
510
    case 130:                   /* --userid */
466
 
      uid = (uid_t)strtol(arg, NULL, 10);
467
 
      break;
468
511
    case 131:                   /* --groupid */
469
 
      gid = (gid_t)strtol(arg, NULL, 10);
470
 
      break;
471
512
    case 132:                   /* --debug */
472
 
      debug = true;
473
 
      break;
474
513
    case ARGP_KEY_ARG:
475
 
      fprintf(stderr, "Ignoring unknown argument \"%s\"\n", arg);
476
 
      break;
477
514
    case ARGP_KEY_END:
478
515
      break;
479
516
    default:
482
519
    return 0;
483
520
  }
484
521
  
485
 
  struct argp argp = { .options = options, .parser = parse_opt,
486
 
                       .args_doc = "[+PLUS_SEPARATED_OPTIONS]",
 
522
  struct argp argp = { .options = options,
 
523
                       .parser = parse_opt_config_file,
 
524
                       .args_doc = "",
487
525
                       .doc = "Mandos plugin runner -- Run plugins" };
488
526
  
489
 
  ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
527
  /* Parse using the parse_opt_config_file in order to get the custom
 
528
     config file location, if any. */
 
529
  ret = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
490
530
  if (ret == ARGP_ERR_UNKNOWN){
491
531
    fprintf(stderr, "Unknown error while parsing arguments\n");
492
532
    exitstatus = EXIT_FAILURE;
493
533
    goto fallback;
494
534
  }
495
 
 
496
 
  /* Opens the configfile if aviable */
 
535
  
 
536
  /* Reset to the normal argument parser */
 
537
  argp.parser = parse_opt;
 
538
  
 
539
  /* Open the configfile if available */
497
540
  if (argfile == NULL){
498
541
    conffp = fopen(AFILE, "r");
499
542
  } else {
553
596
      }
554
597
    }
555
598
    free(org_line);
556
 
  } else{
 
599
  } else {
557
600
    /* Check for harmful errors and go to fallback. Other errors might
558
601
       not affect opening plugins */
559
602
    if (errno == EMFILE or errno == ENFILE or errno == ENOMEM){
565
608
  /* If there was any arguments from configuration file,
566
609
     pass them to parser as command arguments */
567
610
  if(custom_argv != NULL){
568
 
    ret = argp_parse (&argp, custom_argc, custom_argv, 0, 0, NULL);
 
611
    ret = argp_parse (&argp, custom_argc, custom_argv, ARGP_IN_ORDER,
 
612
                      0, NULL);
569
613
    if (ret == ARGP_ERR_UNKNOWN){
570
614
      fprintf(stderr, "Unknown error while parsing arguments\n");
571
615
      exitstatus = EXIT_FAILURE;
573
617
    }
574
618
  }
575
619
  
 
620
  /* Parse actual command line arguments, to let them override the
 
621
     config file */
 
622
  ret = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
 
623
  if (ret == ARGP_ERR_UNKNOWN){
 
624
    fprintf(stderr, "Unknown error while parsing arguments\n");
 
625
    exitstatus = EXIT_FAILURE;
 
626
    goto fallback;
 
627
  }
 
628
  
576
629
  if(debug){
577
630
    for(plugin *p = plugin_list; p != NULL; p=p->next){
578
631
      fprintf(stderr, "Plugin: %s has %d arguments\n",
586
639
      }
587
640
    }
588
641
  }
589
 
 
 
642
  
590
643
  /* Strip permissions down to nobody */
591
644
  ret = setuid(uid);
592
645
  if (ret == -1){
596
649
  if (ret == -1){
597
650
    perror("setgid");
598
651
  }
599
 
 
 
652
  
600
653
  if (plugindir == NULL){
601
654
    dir = opendir(PDIR);
602
655
  } else {
623
676
  }
624
677
  
625
678
  FD_ZERO(&rfds_all);
626
 
 
 
679
  
627
680
  /* Read and execute any executable in the plugin directory*/
628
681
  while(true){
629
682
    dirst = readdir(dir);
630
683
    
631
 
    // All directory entries have been processed
 
684
    /* All directory entries have been processed */
632
685
    if(dirst == NULL){
633
686
      if (errno == EBADF){
634
687
        perror("readdir");
640
693
    
641
694
    d_name_len = strlen(dirst->d_name);
642
695
    
643
 
    // Ignore dotfiles, backup files and other junk
 
696
    /* Ignore dotfiles, backup files and other junk */
644
697
    {
645
698
      bool bad_name = false;
646
699
      
648
701
      
649
702
      const char const *bad_suffixes[] = { "~", "#", ".dpkg-new",
650
703
                                           ".dpkg-old",
 
704
                                           ".dpkg-bak",
651
705
                                           ".dpkg-divert", NULL };
652
706
      for(const char **pre = bad_prefixes; *pre != NULL; pre++){
653
707
        size_t pre_len = strlen(*pre);
684
738
    }
685
739
 
686
740
    char *filename;
687
 
    ret = asprintf(&filename, "%s/%s", plugindir, dirst->d_name);
 
741
    if(plugindir == NULL){
 
742
      ret = asprintf(&filename, PDIR "/%s", dirst->d_name);
 
743
    } else {
 
744
      ret = asprintf(&filename, "%s/%s", plugindir, dirst->d_name);
 
745
    }
688
746
    if(ret < 0){
689
747
      perror("asprintf");
690
748
      continue;
732
790
        }
733
791
        /* Add global environment variables */
734
792
        for(char **e = g->environ; *e != NULL; e++){
735
 
          if(not add_environment(p, *e)){
 
793
          if(not add_environment(p, *e, false)){
736
794
            perror("add_environment");
737
795
          }
738
796
        }
743
801
       process, too. */
744
802
    if(p->environ[0] != NULL){
745
803
      for(char **e = environ; *e != NULL; e++){
746
 
        char *copy = strdup(*e);
747
 
        if(copy == NULL){
748
 
          perror("strdup");
749
 
          continue;
750
 
        }
751
 
        if(not add_environment(p, copy)){
 
804
        if(not add_environment(p, *e, false)){
752
805
          perror("add_environment");
753
806
        }
754
807
      }
781
834
      exitstatus = EXIT_FAILURE;
782
835
      goto fallback;
783
836
    }
784
 
    // Starting a new process to be watched
 
837
    /* Starting a new process to be watched */
785
838
    pid_t pid = fork();
786
839
    if(pid == -1){
787
840
      perror("fork");
795
848
        perror("sigaction");
796
849
        _exit(EXIT_FAILURE);
797
850
      }
798
 
      ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
 
851
      ret = sigprocmask(SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
799
852
      if(ret < 0){
800
853
        perror("sigprocmask");
801
854
        _exit(EXIT_FAILURE);
802
855
      }
803
 
 
 
856
      
804
857
      ret = dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
805
858
      if(ret == -1){
806
859
        perror("dup2");
856
909
    if (maxfd < new_plugin->fd){
857
910
      maxfd = new_plugin->fd;
858
911
    }
859
 
    
860
912
  }
861
913
  
862
914
  closedir(dir);
863
915
  dir = NULL;
864
 
 
 
916
  
865
917
  for(plugin *p = plugin_list; p != NULL; p = p->next){
866
918
    if(p->pid != 0){
867
919
      break;
872
924
      free_plugin_list();
873
925
    }
874
926
  }
875
 
 
 
927
  
876
928
  /* Main loop while running plugins exist */
877
929
  while(plugin_list){
878
930
    fd_set rfds = rfds_all;
884
936
    }
885
937
    /* OK, now either a process completed, or something can be read
886
938
       from one of them */
887
 
    for(plugin *proc = plugin_list; proc != NULL; proc = proc->next){
 
939
    for(plugin *proc = plugin_list; proc != NULL;){
888
940
      /* Is this process completely done? */
889
941
      if(proc->eof and proc->completed){
890
942
        /* Only accept the plugin output if it exited cleanly */
917
969
            exitstatus = EXIT_FAILURE;
918
970
            goto fallback;
919
971
          }
 
972
          
 
973
          plugin *next_plugin = proc->next;
920
974
          free_plugin(proc);
 
975
          proc = next_plugin;
 
976
          
921
977
          /* We are done modifying process list, so unblock signal */
922
978
          ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask,
923
979
                             NULL);
930
986
          if(plugin_list == NULL){
931
987
            break;
932
988
          }
 
989
          
933
990
          continue;
934
991
        }
935
992
        
936
993
        /* This process exited nicely, so print its buffer */
937
 
 
 
994
        
938
995
        bool bret = print_out_password(proc->buffer,
939
996
                                       proc->buffer_length);
940
997
        if(not bret){
947
1004
      /* This process has not completed.  Does it have any output? */
948
1005
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
949
1006
        /* This process had nothing to say at this time */
 
1007
        proc = proc->next;
950
1008
        continue;
951
1009
      }
952
1010
      /* Before reading, make the process' data buffer large enough */
965
1023
                 BUFFER_SIZE);
966
1024
      if(ret < 0){
967
1025
        /* Read error from this process; ignore the error */
 
1026
        proc = proc->next;
968
1027
        continue;
969
1028
      }
970
1029
      if(ret == 0){
985
1044
    bool bret;
986
1045
    fprintf(stderr, "Going to fallback mode using getpass(3)\n");
987
1046
    char *passwordbuffer = getpass("Password: ");
988
 
    bret = print_out_password(passwordbuffer, strlen(passwordbuffer));
 
1047
    size_t len = strlen(passwordbuffer);
 
1048
    /* Strip trailing newline */
 
1049
    if(len > 0 and passwordbuffer[len-1] == '\n'){
 
1050
      passwordbuffer[len-1] = '\0'; /* not strictly necessary */
 
1051
      len--;
 
1052
    }
 
1053
    bret = print_out_password(passwordbuffer, len);
989
1054
    if(not bret){
990
1055
      perror("print_out_password");
991
1056
      exitstatus = EXIT_FAILURE;
998
1063
    perror("sigaction");
999
1064
    exitstatus = EXIT_FAILURE;
1000
1065
  }
1001
 
 
 
1066
  
1002
1067
  if(custom_argv != NULL){
1003
1068
    for(char **arg = custom_argv+1; *arg != NULL; arg++){
1004
1069
      free(*arg);
1010
1075
    closedir(dir);
1011
1076
  }
1012
1077
  
1013
 
  /* Free the process list and kill the processes */
 
1078
  /* Kill the processes */
1014
1079
  for(plugin *p = plugin_list; p != NULL; p = p->next){
1015
1080
    if(p->pid != 0){
1016
1081
      close(p->fd);
1029
1094
  if(errno != ECHILD){
1030
1095
    perror("wait");
1031
1096
  }
1032
 
 
 
1097
  
1033
1098
  free_plugin_list();
1034
1099
  
1035
1100
  free(plugindir);