/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
 
105
108
  if (new_plugin == NULL){
106
109
    return NULL;
107
110
  }
108
 
  char *copy_name = strdup(name);
109
 
  if(copy_name == NULL){
110
 
    return NULL;
 
111
  char *copy_name = NULL;
 
112
  if(name != NULL){
 
113
    copy_name = strdup(name);
 
114
    if(copy_name == NULL){
 
115
      return NULL;
 
116
    }
111
117
  }
112
118
  
113
119
  *new_plugin = (plugin) { .name = copy_name,
118
124
  
119
125
  new_plugin->argv = malloc(sizeof(char *) * 2);
120
126
  if (new_plugin->argv == NULL){
 
127
    free(copy_name);
121
128
    free(new_plugin);
122
129
    return NULL;
123
130
  }
126
133
 
127
134
  new_plugin->environ = malloc(sizeof(char *));
128
135
  if(new_plugin->environ == NULL){
 
136
    free(copy_name);
129
137
    free(new_plugin->argv);
130
138
    free(new_plugin);
131
139
    return NULL;
194
202
 
195
203
process *process_list = NULL;
196
204
 
197
 
/* Mark a process as completed when it exits, and save its exit
 
205
/* Mark processes as completed when they exit, and save their exit
198
206
   status. */
199
207
void handle_sigchld(__attribute__((unused)) int sig){
200
 
  process *proc = process_list;
201
 
  int status;
202
 
  pid_t pid = wait(&status);
203
 
  if(pid == -1){
204
 
    perror("wait");
205
 
    return;
206
 
  }
207
 
  while(proc != NULL and proc->pid != pid){
208
 
    proc = proc->next;
209
 
  }
210
 
  if(proc == NULL){
211
 
    /* Process not found in process list */
212
 
    return;
213
 
  }
214
 
  proc->status = status;
215
 
  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
  }
216
235
}
217
236
 
218
237
bool print_out_password(const char *buffer, size_t length){
230
249
  return true;
231
250
}
232
251
 
233
 
char **add_to_argv(char **argv, int *argc, char *arg){
234
 
  if (argv == NULL){
235
 
    *argc = 1;
236
 
    argv = malloc(sizeof(char*) * 2);
237
 
    if(argv == NULL){
238
 
      return NULL;
239
 
    }
240
 
    argv[0] = NULL;     /* Will be set to argv[0] in main before parsing */
241
 
    argv[1] = NULL;
242
 
  }
243
 
  *argc += 1;
244
 
  argv = realloc(argv, sizeof(char *)
245
 
                  * ((unsigned int) *argc + 1));
246
 
  if(argv == NULL){
247
 
    return NULL;
248
 
  }
249
 
  argv[*argc-1] = arg;
250
 
  argv[*argc] = NULL;   
251
 
  return argv;
252
 
}
253
 
 
254
252
static void free_plugin_list(plugin *plugin_list){
255
 
  for(plugin *next = plugin_list; plugin_list != NULL; plugin_list = next){
 
253
  for(plugin *next; plugin_list != NULL; plugin_list = next){
256
254
    next = plugin_list->next;
257
 
    free(plugin_list->name);
258
255
    for(char **arg = plugin_list->argv; *arg != NULL; arg++){
259
256
      free(*arg);
260
 
    }    
 
257
    }
261
258
    free(plugin_list->argv);
262
259
    for(char **env = plugin_list->environ; *env != NULL; env++){
263
260
      free(*env);
264
261
    }
265
262
    free(plugin_list->environ);
266
263
    free(plugin_list);
267
 
  }  
 
264
  }
268
265
}
269
266
 
270
267
int main(int argc, char *argv[]){
271
 
  const char *plugindir = "/lib/mandos/plugins.d";
272
 
  const char *argfile = ARGFILE;
 
268
  char *plugindir = NULL;
 
269
  char *argfile = NULL;
273
270
  FILE *conffp;
274
271
  size_t d_name_len;
275
272
  DIR *dir = NULL;
298
295
  ret = sigaction(SIGCHLD, &sigchld_action, &old_sigchld_action);
299
296
  if(ret == -1){
300
297
    perror("sigaction");
301
 
    exitstatus = EXIT_FAILURE;    
 
298
    exitstatus = EXIT_FAILURE;
302
299
    goto fallback;
303
300
  }
304
301
  
322
319
    { .name = "plugin-dir", .key = 128,
323
320
      .arg = "DIRECTORY",
324
321
      .doc = "Specify a different plugin directory", .group = 2 },
325
 
    { .name = "userid", .key = 129,
326
 
      .arg = "ID", .flags = 0,
327
 
      .doc = "User ID the plugins will run as", .group = 2 },
328
 
    { .name = "groupid", .key = 130,
329
 
      .arg = "ID", .flags = 0,
330
 
      .doc = "Group ID the plugins will run as", .group = 2 },
331
 
    { .name = "debug", .key = 131,
332
 
      .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 },
333
333
    { .name = NULL }
334
334
  };
335
335
  
419
419
      }
420
420
      break;
