/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:
105
105
  if (new_plugin == NULL){
106
106
    return NULL;
107
107
  }
108
 
  char *copy_name = strdup(name);
109
 
  if(copy_name == NULL){
110
 
    return NULL;
111
 
  }
112
 
  
113
 
  *new_plugin = (plugin) { .name = copy_name,
 
108
  *new_plugin = (plugin) { .name = name,
114
109
                           .argc = 1,
115
110
                           .envc = 0,
116
111
                           .disabled = false,
121
116
    free(new_plugin);
122
117
    return NULL;
123
118
  }
124
 
  new_plugin->argv[0] = copy_name;
 
119
  new_plugin->argv[0] = name;
125
120
  new_plugin->argv[1] = NULL;
126
121
 
127
122
  new_plugin->environ = malloc(sizeof(char *));
251
246
  return argv;
252
247
}
253
248
 
254
 
static void free_plugin_list(plugin *plugin_list){
255
 
  for(plugin *next = plugin_list; plugin_list != NULL; plugin_list = next){
256
 
    next = plugin_list->next;
257
 
    free(plugin_list->name);
258
 
    for(char **arg = plugin_list->argv; *arg != NULL; arg++){
259
 
      free(*arg);
260
 
    }    
261
 
    free(plugin_list->argv);
262
 
    for(char **env = plugin_list->environ; *env != NULL; env++){
263
 
      free(*env);
264
 
    }
265
 
    free(plugin_list->environ);
266
 
    free(plugin_list);
267
 
  }  
268
 
}
269
 
 
270
249
int main(int argc, char *argv[]){
271
250
  const char *plugindir = "/lib/mandos/plugins.d";
272
251
  const char *argfile = ARGFILE;
290
269
  /* Establish a signal handler */
291
270
  sigemptyset(&sigchld_action.sa_mask);
292
271
  ret = sigaddset(&sigchld_action.sa_mask, SIGCHLD);
293
 
  if(ret == -1){
 
272
  if(ret < 0){
294
273
    perror("sigaddset");
295
 
    exitstatus = EXIT_FAILURE;
296
 
    goto fallback;
 
274
    exit(EXIT_FAILURE);
297
275
  }
298
276
  ret = sigaction(SIGCHLD, &sigchld_action, &old_sigchld_action);
299
 
  if(ret == -1){
 
277
  if(ret < 0){
300
278
    perror("sigaction");
301
 
    exitstatus = EXIT_FAILURE;    
302
 
    goto fallback;
 
279
    exit(EXIT_FAILURE);
303
280
  }
304
281
  
305
282
  /* The options we understand. */
451
428
  if (ret == ARGP_ERR_UNKNOWN){
452
429
    fprintf(stderr, "Unknown error while parsing arguments\n");
453
430
    exitstatus = EXIT_FAILURE;
454
 
    goto fallback;
 
431
    goto end;
455
432
  }
456
433
 
457
434
  conffp = fopen(argfile, "r");
458
435
  if(conffp != NULL){
459
436
    char *org_line = NULL;
460
 
    char *p, *arg, *new_arg, *line;
461
437
    size_t size = 0;
462
438
    ssize_t sret;
 
439
    char *p, *arg, *new_arg, *line;
463
440
    const char whitespace_delims[] = " \r\t\f\v\n";
464
441
    const char comment_delim[] = "#";
465
442
 
480
457
        if (custom_argv == NULL){
481
458
          perror("add_to_argv");
482
459
          exitstatus = EXIT_FAILURE;
483
 
          goto fallback;
 
460
          goto end;
484
461
        }
485
462
      }
486
463
    }
491
468
    if (errno == EMFILE or errno == ENFILE or errno == ENOMEM){
492
469
      perror("fopen");
493
470
      exitstatus = EXIT_FAILURE;
494
 
      goto fallback;
 
471
      goto end;
495
472
    }
496
473
  }
497
474
 
501
478
    if (ret == ARGP_ERR_UNKNOWN){
502
479
      fprintf(stderr, "Unknown error while parsing arguments\n");
503
480
      exitstatus = EXIT_FAILURE;
504
 
      goto fallback;
 
481
      goto end;
505
482
    }
506
483
  }
507
484
  
533
510
  if(dir == NULL){
534
511
    perror("Could not open plugin dir");
535
512
    exitstatus = EXIT_FAILURE;
536
 
    goto fallback;
 
513
    goto end;
537
514
  }
538
515
  
539
516
  /* Set the FD_CLOEXEC flag on the directory, if possible */
544
521
      if(ret < 0){
545
522
        perror("set_cloexec_flag");
546
523
        exitstatus = EXIT_FAILURE;
547
 
        goto fallback;
 
524
        goto end;
548
525
      }
549
526
    }
