/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

  • Committer: Teddy Hogeborn
  • Date: 2008-08-25 06:44:13 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080825064413-smqg5qwxfvhkeop4
* Makefile (DOCBOOKTOMAN): Only cd to one directory.

* mandos-options.xml (interface): Removed mention of a specific
                                  replaceable.
  (debug): Reworded slightly.

* mandos.conf.xml (OPTIONS): Renamed some replaceable names.

* mandos.xml (SYNOPSIS, OPTIONS): Renamed replaceable of "interface"
                                  from "IF" to "NAME".

Show diffs side-by-side

added added

removed removed

Lines of Context:
56
56
#include <argp.h>               /* struct argp_option, struct
57
57
                                   argp_state, struct argp,
58
58
                                   argp_parse(), ARGP_ERR_UNKNOWN,
59
 
                                   ARGP_KEY_END, ARGP_KEY_ARG, error_t */
 
59
                                   ARGP_KEY_END, ARGP_KEY_ARG,
 
60
                                   error_t */
60
61
#include <signal.h>             /* struct sigaction, sigemptyset(),
61
62
                                   sigaddset(), sigaction(),
62
63
                                   sigprocmask(), SIG_BLOCK, SIGCHLD,
78
79
  size_t buffer_size;
79
80
  size_t buffer_length;
80
81
  bool eof;
81
 
  bool completed;
82
 
  int status;
 
82
  volatile bool completed;
 
83
  volatile int status;
83
84
  struct process *next;
84
85
} process;
85
86
 
105
106
  if (new_plugin == NULL){
106
107
    return NULL;
107
108
  }
