/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 = NULL;
109
 
  if(name != NULL){
110
 
    copy_name = strdup(name);
111
 
    if(copy_name == NULL){
112
 
      return NULL;
113
 
    }
114
 
  }
115
 
  
116
 
  *new_plugin = (plugin) { .name = copy_name,
 
108
  *new_plugin = (plugin) { .name = name,
117
109
                           .argc = 1,
118
110
                           .envc = 0,
119
111
                           .disabled = false,
121
113
  
122
114
  new_plugin->argv = malloc(sizeof(char *) * 2);
123
115
  if (new_plugin->argv == NULL){
124
 
    free(copy_name);
125
116
    free(new_plugin);
126
117
    return NULL;
127
118
  }
128
 
  new_plugin->argv[0] = copy_name;
 
119
  new_plugin->argv[0] = name;
129
120
  new_plugin->argv[1] = NULL;
130
121
 
131
122
  new_plugin->environ = malloc(sizeof(char *));
132
123
  if(new_plugin->environ == NULL){
133
 
    free(copy_name);
134
124
    free(new_plugin->argv);
135
125
    free(new_plugin);
136
126
    return NULL;
252
242
    return NULL;
253
243
  }
254
244
  argv[*argc-1] = arg;
255
 
  argv[*argc] = NULL;
 
245
  argv[*argc] = NULL;   
256
246
  return argv;
257
247
}
258
248
 
259
 
static void free_plugin_list(plugin *plugin_list){
260
 
  for(plugin *next; plugin_list != NULL; plugin_list = next){
261
 
    next = plugin_list->next;
262
 
    for(char **arg = plugin_list->argv; *arg != NULL; arg++){
263
 
      free(*arg);
264
 
    }
265
 
    free(plugin_list->argv);
266
 
    for(char **env = plugin_list->environ; *env != NULL; env++){
267
 
      free(*env);
268
 
    }
269
 
    free(plugin_list->environ);
270
 
    free(plugin_list);
271
 
  }
272
 
}
273
 
 
274
249
int main(int argc, char *argv[]){
275
250
  const char *plugindir = "/lib/mandos/plugins.d";
276
251
  const char *argfile = ARGFILE;
294
269
  /* Establish a signal handler */
295
270
  sigemptyset(&sigchld_action.sa_mask);
296
271
  ret = sigaddset(&sigchld_action.sa_mask, SIGCHLD);
297
 
  if(ret == -1){
 
272
  if(ret < 0){
298
273
    perror("sigaddset");
299
 
    exitstatus = EXIT_FAILURE;
300
 
    goto fallback;
 
274
    exit(EXIT_FAILURE);
301
275
  }
302
276
  ret = sigaction(SIGCHLD, &sigchld_action, &old_sigchld_action);
303
 
  if(ret == -1){
 
277
  if(ret < 0){
304
278
    perror("sigaction");
305
 
    exitstatus = EXIT_FAILURE;
306
 
    goto fallback;
 
279
    exit(EXIT_FAILURE);
307
280
  }
308
281
  
309
282
  /* The options we understand. */
455
428
  if (ret == ARGP_ERR_UNKNOWN){
456
429
    fprintf(stderr, "Unknown error while parsing arguments\n");
457
430
    exitstatus = EXIT_FAILURE;
458
 
    goto fallback;
 
431
    goto end;
459
432
  }
460
433
 
461
434
  conffp = fopen(argfile, "r");
462
435
  if(conffp != NULL){
463
436
    char *org_line = NULL;
464
 
    char *p, *arg, *new_arg, *line;
465
437
    size_t size = 0;
466
438
    ssize_t sret;
 
439
    char *p, *arg, *new_arg, *line;
467
440
    const char whitespace_delims[] = " \r\t\f\v\n";
468
441
    const char comment_delim[] = "#";
469
442
 
484
457
        if (custom_argv == NULL){
485
458
          perror("add_to_argv");
486
459
          exitstatus = EXIT_FAILURE;
487
 
          goto fallback;
 
460
          goto end;
488
461
        }
489
462
      }
490
463
    }
495
468
    if (errno == EMFILE or errno == ENFILE or errno == ENOMEM){
496
469
      perror("fopen");
497
470
      exitstatus = EXIT_FAILURE;
498
 
      goto fallback;
 
471
      goto end;
499
472
    }
500
473
  }
501
474
 
505
478
    if (ret == ARGP_ERR_UNKNOWN){
506
479
      fprintf(stderr, "Unknown error while parsing arguments\n");
507
480
      exitstatus = EXIT_FAILURE;
508
 
      goto fallback;
 
481
      goto end;
509
482
    }
510
483
  }
511
484
  
537
510
  if(dir == NULL){
538
511
    perror("Could not open plugin dir");
539
512
    exitstatus = EXIT_FAILURE;
540
 
    goto fallback;
 
513
    goto end;
541
514
  }
542
515
  
543
516
  /* Set the FD_CLOEXEC flag on the directory, if possible */
548
521
      if(ret < 0){
549
522
        perror("set_cloexec_flag");
550
523
        exitstatus = EXIT_FAILURE;
551
 
        goto fallback;
 
524
        goto end;
552
525
      }
553
526
    }
