/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-29 05:53:59 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080829055359-wkdasnyxtylmnxus
* mandos.xml (EXAMPLE): Replaced all occurences of command name with
                        "&COMMANDNAME;".

* plugins.d/password-prompt.c (main): Improved some documentation
                                      strings.  Do perror() of
                                      tcgetattr() fails.  Add debug
                                      output if interrupted by signal.
                                      Loop over write() instead of
                                      using fwrite() when outputting
                                      password.  Add debug output if
                                      getline() returns 0, unless it
                                      was caused by a signal.  Add
                                      exit status code to debug
                                      output.

* plugins.d/password-prompt.xml: Changed all single quotes to double
                                 quotes for consistency.  Removed
                                 <?xml-stylesheet>.
  (ENTITY TIMESTAMP): New.  Automatically updated by Emacs time-stamp
                      by using Emacs local variables.
  (/refentry/refentryinfo/title): Changed to "Mandos Manual".
  (/refentry/refentryinfo/productname): Changed to "Mandos".
  (/refentry/refentryinfo/date): New; set to "&TIMESTAMP;".
  (/refentry/refentryinfo/copyright): Split copyright holders.
  (/refentry/refnamediv/refpurpose): Improved wording.
  (SYNOPSIS): Fix to use correct markup.  Add short options.
  (DESCRIPTION, OPTIONS): Improved wording.
  (OPTIONS): Improved wording.  Use more correct markup.  Document
             short options.
  (EXIT STATUS): Add text.
  (ENVIRONMENT): Document use of "cryptsource" and "crypttarget".
  (FILES): REMOVED.
  (BUGS): Add text.
  (EXAMPLE): Added some examples.
  (SECURITY): Added text.
  (SEE ALSO): Remove reference to mandos(8).  Add reference to
              crypttab(5).

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,
64
65
#include <errno.h>              /* errno, EBADF */
65
66
 
66
67
#define BUFFER_SIZE 256
67
 
#define ARGFILE "/conf/conf.d/mandos/plugin-runner.conf"
 
68
 
 
69
#define PDIR "/lib/mandos/plugins.d"
 
70
#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
68
71
 
69
72
const char *argp_program_version = "plugin-runner 1.0";
70
73
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
78
81
  size_t buffer_size;
79
82
  size_t buffer_length;
80
83
  bool eof;
81
 
  bool completed;
82
 
  int status;
 
84
  volatile bool completed;
 
85
  volatile int status;
83
86
  struct process *next;
84
87
} process;
85
88
 
199
202
 
200
203
process *process_list = NULL;
201
204
 
202
 
/* Mark a process as completed when it exits, and save its exit
 
205
/* Mark processes as completed when they exit, and save their exit
203
206
   status. */
204
207
void handle_sigchld(__attribute__((unused)) int sig){
205
 
  process *proc = process_list;
206
 
  int status;
207
 
  pid_t pid = wait(&status);
208
 
  if(pid == -1){
209
 
    perror("wait");
210
 
    return;
211
 
  }
212
 
  while(proc != NULL and proc->pid != pid){
213
 
    proc = proc->next;
214
 
  }
215
 
  if(proc == NULL){
216
 
    /* Process not found in process list */
217
 
    return;
218
 
  }
219
 
  proc->status = status;
220
 
  proc->completed = true;
 
208
  while(true){
 
209
    process *proc = process_list;
 
210
    int status;
 
211
    pid_t pid = waitpid(-1, &status, WNOHANG);
 
212
    if(pid == 0){
 
213
      /* Only still running child processes */
 
214
      break;
 
215
    }
 
216
    if(pid == -1){
 
217
      if (errno != ECHILD){
 
218
        perror("waitpid");
 
219
      }
 
220
      /* No child processes */
 
221
      break;
 
222
    }
 
223
 
 
224
    /* A child exited, find it in process_list */
 
225
    while(proc != NULL and proc->pid != pid){
 
226
      proc = proc->next;
 
227
    }
 
228
    if(proc == NULL){
 
229
      /* Process not found in process list */
 
230
      continue;
 
231
    }
 
232
    proc->status = status;
 
233
    proc->completed = true;
 
234
  }
221
235
}
222
236
 
223
237
bool print_out_password(const char *buffer, size_t length){
235
249
  return true;
236
250
}
237
251
 
238
 