108
 
  *new_plugin = (plugin) { .name = name,
 
109
  char *copy_name = NULL;
 
110
  if(name != NULL){
 
111
    copy_name = strdup(name);
 
112
    if(copy_name == NULL){
 
113
      return NULL;
 
114
    }
 
115
  }
 
116
  
 
117
  *new_plugin = (plugin) { .name = copy_name,
109
118
                           .argc = 1,
110
119
                           .envc = 0,
111
120
                           .disabled = false,
113
122
  
114
123
  new_plugin->argv = malloc(sizeof(char *) * 2);
115
124
  if (new_plugin->argv == NULL){
 
125
    free(copy_name);
116
126
    free(new_plugin);
117
127
    return NULL;
118
128
  }
119
 
  new_plugin->argv[0] = name;
 
129
  new_plugin->argv[0] = copy_name;
120
130
  new_plugin->argv[1] = NULL;
121
131
 
122
132
  new_plugin->environ = malloc(sizeof(char *));
123
133
  if(new_plugin->environ == NULL){
 
134
    free(copy_name);
124
135
    free(new_plugin->argv);
125
136
    free(new_plugin);
126
137
    return NULL;
189
200
 
190
201
process *process_list = NULL;
191
202
 
192
 
/* Mark a process as completed when it exits, and save its exit
 
203
/* Mark processes as completed when they exit, and save their exit
193
204
   status. */
194
205
void handle_sigchld(__attribute__((unused)) int sig){
195
 
  process *proc = process_list;
196
 
  int status;
197
 
  pid_t pid = wait(&status);
198
 
  if(pid == -1){
199
 
    perror("wait");
200
 
    return;
201
 
  }
202
 
  while(proc != NULL and proc->pid != pid){
203
 
    proc = proc->next;
204
 
  }
205
 
  if(proc == NULL){
206
 
    /* Process not found in process list */
207
 
    return;
208
 
  }
209
 
  proc->status = status;
210
 
  proc->completed = true;
 
206
  while(true){
 
207
    process *proc = process_list;
 
208
    int status;
 
209
    pid_t pid = waitpid(-1, &status, WNOHANG);
 
210
    if(pid == 0){
 
211
      /* Only still running child processes */
 
212
      break;
 
213
    }
 
214
    if(pid == -1){
 
215
      if (errno != ECHILD){
 
216
        perror("waitpid");
 
217
      }
 
218
      /* No child processes */
 
219
      break;
 
220
    }
 
221
 
 
222
    /* A child exited, find it in process_list */
 
223
    while(proc != NULL and proc->pid != pid){
 
224
      proc = proc->next;
 
225
    }
 
226
    if(proc == NULL){
 
227
      /* Process not found in process list */
 
228
      continue;
 
229
    }
 
230
    proc->status = status;
 
231
    proc->completed = true;
 
232
  }
211
233
}
212
234
 
213
235
bool print_out_password(const char *buffer, size_t length){
232
254
    if(argv == NULL){
233
255
      return NULL;
234
256
    }
235
 
    argv[0] = NULL;     /* Will be set to argv[0] in main before parsing */
 
257
    argv[0] = NULL;     /* Will be set to argv[0] in main before
 
258
                           parsing */
236
259
    argv[1] = NULL;
237
260
  }
238
261
  *argc += 1;
242
265
    return NULL;
243
266
  }
244
267
  argv[*argc-1] = arg;
245
 
  argv[*argc] = NULL;   
 
268
  argv[*argc] = NULL;
246
269
  return argv;
247
270
}
248
271
 
 
272
static void free_plugin_list(plugin *plugin_list){
 
273
  for(plugin *next; plugin_list != NULL; plugin_list = next){
 
274
    next = plugin_list->next;
 
275
    for(char **arg = plugin_list->argv; *arg != NULL; arg++){
 
276
      free(*arg);
 
277
    }
 
278
    free(plugin_list->argv);
 
279
    for(char **env = plugin_list->environ; *env != NULL; env++){
 
280
      free(*env);
 
281
    }
 
282
    free(plugin_list->environ);
 
283
    free(plugin_list);
 
284
  }
 
285
}
 
286
 
249
287
int main(int argc, char *argv[]){
250
288
  const char *plugindir = "/lib/mandos/plugins.d";
251
289
  const char *argfile = ARGFILE;
269
307
  /* Establish a signal handler */
270
308
  sigemptyset(&sigchld_action.sa_mask);
271
309
  ret = sigaddset(&sigchld_action.sa_mask, SIGCHLD);
272
 
  if(ret < 0){
 
310
  if(ret == -1){
273
311
    perror("sigaddset");
274
 
    exit(EXIT_FAILURE);
 
312
    exitstatus = EXIT_FAILURE;
 
313
    goto fallback;
275
314
  }
276
315
  ret = sigaction(SIGCHLD, &sigchld_action, &old_sigchld_action);
277
 
  if(ret < 0){
 
316
  if(ret == -1){
278
317
    perror("sigaction");
279
 
    exit(EXIT_FAILURE);
 
318
    exitstatus = EXIT_FAILURE;
 
319
    goto fallback;
280
320
  }
281
321
  
282
322
  /* The options we understand. */
428
468
  if (ret == ARGP_ERR_UNKNOWN){
429
469
    fprintf(stderr, "Unknown error while parsing arguments\n");
430
470
    exitstatus = EXIT_FAILURE;
431
 
    goto end;
 
471
    goto fallback;
432
472
  }
433
473
 
434
474
  conffp = fopen(argfile, "r");
435
475
  if(conffp != NULL){
436
476
    char *org_line = NULL;
 
477
    char *p, *arg, *new_arg, *line;
437
478
    size_t size = 0;
438
479
    ssize_t sret;
439
 
    char *p, *arg, *new_arg, *line;
440
480
    const char whitespace_delims[] = " \r\t\f\v\n";
441
481
    const char comment_delim[] = "#";
442
482
 
457
497
        if (custom_argv == NULL){
458
498
          perror("add_to_argv");
459
499
          exitstatus = EXIT_FAILURE;
460
 
          goto end;
 
500
          goto fallback;
461
501
        }
462
502
      }
463
503
    }
468
508
    if (errno == EMFILE or errno == ENFILE or errno == ENOMEM){
469
509
      perror("fopen");
470
510
      exitstatus = EXIT_FAILURE;
471
 
      goto end;
 
511
      goto fallback;
472
512
    }
473
513
  }
474
514
 
475
515
  if(custom_argv != NULL){
476
516
    custom_argv[0] = argv[0];
477
 
    ret = argp_parse (&argp, custom_argc, custom_argv, 0, 0, &plugin_list);
 
517
    ret = argp_parse (&argp, custom_argc, custom_argv, 0, 0,
 
518
                      &plugin_list);
478
519
    if (ret == ARGP_ERR_UNKNOWN){
479
520
      fprintf(stderr, "Unknown error while parsing arguments\n");
480
521
      exitstatus = EXIT_FAILURE;
481
 
      goto end;
 
522
      goto fallback;
482
523
    }
483
524
  }
484
525
  
510
551
  if(dir == NULL){
511
552
    perror("Could not open plugin dir");
512
553
    exitstatus = EXIT_FAILURE;
513
 
    goto end;
 
554
    goto fallback;
514
555
  }
515
556
  
516
557
  /* Set the FD_CLOEXEC flag on the directory, if possible */
521
562
      if(ret < 0){
522
563
        perror("set_cloexec_flag");
523
564
        exitstatus = EXIT_FAILURE;
524
 
        goto end;
 
565
        goto fallback;
525
566
      }
526
567
    }
527
568
  }