554
527
  }
563
536
      if (errno == EBADF){
564
537
        perror("readdir");
565
538
        exitstatus = EXIT_FAILURE;
566
 
        goto fallback;
 
539
        goto end;
567
540
      }
568
541
      break;
569
542
    }
684
657
      }
685
658
    }
686
659
    
687
 
    int pipefd[2];
 
660
    int pipefd[2]; 
688
661
    ret = pipe(pipefd);
689
662
    if (ret == -1){
690
663
      perror("pipe");
691
664
      exitstatus = EXIT_FAILURE;
692
 
      goto fallback;
 
665
      goto end;
693
666
    }
694
667
    ret = set_cloexec_flag(pipefd[0]);
695
668
    if(ret < 0){
696
669
      perror("set_cloexec_flag");
697
670
      exitstatus = EXIT_FAILURE;
698
 
      goto fallback;
 
671
      goto end;
699
672
    }
700
673
    ret = set_cloexec_flag(pipefd[1]);
701
674
    if(ret < 0){
702
675
      perror("set_cloexec_flag");
703
676
      exitstatus = EXIT_FAILURE;
704
 
      goto fallback;
 
677
      goto end;
705
678
    }
706
679
    /* Block SIGCHLD until process is safely in process list */
707
680
    ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
708
681
    if(ret < 0){
709
682
      perror("sigprocmask");
710
683
      exitstatus = EXIT_FAILURE;
711
 
      goto fallback;
 
684
      goto end;
712
685
    }
713
686
    // Starting a new process to be watched
714
687
    pid_t pid = fork();
715
688
    if(pid == -1){
716
689
      perror("fork");
717
690
      exitstatus = EXIT_FAILURE;
718
 
      goto fallback;
 
691
      goto end;
719
692
    }
720
693
    if(pid == 0){
721
694
      /* this is the child process */
765
738
        perror("sigprocmask");
766
739
      }
767
740
      exitstatus = EXIT_FAILURE;
768
 
      goto fallback;
 
741
      goto end;
769
742
    }
770
743
    
771
744
    *new_process = (struct process){ .pid = pid,
779
752
    if(ret < 0){
780
753
      perror("sigprocmask");
781
754
      exitstatus = EXIT_FAILURE;
782
 
      goto fallback;
 
755
      goto end;
783
756
    }
784
757
    
785
758
    FD_SET(new_process->fd, &rfds_all);
790
763
    
791
764
  }
792
765
  
793
 
  free_plugin_list(plugin_list);
794
 
  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
  }
795
777
  
796
778
  closedir(dir);
797
779
  dir = NULL;
807
789
    if (select_ret == -1){
808
790
      perror("select");
809
791
      exitstatus = EXIT_FAILURE;
810
 
      goto fallback;
 
792
      goto end;
811
793
    }
812
794
    /* OK, now either a process completed, or something can be read
813
795
       from one of them */
839
821
          if(ret < 0){
840
822
            perror("sigprocmask");
841
823
            exitstatus = EXIT_FAILURE;
842
 
            goto fallback;
 
824
            goto end;
843
825
          }
844
826
          /* Delete this process entry from the list */
845
827
          if(process_list == proc){
874
856
          perror("print_out_password");
875
857
          exitstatus = EXIT_FAILURE;
876
858
        }
877
 
        goto fallback;
 
859
        goto end;
878
860
      }
879
861
      /* This process has not completed.  Does it have any output? */
880
862
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
888
870
        if (proc->buffer == NULL){
889
871
          perror("malloc");
890
872
          exitstatus = EXIT_FAILURE;
891
 
          goto fallback;
 
873
          goto end;
892
874
        }
893
875
        proc->buffer_size += BUFFER_SIZE;
894
876
      }
909
891
  }
910
892
 
911
893
 
912
 
 fallback:
 
894
 end:
913
895
  
914
896
  if(process_list == NULL or exitstatus != EXIT_SUCCESS){
915
897
    /* Fallback if all plugins failed, none are found or an error occured */
920
902
    if(not bret){
921
903
      perror("print_out_password");
922
904
      exitstatus = EXIT_FAILURE;
 
905
      goto end;
923
906
    }
924
907
  }
925
908
  
926
909
  /* Restore old signal handler */
927
 
  ret = sigaction(SIGCHLD, &old_sigchld_action, NULL);
928
 
  if(ret == -1){
929
 
    perror("sigaction");
930
 
    exitstatus = EXIT_FAILURE;
931
 
  }
932
 
 
933
 
  if(custom_argv != NULL){
934
 
    for(char **arg = custom_argv; *arg != NULL; arg++){
935
 
      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
      }
936
922
    }
937
 
    free(custom_argv);
 
923
    free(plugin_list->environ);
 
924
    free(plugin_list);
938
925
  }
939
 
  free_plugin_list(plugin_list);
940
926
  
941
927
  if(dir != NULL){
942
928
    closedir(dir);