550
527
  }
559
536
      if (errno == EBADF){
560
537
        perror("readdir");
561
538
        exitstatus = EXIT_FAILURE;
562
 
        goto fallback;
 
539
        goto end;
563
540
      }
564
541
      break;
565
542
    }
685
662
    if (ret == -1){
686
663
      perror("pipe");
687
664
      exitstatus = EXIT_FAILURE;
688
 
      goto fallback;
 
665
      goto end;
689
666
    }
690
667
    ret = set_cloexec_flag(pipefd[0]);
691
668
    if(ret < 0){
692
669
      perror("set_cloexec_flag");
693
670
      exitstatus = EXIT_FAILURE;
694
 
      goto fallback;
 
671
      goto end;
695
672
    }
696
673
    ret = set_cloexec_flag(pipefd[1]);
697
674
    if(ret < 0){
698
675
      perror("set_cloexec_flag");
699
676
      exitstatus = EXIT_FAILURE;
700
 
      goto fallback;
 
677
      goto end;
701
678
    }
702
679
    /* Block SIGCHLD until process is safely in process list */
703
680
    ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
704
681
    if(ret < 0){
705
682
      perror("sigprocmask");
706
683
      exitstatus = EXIT_FAILURE;
707
 
      goto fallback;
 
684
      goto end;
708
685
    }
709
686
    // Starting a new process to be watched
710
687
    pid_t pid = fork();
711
688
    if(pid == -1){
712
689
      perror("fork");
713
690
      exitstatus = EXIT_FAILURE;
714
 
      goto fallback;
 
691
      goto end;
715
692
    }
716
693
    if(pid == 0){
717
694
      /* this is the child process */
761
738
        perror("sigprocmask");
762
739
      }
763
740
      exitstatus = EXIT_FAILURE;
764
 
      goto fallback;
 
741
      goto end;
765
742
    }
766
743
    
767
744
    *new_process = (struct process){ .pid = pid,
775
752
    if(ret < 0){
776
753
      perror("sigprocmask");
777
754
      exitstatus = EXIT_FAILURE;
778
 
      goto fallback;
 
755
      goto end;
779
756
    }
780
757
    
781
758
    FD_SET(new_process->fd, &rfds_all);
786
763
    
787
764
  }
788
765
  
789
 
  free_plugin_list(plugin_list);
 
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
  }
790
777
  
791
778
  closedir(dir);
792
779
  dir = NULL;
802
789
    if (select_ret == -1){
803
790
      perror("select");
804
791
      exitstatus = EXIT_FAILURE;
805
 
      goto fallback;
 
792
      goto end;
806
793
    }
807
794
    /* OK, now either a process completed, or something can be read
808
795
       from one of them */
834
821
          if(ret < 0){
835
822
            perror("sigprocmask");
836
823
            exitstatus = EXIT_FAILURE;
837
 
            goto fallback;
 
824
            goto end;
838
825
          }
839
826
          /* Delete this process entry from the list */
840
827
          if(process_list == proc){
869
856
          perror("print_out_password");
870
857
          exitstatus = EXIT_FAILURE;
871
858
        }
872
 
        goto fallback;
 
859
        goto end;
873
860
      }
874
861
      /* This process has not completed.  Does it have any output? */
875
862
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
883
870
        if (proc->buffer == NULL){
884
871
          perror("malloc");
885
872
          exitstatus = EXIT_FAILURE;
886
 
          goto fallback;
 
873
          goto end;
887
874
        }
888
875
        proc->buffer_size += BUFFER_SIZE;
889
876
      }
904
891
  }
905
892
 
906
893
 
907
 
 fallback:
 
894
 end:
908
895
  
909
896
  if(process_list == NULL or exitstatus != EXIT_SUCCESS){
910
897
    /* Fallback if all plugins failed, none are found or an error occured */
915
902
    if(not bret){
916
903
      perror("print_out_password");
917
904
      exitstatus = EXIT_FAILURE;
 
905
      goto end;
918
906
    }
919
907
  }
920
908
  
921
909
  /* Restore old signal handler */
922
 
  ret = sigaction(SIGCHLD, &old_sigchld_action, NULL);
923
 
  if(ret == -1){
924
 
    perror("sigaction");
925
 
    exitstatus = EXIT_FAILURE;
926
 
  }
927
 
 
928
 
  if(custom_argv != NULL){
929
 
    for(char **arg = custom_argv; *arg != NULL; arg++){
930
 
      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
      }
931
922
    }
932
 
    free(custom_argv);
 
923
    free(plugin_list->environ);
 
924
    free(plugin_list);
933
925
  }
934
 
  free_plugin_list(plugin_list);
935
926
  
936
927
  if(dir != NULL){
937
928
    closedir(dir);