536
577
      if (errno == EBADF){
537
578
        perror("readdir");
538
579
        exitstatus = EXIT_FAILURE;
539
 
        goto end;
 
580
        goto fallback;
540
581
      }
541
582
      break;
542
583
    }
657
698
      }
658
699
    }
659
700
    
660
 
    int pipefd[2]; 
 
701
    int pipefd[2];
661
702
    ret = pipe(pipefd);
662
703
    if (ret == -1){
663
704
      perror("pipe");
664
705
      exitstatus = EXIT_FAILURE;
665
 
      goto end;
 
706
      goto fallback;
666
707
    }
667
708
    ret = set_cloexec_flag(pipefd[0]);
668
709
    if(ret < 0){
669
710
      perror("set_cloexec_flag");
670
711
      exitstatus = EXIT_FAILURE;
671
 
      goto end;
 
712
      goto fallback;
672
713
    }
673
714
    ret = set_cloexec_flag(pipefd[1]);
674
715
    if(ret < 0){
675
716
      perror("set_cloexec_flag");
676
717
      exitstatus = EXIT_FAILURE;
677
 
      goto end;
 
718
      goto fallback;
678
719
    }
679
720
    /* Block SIGCHLD until process is safely in process list */
680
721
    ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
681
722
    if(ret < 0){
682
723
      perror("sigprocmask");
683
724
      exitstatus = EXIT_FAILURE;
684
 
      goto end;
 
725
      goto fallback;
685
726
    }
686
727
    // Starting a new process to be watched
687
728
    pid_t pid = fork();
688
729
    if(pid == -1){
689
730
      perror("fork");
690
731
      exitstatus = EXIT_FAILURE;
691
 
      goto end;
 
732
      goto fallback;
692
733
    }
693
734
    if(pid == 0){
694
735
      /* this is the child process */
738
779
        perror("sigprocmask");
739
780
      }
740
781
      exitstatus = EXIT_FAILURE;
741
 
      goto end;
 
782
      goto fallback;
742
783
    }
743
784
    
744
785
    *new_process = (struct process){ .pid = pid,
752
793
    if(ret < 0){
753
794
      perror("sigprocmask");
754
795
      exitstatus = EXIT_FAILURE;
755
 
      goto end;
 
796
      goto fallback;
756
797
    }
757
798
    
758
799
    FD_SET(new_process->fd, &rfds_all);
763
804
    
764
805
  }
765
806
  
