/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 16:58:31 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080816165831-cx018vo5i9oqmgo0
* plugins.d/password-request.c (main): Include environment variables
                                       "cryptsource" and "crypttarget"
                                       in password prompt.

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