char **add_to_argv(char **argv, int *argc, char *arg){
239
 
  if (argv == NULL){
240
 
    *argc = 1;
241
 
    argv = malloc(sizeof(char*) * 2);
242
 
    if(argv == NULL){
243
 
      return NULL;
244
 
    }
245
 
    argv[0] = NULL;     /* Will be set to argv[0] in main before parsing */
246
 
    argv[1] = NULL;
247
 
  }
248
 
  *argc += 1;
249
 
  argv = realloc(argv, sizeof(char *)
250
 
                  * ((unsigned int) *argc + 1));
251
 
  if(argv == NULL){
252
 
    return NULL;
253
 
  }
254
 
  argv[*argc-1] = arg;
255
 
  argv[*argc] = NULL;
256
 
  return argv;
257
 
}
258
 
 
259
252
static void free_plugin_list(plugin *plugin_list){
260
253
  for(plugin *next; plugin_list != NULL; plugin_list = next){
261
254
    next = plugin_list->next;
272
265
}
273
266
 
274
267
int main(int argc, char *argv[]){
275
 
  const char *plugindir = "/lib/mandos/plugins.d";
276
 
  const char *argfile = ARGFILE;
 
268
  char *plugindir = NULL;
 
269
  char *argfile = NULL;
277
270
  FILE *conffp;
278
271
  size_t d_name_len;
279
272
  DIR *dir = NULL;
326
319
    { .name = "plugin-dir", .key = 128,
327
320
      .arg = "DIRECTORY",
328
321
      .doc = "Specify a different plugin directory", .group = 2 },
329
 
    { .name = "userid", .key = 129,
330
 
      .arg = "ID", .flags = 0,
331
 
      .doc = "User ID the plugins will run as", .group = 2 },
332
 
    { .name = "groupid", .key = 130,
333
 
      .arg = "ID", .flags = 0,
334
 
      .doc = "Group ID the plugins will run as", .group = 2 },
335
 
    { .name = "debug", .key = 131,
336
 
      .doc = "Debug mode", .group = 3 },
 
322
    { .name = "config-file", .key = 129,
 
323
      .arg = "FILE",
 
324
      .doc = "Specify a different configuration file", .group = 2 },
 
325
    { .name = "userid", .key = 130,
 
326
      .arg = "ID", .flags = 0,
 
327
      .doc = "User ID the plugins will run as", .group = 3 },
 
328
    { .name = "groupid", .key = 131,
 
329
      .arg = "ID", .flags = 0,
 
330
      .doc = "Group ID the plugins will run as", .group = 3 },
 
331
    { .name = "debug", .key = 132,
 
332
      .doc = "Debug mode", .group = 4 },
337
333
    { .name = NULL }
338
334
  };
339
335
  
423
419
      }
424
420
      break;
425
421
    case 128:
426
 
      plugindir = arg;
 
422
      plugindir = strdup(arg);
 
423
      if(plugindir == NULL){
 
424
        perror("strdup");
 
425
      }      
427
426
      break;
428
427
    case 129:
 
428
      argfile = strdup(arg);
 
429
      if(argfile == NULL){
 
430
        perror("strdup");
 
431
      }
 
432
      break;      
 
433
    case 130:
429
434
      uid = (uid_t)strtol(arg, NULL, 10);
430
435
      break;
431
 
    case 130:
 
436
    case 131:
432
437
      gid = (gid_t)strtol(arg, NULL, 10);
433
438
      break;
434
 
    case 131:
 
439
    case 132:
435
440
      debug = true;
436
441
      break;
437
442
    case ARGP_KEY_ARG:
458
463
    goto fallback;
459
464
  }
460
465
 
461
 
  conffp = fopen(argfile, "r");
 
466
  if (argfile == NULL){
 
467
    conffp = fopen(AFILE, "r");
 
468
  } else {
 
469
    conffp = fopen(argfile, "r");
 
470
  }
 
471
  