421
421
    case 128:
422
 
      plugindir = arg;
 
422
      plugindir = strdup(arg);
 
423
      if(plugindir == NULL){
 
424
        perror("strdup");
 
425
      }      
423
426
      break;
424
427
    case 129:
 
428
      argfile = strdup(arg);
 
429
      if(argfile == NULL){
 
430
        perror("strdup");
 
431
      }
 
432
      break;      
 
433
    case 130:
425
434
      uid = (uid_t)strtol(arg, NULL, 10);
426
435
      break;
427
 
    case 130:
 
436
    case 131:
428
437
      gid = (gid_t)strtol(arg, NULL, 10);
429
438
      break;
430
 
    case 131:
 
439
    case 132:
431
440
      debug = true;
432
441
      break;
433
442
    case ARGP_KEY_ARG:
454
463
    goto fallback;
455
464
  }
456
465
 
457
 
  conffp = fopen(argfile, "r");
 
466
  if (argfile == NULL){
 
467
    conffp = fopen(AFILE, "r");
 
468
  } else {
 
469
    conffp = fopen(argfile, "r");
 
470
  }
 
471
  
458
472
  if(conffp != NULL){
459
473
    char *org_line = NULL;
460
474
    char *p, *arg, *new_arg, *line;
463
477
    const char whitespace_delims[] = " \r\t\f\v\n";
464
478
    const char comment_delim[] = "#";
465
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
    
466
490
    while(true){
467
491
      sret = getline(&org_line, &size, conffp);
468
492
      if(sret == -1){
476
500
          continue;
477
501
        }
478
502
        new_arg = strdup(p);
479
 
        custom_argv = add_to_argv(custom_argv, &custom_argc, new_arg);
480
 
        if (custom_argv == NULL){
481
 
          perror("add_to_argv");
482
 
          exitstatus = EXIT_FAILURE;
483
 
          goto fallback;
484
 
        }
 
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;        
485
521
      }
486
522
    }
487
523
    free(org_line);
496
532
  }
497
533
 
498
534
  if(custom_argv != NULL){
499
 
    custom_argv[0] = argv[0];
500
535
    ret = argp_parse (&argp, custom_argc, custom_argv, 0, 0, &plugin_list);
501
536
    if (ret == ARGP_ERR_UNKNOWN){
502
537
      fprintf(stderr, "Unknown error while parsing arguments\n");
528
563
  if (ret == -1){
529
564
    perror("setgid");
530
565
  }
 
566
 
 
567
  if (plugindir == NULL){
 
568
    dir = opendir(PDIR);
 
569
  } else {
 
570
    dir = opendir(plugindir);
 
571
  }
531
572
  
532
 
  dir = opendir(plugindir);
533
573
  if(dir == NULL){
534
574
    perror("Could not open plugin dir");
535
575
    exitstatus = EXIT_FAILURE;
680
720
      }
681
721
    }
682
722
    
683
 
    int pipefd[2]; 
 
723
    int pipefd[2];
684
724
    ret = pipe(pipefd);
685
725
    if (ret == -1){
686
726
      perror("pipe");
785
825
    }
786
826
    
787
827
  }
788
 
  
 
828
 
789
829
  free_plugin_list(plugin_list);
 
830
  plugin_list = NULL;
790
831
  
791
832
  closedir(dir);
792
833
  dir = NULL;
830
871
          /* Remove the plugin */
831
872
          FD_CLR(proc->fd, &rfds_all);
832
873
          /* Block signal while modifying process_list */
833
 
          ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
 
874
          ret = sigprocmask(SIG_BLOCK, &sigchld_action.sa_mask, NULL);
834
875
          if(ret < 0){
835
876
            perror("sigprocmask");
836
877
            exitstatus = EXIT_FAILURE;
864
905
        }
865
906
        /* This process exited nicely, so print its buffer */
866
907
 
867
 
        bool bret = print_out_password(proc->buffer, proc->buffer_length);
 
908
        bool bret = print_out_password(proc->buffer,
 
909
                                       proc->buffer_length);
868
910
        if(not bret){
869
911
          perror("print_out_password");
870
912
          exitstatus = EXIT_FAILURE;
907
949
 fallback:
908
950
  
909
951
  if(process_list == NULL or exitstatus != EXIT_SUCCESS){
910
 
    /* 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 */
911
954
    bool bret;
912
955
    fprintf(stderr, "Going to fallback mode using getpass(3)\n");
913
956
    char *passwordbuffer = getpass("Password: ");
926
969
  }
927
970
 
928
971
  if(custom_argv != NULL){
929
 
    for(char **arg = custom_argv; *arg != NULL; arg++){
 
972
    for(char **arg = custom_argv+1; *arg != NULL; arg++){
930
973
      free(*arg);
931
974
    }
932
975
    free(custom_argv);
957
1000
  if(errno != ECHILD){
958
1001
    perror("wait");
959
1002
  }
 
1003
 
 
1004
  free(plugindir);
 
1005
  free(argfile);
960
1006
  
961
1007
  return exitstatus;
962
1008
}