766
 
  /* Free the plugin list */
767
 
  for(plugin *next; plugin_list != NULL; plugin_list = next){
768
 
    next = plugin_list->next;
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
 
    }
775
 
    free(plugin_list);
776
 
  }
 
807
  free_plugin_list(plugin_list);
 
808
  plugin_list = NULL;
777
809
  
778
810
  closedir(dir);
779
811
  dir = NULL;
789
821
    if (select_ret == -1){
790
822
      perror("select");
791
823
      exitstatus = EXIT_FAILURE;
792
 
      goto end;
 
824
      goto fallback;
793
825
    }
794
826
    /* OK, now either a process completed, or something can be read
795
827
       from one of them */
817
849
          /* Remove the plugin */
818
850
          FD_CLR(proc->fd, &rfds_all);
819
851
          /* Block signal while modifying process_list */
820
 
          ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
 
852
          ret = sigprocmask(SIG_BLOCK, &sigchld_action.sa_mask, NULL);
821
853
          if(ret < 0){
822
854
            perror("sigprocmask");
823
855
            exitstatus = EXIT_FAILURE;
824
 
            goto end;
 
856
            goto fallback;
825
857
          }
826
858
          /* Delete this process entry from the list */
827
859
          if(process_list == proc){
851
883
        }
852
884
        /* This process exited nicely, so print its buffer */
853
885
 
854
 
        bool bret = print_out_password(proc->buffer, proc->buffer_length);
 
886
        bool bret = print_out_password(proc->buffer,
 
887
                                       proc->buffer_length);
855
888
        if(not bret){
856
889
          perror("print_out_password");
857
890
          exitstatus = EXIT_FAILURE;
858
891
        }
859
 
        goto end;
 
892
        goto fallback;
860
893
      }
861
894
      /* This process has not completed.  Does it have any output? */
862
895
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
870
903
        if (proc->buffer == NULL){
871
904
          perror("malloc");
872
905
          exitstatus = EXIT_FAILURE;
873
 
          goto end;
 
906
          goto fallback;
874
907
        }
875
908
        proc->buffer_size += BUFFER_SIZE;
876
909
      }
891
924
  }
892
925
 
893
926
 
894
 
 end:
 
927
 fallback:
895
928
  
896
929
  if(process_list == NULL or exitstatus != EXIT_SUCCESS){
897
 
    /* Fallback if all plugins failed, none are found or an error occured */
 
930
    /* Fallback if all plugins failed, none are found or an error
 
931
       occured */
898
932
    bool bret;
899
933
    fprintf(stderr, "Going to fallback mode using getpass(3)\n");
900
934
    char *passwordbuffer = getpass("Password: ");
902
936
    if(not bret){
903
937
      perror("print_out_password");
904
938
      exitstatus = EXIT_FAILURE;
905
 
      goto end;
906
939
    }
907
940
  }
908
941
  
909
942
  /* Restore old signal handler */
910
 
  sigaction(SIGCHLD, &old_sigchld_action, NULL);
911
 
  
912
 
  free(custom_argv);
913
 
  
914
 
  /* Free the plugin list */
915
 
  for(plugin *next; plugin_list != NULL; plugin_list = next){
916
 
    next = plugin_list->next;
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
 
      }
 
943
  ret = sigaction(SIGCHLD, &old_sigchld_action, NULL);
 
944
  if(ret == -1){
 
945
    perror("sigaction");
 
946
    exitstatus = EXIT_FAILURE;
 
947
  }
 
948
 
 
949
  if(custom_argv != NULL){
 
950
    for(char **arg = custom_argv; *arg != NULL; arg++){
 
951
      free(*arg);
922
952
    }
923
 
    free(plugin_list->environ);
924
 
    free(plugin_list);
 
953
    free(custom_argv);
925
954
  }
 
955
  free_plugin_list(plugin_list);
926
956
  
927
957
  if(dir != NULL){
928
958
    closedir(dir);