462
472
  if(conffp != NULL){
463
473
    char *org_line = NULL;
464
474
    char *p, *arg, *new_arg, *line;
467
477
    const char whitespace_delims[] = " \r\t\f\v\n";
468
478
    const char comment_delim[] = "#";
469
479
 
 
480
    custom_argc = 1;
 
481
    custom_argv = malloc(sizeof(char*) * 2);
 
482
    if(custom_argv == NULL){
 
483
      perror("malloc");
 
484
      exitstatus = EXIT_FAILURE;
 
485
      goto fallback;
 
486
    }
 
487
    custom_argv[0] = argv[0];
 
488
    custom_argv[1] = NULL;
 
489
    
470
490
    while(true){
471
491
      sret = getline(&org_line, &size, conffp);
472
492
      if(sret == -1){
480
500
          continue;
481
501
        }
482
502
        new_arg = strdup(p);
483
 
        custom_argv = add_to_argv(custom_argv, &custom_argc, new_arg);
484
 
        if (custom_argv == NULL){
485
 
          perror("add_to_argv");
486
 
          exitstatus = EXIT_FAILURE;
487
 
          goto fallback;
488
 
        }
 
503
        if(new_arg == NULL){
 
504
          perror("strdup");
 
505
          exitstatus = EXIT_FAILURE;
 
506
          free(org_line);
 
507
          goto fallback;
 
508
        }
 
509
        
 
510
        custom_argc += 1;
 
511
        custom_argv = realloc(custom_argv, sizeof(char *)
 
512
                              * ((unsigned int) custom_argc + 1));
 
513
        if(custom_argv == NULL){
 
514
          perror("realloc");
 
515
          exitstatus = EXIT_FAILURE;
 
516
          free(org_line);
 
517
          goto fallback;
 
518
        }
 
519
        custom_argv[custom_argc-1] = new_arg;
 
520
        custom_argv[custom_argc] = NULL;        
489
521
      }
490
522
    }
491
523
    free(org_line);
500
532
  }
501
533
 
502
534
  if(custom_argv != NULL){
503
 
    custom_argv[0] = argv[0];
504
535
    ret = argp_parse (&argp, custom_argc, custom_argv, 0, 0, &plugin_list);
505
536
    if (ret == ARGP_ERR_UNKNOWN){
506
537
      fprintf(stderr, "Unknown error while parsing arguments\n");
532
563
  if (ret == -1){
533
564
    perror("setgid");
534
565
  }
 
566
 
 
567
  if (plugindir == NULL){
 
568
    dir = opendir(PDIR);
 
569
  } else {
 
570
    dir = opendir(plugindir);
 
571
  }
535
572
  
536
 
  dir = opendir(plugindir);
537
573
  if(dir == NULL){
538
574
    perror("Could not open plugin dir");
539
575
    exitstatus = EXIT_FAILURE;
789
825
    }
790
826
    
791
827
  }
792
 
  
 
828
 
793
829
  free_plugin_list(plugin_list);
794
830
  plugin_list = NULL;
795
831
  
835
871
          /* Remove the plugin */
836
872
          FD_CLR(proc->fd, &rfds_all);
837
873
          /* Block signal while modifying process_list */
838
 
          ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
 
874
          ret = sigprocmask(SIG_BLOCK, &sigchld_action.sa_mask, NULL);
839
875
          if(ret < 0){
840
876
            perror("sigprocmask");
841
877
            exitstatus = EXIT_FAILURE;
869
905
        }
870
906
        /* This process exited nicely, so print its buffer */
871
907
 
872
 
        bool bret = print_out_password(proc->buffer, proc->buffer_length);
 
908
        bool bret = print_out_password(proc->buffer,
 
909
                                       proc->buffer_length);
873
910
        if(not bret){
874
911
          perror("print_out_password");
875
912
          exitstatus = EXIT_FAILURE;
912
949
 fallback:
913
950
  
914
951
  if(process_list == NULL or exitstatus != EXIT_SUCCESS){
915
 
    /* Fallback if all plugins failed, none are found or an error occured */
 
952
    /* Fallback if all plugins failed, none are found or an error
 
953
       occured */
916
954
    bool bret;
917
955
    fprintf(stderr, "Going to fallback mode using getpass(3)\n");
918
956
    char *passwordbuffer = getpass("Password: ");
931
969
  }
932
970
 
933
971
  if(custom_argv != NULL){
934
 
    for(char **arg = custom_argv; *arg != NULL; arg++){
 
972
    for(char **arg = custom_argv+1; *arg != NULL; arg++){
935
973
      free(*arg);
936
974
    }
937
975
    free(custom_argv);
962
1000
  if(errno != ECHILD){
963
1001
    perror("wait");
964
1002
  }
 
1003
 
 
1004
  free(plugindir);
 
1005
  free(argfile);
965
1006
  
966
1007
  return exitstatus;
967
1008
}