/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugbasedclient.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-02 10:48:24 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080802104824-fx0miwp9o4g9r31e
* plugbasedclient.c (struct process): New fields "eof", "completed",
                                      and "status".
  (handle_sigchld): New function.
  (main): Initialize "dir" to NULL to only closedir() it if necessary.
          Move "process_list" to be a global variable to be accessible
          by "handle_sigchld".  Make "handle_sigchld" handle SIGCHLD.
          Remove redundant check for NULL "dir".  Free "filename" when
          no longer used.  Block SIGCHLD around fork()/exec().
          Restore normal signals in child.  Only loop while running
          processes exist.  Print process buffer when the process is
          done and it has emitted EOF, not when it only emits EOF.
          Remove processes from list which exit non-cleanly.  In
          cleaning up, closedir() if necessary.  Bug fix: set next
          pointer correctly when freeing process list.

* plugins.d/passprompt.c (main): Do not ignore SIGQUIT.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 * Contact the authors at <mandos@fukt.bsnet.se>.
22
22
 */
23
23
 
24
 
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), getline(),
25
 
                                   asprintf() */
26
 
#include <stddef.h>             /* size_t, NULL */
27
 
#include <stdlib.h>             /* malloc(), exit(), EXIT_FAILURE,
28
 
                                   EXIT_SUCCESS, realloc() */
29
 
#include <stdbool.h>            /* bool, true, false */
30
 
#include <stdio.h>              /* perror, popen(), fileno(),
31
 
                                   fprintf(), stderr, STDOUT_FILENO */
32
 
#include <sys/types.h>          /* DIR, opendir(), stat(), struct
33
 
                                   stat, waitpid(), WIFEXITED(),
34
 
                                   WEXITSTATUS(), wait(), pid_t,
35
 
                                   uid_t, gid_t, getuid(), getgid(),
36
 
                                   dirfd() */
37
 
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
38
 
                                   FD_SET(), FD_ISSET(), FD_CLR */
39
 
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
40
 
                                   WEXITSTATUS() */
41
 
#include <sys/stat.h>           /* struct stat, stat(), S_ISREG() */
 
24
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY() */
 
25
 
 
26
#include <stdio.h>              /* popen(), fileno(), fprintf(),
 
27
                                   stderr, STDOUT_FILENO */
42
28
#include <iso646.h>             /* and, or, not */
 
29
#include <sys/types.h>          /* DIR, opendir(), stat(),
 
30
                                   struct stat, waitpid(),
 
31
                                   WIFEXITED(), WEXITSTATUS(),
 
32
                                   wait() */
 
33
#include <sys/wait.h>           /* wait() */
43
34
#include <dirent.h>             /* DIR, struct dirent, opendir(),
44
 
                                   readdir(), closedir(), dirfd() */
 
35
                                   readdir(), closedir() */
 
36
#include <sys/stat.h>           /* struct stat, stat(), S_ISREG() */
45
37
#include <unistd.h>             /* struct stat, stat(), S_ISREG(),
46
 
                                   fcntl(), setuid(), setgid(),
47
 
                                   F_GETFD, F_SETFD, FD_CLOEXEC,
48
 
                                   access(), pipe(), fork(), close()
49
 
                                   dup2, STDOUT_FILENO, _exit(),
50
 
                                   execv(), write(), read(),
51
 
                                   close() */
52
 
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
53
 
                                   FD_CLOEXEC */
54
 
#include <string.h>             /* strsep, strlen(), asprintf() */
 
38
                                   fcntl() */
 
39
#include <fcntl.h>              /* fcntl() */
 
40
#include <stddef.h>             /* NULL */
 
41
#include <stdlib.h>             /* EXIT_FAILURE */
 
42
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
 
43
                                   FD_SET(), FD_ISSET() */
 
44
#include <string.h>             /* strlen(), strcpy(), strcat() */
 
45
#include <stdbool.h>            /* true */
 
46
#include <sys/wait.h>           /* waitpid(), WIFEXITED(),
 
47
                                   WEXITSTATUS() */
55
48
#include <errno.h>              /* errno */
56
 
#include <argp.h>               /* struct argp_option, struct
57
 
                                   argp_state, struct argp,
58
 
                                   argp_parse(), ARGP_ERR_UNKNOWN,
59
 
                                   ARGP_KEY_END, ARGP_KEY_ARG, error_t */
60
 
#include <signal.h>             /* struct sigaction, sigemptyset(),
61
 
                                   sigaddset(), sigaction(),
62
 
                                   sigprocmask(), SIG_BLOCK, SIGCHLD,
63
 
                                   SIG_UNBLOCK, kill() */
64
 
#include <errno.h>              /* errno, EBADF */
65
 
 
66
 
#define BUFFER_SIZE 256
67
 
#define ARGFILE "/conf/conf.d/mandos/plugin-runner.conf"
68
 
 
69
 
const char *argp_program_version = "plugin-runner 1.0";
70
 
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
49
#include <argp.h>               /* struct argp_option,
 
50
                                   struct argp_state, struct argp,
 
51
                                   argp_parse() */
71
52
 
72
53
struct process;
73
54
 
87
68
  char *name;                   /* can be NULL or any plugin name */
88
69
  char **argv;
89
70
  int argc;
90
 
  char **environ;
91
 
  int envc;
92
71
  bool disabled;
93
72
  struct plugin *next;
94
73
} plugin;
95
74
 
96
 
static plugin *getplugin(char *name, plugin **plugin_list){
 
75
plugin *getplugin(char *name, plugin **plugin_list){
97
76
  for (plugin *p = *plugin_list; p != NULL; p = p->next){
98
77
    if ((p->name == name)
99
78
        or (p->name and name and (strcmp(p->name, name) == 0))){
103
82
  /* Create a new plugin */
104
83
  plugin *new_plugin = malloc(sizeof(plugin));
105
84
  if (new_plugin == NULL){
106
 
    return NULL;
 
85
    perror("malloc");
 
86
    exit(EXIT_FAILURE);
107
87
  }
108
 
  *new_plugin = (plugin) { .name = name,
109
 
                           .argc = 1,
110
 
                           .envc = 0,
111
 
                           .disabled = false,
112
 
                           .next = *plugin_list };
113
 
  
 
88
  new_plugin->name = name;
114
89
  new_plugin->argv = malloc(sizeof(char *) * 2);
115
90
  if (new_plugin->argv == NULL){
116
 
    free(new_plugin);
117
 
    return NULL;
 
91
    perror("malloc");
 
92
    exit(EXIT_FAILURE);
118
93
  }
119
94
  new_plugin->argv[0] = name;
120
95
  new_plugin->argv[1] = NULL;
121
 
 
122
 
  new_plugin->environ = malloc(sizeof(char *));
123
 
  if(new_plugin->environ == NULL){
124
 
    free(new_plugin->argv);
125
 
    free(new_plugin);
126
 
    return NULL;
127
 
  }
128
 
  new_plugin->environ[0] = NULL;
 
96
  new_plugin->argc = 1;
 
97
  new_plugin->disabled = false;
 
98
  new_plugin->next = *plugin_list;
129
99
  /* Append the new plugin to the list */
130
100
  *plugin_list = new_plugin;
131
101
  return new_plugin;
132
102
}
133
103
 
134
 
/* Helper function for add_argument and add_environment */
135
 
static bool add_to_char_array(const char *new, char ***array,
136
 
                              int *len){
137
 
  /* Resize the pointed-to array to hold one more pointer */
138
 
  *array = realloc(*array, sizeof(char *)
139
 
                   * (size_t) ((*len) + 2));
140
 
  /* Malloc check */
141
 
  if(*array == NULL){
142
 
    return false;
143
 
  }
144
 
  /* Make a copy of the new string */
145
 
  char *copy = strdup(new);
146
 
  if(copy == NULL){
147
 
    return false;
148
 
  }
149
 
  /* Insert the copy */
150
 
  (*array)[*len] = copy;
151
 
  (*len)++;
152
 
  /* Add a new terminating NULL pointer to the last element */
153
 
  (*array)[*len] = NULL;
154
 
  return true;
155
 
}
156
 
 
157
 
/* Add to a plugin's argument vector */
158
 
static bool add_argument(plugin *p, const char *arg){
159
 
  if(p == NULL){
160
 
    return false;
161
 
  }
162
 
  return add_to_char_array(arg, &(p->argv), &(p->argc));
163
 
}
164
 
 
165
 
/* Add to a plugin's environment */
166
 
static bool add_environment(plugin *p, const char *def){
167
 
  if(p == NULL){
168
 
    return false;
169
 
  }
170
 
  return add_to_char_array(def, &(p->environ), &(p->envc));
171
 
}
172
 
 
 
104
void addargument(plugin *p, char *arg){
 
105
  p->argv[p->argc] = arg;
 
106
  p->argv = realloc(p->argv, sizeof(char *) * (size_t)(p->argc + 2));
 
107
  if (p->argv == NULL){
 
108
    perror("malloc");
 
109
    exit(EXIT_FAILURE);
 
110
  }
 
111
  p->argc++;
 
112
  p->argv[p->argc] = NULL;
 
113
}
173
114
 
174
115
/*
175
116
 * Based on the example in the GNU LibC manual chapter 13.13 "File
176
117
 * Descriptor Flags".
177
118
 * *Note File Descriptor Flags:(libc)Descriptor Flags.
178
119
 */
179
 
static int set_cloexec_flag(int fd)
 
120
int set_cloexec_flag(int fd)
180
121
{
181
122
  int ret = fcntl(fd, F_GETFD, 0);
182
123
  /* If reading the flags failed, return error indication now. */
187
128
  return fcntl(fd, F_SETFD, ret | FD_CLOEXEC);
188
129
}
189
130
 
 
131
#define BUFFER_SIZE 256
 
132
 
 
133
const char *argp_program_version = "plugbasedclient 0.9";
 
134
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
135
 
190
136
process *process_list = NULL;
191
137
 
192
138
/* Mark a process as completed when it exits, and save its exit
195
141
  process *proc = process_list;
196
142
  int status;
197
143
  pid_t pid = wait(&status);
198
 
  if(pid == -1){
199
 
    perror("wait");
200
 
    return;
201
 
  }
202
144
  while(proc != NULL and proc->pid != pid){
203
 
    proc = proc->next;
 
145
    proc = proc->next;    
204
146
  }
205
147
  if(proc == NULL){
206
148
    /* Process not found in process list */
210
152
  proc->completed = true;
211
153
}
212
154
 
213
 
bool print_out_password(const char *buffer, size_t length){
214
 
  ssize_t ret;
215
 
  if(length>0 and buffer[length-1] == '\n'){
216
 
    length--;
217
 
  }
218
 
  for(size_t written = 0; written < length; written += (size_t)ret){
219
 
    ret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buffer + written,
220
 
                                   length - written));
221
 
    if(ret < 0){
222
 
      return false;
223
 
    }
224
 
  }
225
 
  return true;
226
 
}
227
 
 
228
 
char **add_to_argv(char **argv, int *argc, char *arg){
229
 
  if (argv == NULL){
230
 
    *argc = 1;
231
 
    argv = malloc(sizeof(char*) * 2);
232
 
    if(argv == NULL){
233
 
      return NULL;
234
 
    }
235
 
    argv[0] = NULL;     /* Will be set to argv[0] in main before parsing */
236
 
    argv[1] = NULL;
237
 
  }
238
 
  *argc += 1;
239
 
  argv = realloc(argv, sizeof(char *)
240
 
                  * ((unsigned int) *argc + 1));
241
 
  if(argv == NULL){
242
 
    return NULL;
243
 
  }
244
 
  argv[*argc-1] = arg;
245
 
  argv[*argc] = NULL;   
246
 
  return argv;
247
 
}
248
 
 
249
155
int main(int argc, char *argv[]){
250
 
  const char *plugindir = "/lib/mandos/plugins.d";
251
 
  const char *argfile = ARGFILE;
252
 
  FILE *conffp;
 
156
  const char *plugindir = "/conf/conf.d/mandos/plugins.d";
253
157
  size_t d_name_len;
254
158
  DIR *dir = NULL;
255
159
  struct dirent *dirst;
256
160
  struct stat st;
257
161
  fd_set rfds_all;
258
162
  int ret, maxfd = 0;
259
 
  uid_t uid = 65534;
260
 
  gid_t gid = 65534;
261
163
  bool debug = false;
262
164
  int exitstatus = EXIT_SUCCESS;
263
 
  struct sigaction old_sigchld_action;
264
 
  struct sigaction sigchld_action = { .sa_handler = handle_sigchld,
265
 
                                      .sa_flags = SA_NOCLDSTOP };
266
 
  char **custom_argv = NULL;
267
 
  int custom_argc = 0;
268
165
  
269
166
  /* Establish a signal handler */
 
167
  struct sigaction old_sigchld_action,
 
168
    sigchld_action = { .sa_handler = handle_sigchld,
 
169
                       .sa_flags = SA_NOCLDSTOP };
270
170
  sigemptyset(&sigchld_action.sa_mask);
271
171
  ret = sigaddset(&sigchld_action.sa_mask, SIGCHLD);
272
172
  if(ret < 0){
284
184
    { .name = "global-options", .key = 'g',
285
185
      .arg = "OPTION[,OPTION[,...]]",
286
186
      .doc = "Options passed to all plugins" },
287
 
    { .name = "global-envs", .key = 'e',
288
 
      .arg = "VAR=value",
289
 
      .doc = "Environment variable passed to all plugins" },
290
187
    { .name = "options-for", .key = 'o',
291
188
      .arg = "PLUGIN:OPTION[,OPTION[,...]]",
292
189
      .doc = "Options passed only to specified plugin" },
293
 
    { .name = "envs-for", .key = 'f',
294
 
      .arg = "PLUGIN:ENV=value",
295
 
      .doc = "Environment variable passed to specified plugin" },
296
190
    { .name = "disable", .key = 'd',
297
191
      .arg = "PLUGIN",
298
192
      .doc = "Disable a specific plugin", .group = 1 },
299
193
    { .name = "plugin-dir", .key = 128,
300
194
      .arg = "DIRECTORY",
301
195
      .doc = "Specify a different plugin directory", .group = 2 },
302
 
    { .name = "userid", .key = 129,
303
 
      .arg = "ID", .flags = 0,
304
 
      .doc = "User ID the plugins will run as", .group = 2 },
305
 
    { .name = "groupid", .key = 130,
306
 
      .arg = "ID", .flags = 0,
307
 
      .doc = "Group ID the plugins will run as", .group = 2 },
308
 
    { .name = "debug", .key = 131,
 
196
    { .name = "debug", .key = 129,
309
197
      .doc = "Debug mode", .group = 3 },
310
198
    { .name = NULL }
311
199
  };
317
205
    switch (key) {
318
206
    case 'g':
319
207
      if (arg != NULL){
320
 
        char *p;
321
 
        while((p = strsep(&arg, ",")) != NULL){
322
 
          if(p[0] == '\0'){
323
 
            continue;
324
 
          }
325
 
          if(not add_argument(getplugin(NULL, plugins), p)){
326
 
            perror("add_argument");
327
 
            return ARGP_ERR_UNKNOWN;
328
 
          }
329
 
        }
330
 
      }
331
 
      break;
332
 
    case 'e':
333
 
      if(arg == NULL){
334
 
        break;
335
 
      }
336
 
      {
337
 
        char *envdef = strdup(arg);
338
 
        if(envdef == NULL){
339
 
          break;
340
 
        }
341
 
        if(not add_environment(getplugin(NULL, plugins), envdef)){
342
 
          perror("add_environment");
343
 
        }
 
208
        char *p = strtok(arg, ",");
 
209
        do{
 
210
          addargument(getplugin(NULL, plugins), p);
 
211
          p = strtok(NULL, ",");
 
212
        } while (p);
344
213
      }
345
214
      break;
346
215
    case 'o':
347
216
      if (arg != NULL){
348
 
        char *p_name = strsep(&arg, ":");
349
 
        if(p_name[0] == '\0'){
350
 
          break;
351
 
        }
352
 
        char *opt = strsep(&arg, ":");
353
 
        if(opt[0] == '\0'){
354
 
          break;
355
 
        }
356
 
        if(opt != NULL){
357
 
          char *p;
358
 
          while((p = strsep(&opt, ",")) != NULL){
359
 
            if(p[0] == '\0'){
360
 
              continue;
361
 
            }
362
 
            if(not add_argument(getplugin(p_name, plugins), p)){
363
 
              perror("add_argument");
364
 
              return ARGP_ERR_UNKNOWN;
365
 
            }
366
 
          }
367
 
        }
368
 
      }
369
 
      break;
370
 
    case 'f':
371
 
      if(arg == NULL){
372
 
        break;
373
 
      }
374
 
      {
375
 
        char *envdef = strchr(arg, ':');
376
 
        if(envdef == NULL){
377
 
          break;
378
 
        }
379
 
        char *p_name = strndup(arg, (size_t) (envdef-arg));
380
 
        if(p_name == NULL){
381
 
          break;
382
 
        }
383
 
        envdef++;
384
 
        if(not add_environment(getplugin(p_name, plugins), envdef)){
385
 
          perror("add_environment");
 
217
        char *name = strtok(arg, ":");
 
218
        char *p = strtok(NULL, ":");
 
219
        if(p){
 
220
          p = strtok(p, ",");
 
221
          do{
 
222
            addargument(getplugin(name, plugins), p);
 
223
            p = strtok(NULL, ",");
 
224
          } while (p);
386
225
        }
387
226
      }
388
227
      break;
389
228
    case 'd':
390
229
      if (arg != NULL){
391
 
        plugin *p = getplugin(arg, plugins);
392
 
        if(p == NULL){
393
 
          return ARGP_ERR_UNKNOWN;
394
 
        }
395
 
        p->disabled = true;
 
230
        getplugin(arg, plugins)->disabled = true;
396
231
      }
397
232
      break;
398
233
    case 128:
399
234
      plugindir = arg;
400
235
      break;
401
236
    case 129:
402
 
      uid = (uid_t)strtol(arg, NULL, 10);
403
 
      break;
404
 
    case 130:
405
 
      gid = (gid_t)strtol(arg, NULL, 10);
406
 
      break;
407
 
    case 131:
408
237
      debug = true;
409
238
      break;
410
239
    case ARGP_KEY_ARG:
411
 
      fprintf(stderr, "Ignoring unknown argument \"%s\"\n", arg);
 
240
      argp_usage (state);
412
241
      break;
413
242
    case ARGP_KEY_END:
414
243
      break;
421
250
  plugin *plugin_list = NULL;
422
251
  
423
252
  struct argp argp = { .options = options, .parser = parse_opt,
424
 
                       .args_doc = "[+PLUS_SEPARATED_OPTIONS]",
 
253
                       .args_doc = "",
425
254
                       .doc = "Mandos plugin runner -- Run plugins" };
426
255
  
427
 
  ret = argp_parse (&argp, argc, argv, 0, 0, &plugin_list);
428
 
  if (ret == ARGP_ERR_UNKNOWN){
429
 
    fprintf(stderr, "Unknown error while parsing arguments\n");
430
 
    exitstatus = EXIT_FAILURE;
431
 
    goto end;
432
 
  }
433
 
 
434
 
  conffp = fopen(argfile, "r");
435
 
  if(conffp != NULL){
436
 
    char *org_line = NULL;
437
 
    size_t size = 0;
438
 
    ssize_t sret;
439
 
    char *p, *arg, *new_arg, *line;
440
 
    const char whitespace_delims[] = " \r\t\f\v\n";
441
 
    const char comment_delim[] = "#";
442
 
 
443
 
    while(true){
444
 
      sret = getline(&org_line, &size, conffp);
445
 
      if(sret == -1){
446
 
        break;
447
 
      }
448
 
 
449
 
      line = org_line;
450
 
      arg = strsep(&line, comment_delim);
451
 
      while((p = strsep(&arg, whitespace_delims)) != NULL){
452
 
        if(p[0] == '\0'){
453
 
          continue;
454
 
        }
455
 
        new_arg = strdup(p);
456
 
        custom_argv = add_to_argv(custom_argv, &custom_argc, new_arg);
457
 
        if (custom_argv == NULL){
458
 
          perror("add_to_argv");
459
 
          exitstatus = EXIT_FAILURE;
460
 
          goto end;
461
 
        }
462
 
      }
463
 
    }
464
 
    free(org_line);
465
 
  } else{
466
 
    /* Check for harmful errors and go to fallback. Other errors might
467
 
       not affect opening plugins */
468
 
    if (errno == EMFILE or errno == ENFILE or errno == ENOMEM){
469
 
      perror("fopen");
470
 
      exitstatus = EXIT_FAILURE;
471
 
      goto end;
472
 
    }
473
 
  }
474
 
 
475
 
  if(custom_argv != NULL){
476
 
    custom_argv[0] = argv[0];
477
 
    ret = argp_parse (&argp, custom_argc, custom_argv, 0, 0, &plugin_list);
478
 
    if (ret == ARGP_ERR_UNKNOWN){
479
 
      fprintf(stderr, "Unknown error while parsing arguments\n");
480
 
      exitstatus = EXIT_FAILURE;
481
 
      goto end;
482
 
    }
483
 
  }
 
256
  argp_parse (&argp, argc, argv, 0, 0, &plugin_list);
484
257
  
485
258
  if(debug){
486
259
    for(plugin *p = plugin_list; p != NULL; p=p->next){
489
262
      for(char **a = p->argv; *a != NULL; a++){
490
263
        fprintf(stderr, "\tArg: %s\n", *a);
491
264
      }
492
 
      fprintf(stderr, "...and %u environment variables\n", p->envc);
493
 
      for(char **a = p->environ; *a != NULL; a++){
494
 
        fprintf(stderr, "\t%s\n", *a);
495
 
      }
496
265
    }
497
266
  }
498
267
  
499
 
  ret = setuid(uid);
500
 
  if (ret == -1){
501
 
    perror("setuid");
502
 
  }
503
 
  
504
 
  setgid(gid);
505
 
  if (ret == -1){
506
 
    perror("setgid");
507
 
  }
508
 
  
509
268
  dir = opendir(plugindir);
510
269
  if(dir == NULL){
511
270
    perror("Could not open plugin dir");
533
292
    
534
293
    // All directory entries have been processed
535
294
    if(dirst == NULL){
536
 
      if (errno == EBADF){
537
 
        perror("readdir");
538
 
        exitstatus = EXIT_FAILURE;
539
 
        goto end;
540
 
      }
541
295
      break;
542
296
    }
543
297
    
587
341
        continue;
588
342
      }
589
343
    }
590
 
 
591
 
    char *filename;
592
 
    ret = asprintf(&filename, "%s/%s", plugindir, dirst->d_name);
593
 
    if(ret < 0){
594
 
      perror("asprintf");
595
 
      continue;
596
 
    }
597
 
    
598
 
    ret = stat(filename, &st);
599
 
    if (ret == -1){
600
 
      perror("stat");
601
 
      free(filename);
602
 
      continue;
603
 
    }
 
344
    
 
345
    char *filename = malloc(d_name_len + strlen(plugindir) + 2);
 
346
    if (filename == NULL){
 
347
      perror("malloc");
 
348
      exitstatus = EXIT_FAILURE;
 
349
      goto end;
 
350
    }
 
351
    strcpy(filename, plugindir); /* Spurious warning */
 
352
    strcat(filename, "/");      /* Spurious warning */
 
353
    strcat(filename, dirst->d_name); /* Spurious warning */
 
354
    
 
355
    stat(filename, &st);
604
356
    
605
357
    if (not S_ISREG(st.st_mode) or (access(filename, X_OK) != 0)){
606
358
      if(debug){
610
362
      free(filename);
611
363
      continue;
612
364
    }
613
 
    plugin *p = getplugin(dirst->d_name, &plugin_list);
614
 
    if(p == NULL){
615
 
      perror("getplugin");
616
 
      free(filename);
617
 
      continue;
618
 
    }
619
 
    if(p->disabled){
 
365
    if(getplugin(dirst->d_name, &plugin_list)->disabled){
620
366
      if(debug){
621
367
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
622
368
                dirst->d_name);
624
370
      free(filename);
625
371
      continue;
626
372
    }
 
373
    plugin *p = getplugin(dirst->d_name, &plugin_list);
627
374
    {
628
375
      /* Add global arguments to argument list for this plugin */
629
376
      plugin *g = getplugin(NULL, &plugin_list);
630
 
      if(g != NULL){
631
 
        for(char **a = g->argv + 1; *a != NULL; a++){
632
 
          if(not add_argument(p, *a)){
633
 
            perror("add_argument");
634
 
          }
635
 
        }
636
 
        /* Add global environment variables */
637
 
        for(char **e = g->environ; *e != NULL; e++){
638
 
          if(not add_environment(p, *e)){
639
 
            perror("add_environment");
640
 
          }
641
 
        }
642
 
      }
643
 
    }
644
 
    /* If this plugin has any environment variables, we will call
645
 
       using execve and need to duplicate the environment from this
646
 
       process, too. */
647
 
    if(p->environ[0] != NULL){
648
 
      for(char **e = environ; *e != NULL; e++){
649
 
        char *copy = strdup(*e);
650
 
        if(copy == NULL){
651
 
          perror("strdup");
652
 
          continue;
653
 
        }
654
 
        if(not add_environment(p, copy)){
655
 
          perror("add_environment");
656
 
        }
657
 
      }
658
 
    }
659
 
    
 
377
      for(char **a = g->argv + 1; *a != NULL; a++){
 
378
        addargument(p, *a);
 
379
      }
 
380
    }
660
381
    int pipefd[2]; 
661
382
    ret = pipe(pipefd);
662
383
    if (ret == -1){
685
406
    }
686
407
    // Starting a new process to be watched
687
408
    pid_t pid = fork();
688
 
    if(pid == -1){
689
 
      perror("fork");
690
 
      exitstatus = EXIT_FAILURE;
691
 
      goto end;
692
 
    }
693
409
    if(pid == 0){
694
410
      /* this is the child process */
695
411
      ret = sigaction(SIGCHLD, &old_sigchld_action, NULL);
702
418
        perror("sigprocmask");
703
419
        _exit(EXIT_FAILURE);
704
420
      }
705
 
 
706
 
      ret = dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
707
 
      if(ret == -1){
708
 
        perror("dup2");
709
 
        _exit(EXIT_FAILURE);
710
 
      }
 
421
      dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
711
422
      
712
423
      if(dirfd(dir) < 0){
713
424
        /* If dir has no file descriptor, we could not set FD_CLOEXEC
714
425
           above and must now close it manually here. */
715
426
        closedir(dir);
716
427
      }
717
 
      if(p->environ[0] == NULL){
718
 
        if(execv(filename, p->argv) < 0){
719
 
          perror("execv");
720
 
          _exit(EXIT_FAILURE);
721
 
        }
722
 
      } else {
723
 
        if(execve(filename, p->argv, p->environ) < 0){
724
 
          perror("execve");
725
 
          _exit(EXIT_FAILURE);
726
 
        }
 
428
      if(execv(filename, p->argv) < 0){
 
429
        perror("execv");
 
430
        _exit(EXIT_FAILURE);
727
431
      }
728
432
      /* no return */
729
433
    }
767
471
  for(plugin *next; plugin_list != NULL; plugin_list = next){
768
472
    next = plugin_list->next;
769
473
    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
474
    free(plugin_list);
776
475
  }
777
476
  
778
477
  closedir(dir);
779
478
  dir = NULL;
780
 
    
 
479
  
781
480
  if (process_list == NULL){
782
 
    fprintf(stderr, "No plugin processes started. Incorrect plugin"
783
 
            " directory?\n");
784
 
    process_list = NULL;
 
481
    fprintf(stderr, "No plugin processes started, exiting\n");
 
482
    exitstatus = EXIT_FAILURE;
 
483
    goto end;
785
484
  }
786
485
  while(process_list){
787
486
    fd_set rfds = rfds_all;
802
501
          /* Bad exit by plugin */
803
502
          if(debug){
804
503
            if(WIFEXITED(proc->status)){
805
 
              fprintf(stderr, "Plugin %u exited with status %d\n",
806
 
                      (unsigned int) (proc->pid),
807
 
                      WEXITSTATUS(proc->status));
 
504
              fprintf(stderr, "Plugin %d exited with status %d\n",
 
505
                      proc->pid, WEXITSTATUS(proc->status));
808
506
            } else if(WIFSIGNALED(proc->status)) {
809
 
              fprintf(stderr, "Plugin %u killed by signal %d\n",
810
 
                      (unsigned int) (proc->pid),
811
 
                      WTERMSIG(proc->status));
 
507
              fprintf(stderr, "Plugin %d killed by signal %d\n",
 
508
                      proc->pid, WTERMSIG(proc->status));
812
509
            } else if(WCOREDUMP(proc->status)){
813
 
              fprintf(stderr, "Plugin %d dumped core\n",
814
 
                      (unsigned int) (proc->pid));
 
510
              fprintf(stderr, "Plugin %d dumped core\n", proc->pid);
815
511
            }
816
512
          }
817
513
          /* Remove the plugin */
850
546
          break;
851
547
        }
852
548
        /* This process exited nicely, so print its buffer */
853
 
 
854
 
        bool bret = print_out_password(proc->buffer, proc->buffer_length);
855
 
        if(not bret){
856
 
          perror("print_out_password");
857
 
          exitstatus = EXIT_FAILURE;
 
549
        for(size_t written = 0; written < proc->buffer_length;
 
550
            written += (size_t)ret){
 
551
          ret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO,
 
552
                                         proc->buffer + written,
 
553
                                         proc->buffer_length
 
554
                                         - written));
 
555
          if(ret < 0){
 
556
            perror("write");
 
557
            exitstatus = EXIT_FAILURE;
 
558
            goto end;
 
559
          }
858
560
        }
859
561
        goto end;
860
562
      }
889
591
      }
890
592
    }
891
593
  }
892
 
 
893
 
 
 
594
  if(process_list == NULL){
 
595
    fprintf(stderr, "All plugin processes failed, exiting\n");
 
596
    exitstatus = EXIT_FAILURE;
 
597
  }
 
598
  
894
599
 end:
895
 
  
896
 
  if(process_list == NULL or exitstatus != EXIT_SUCCESS){
897
 
    /* Fallback if all plugins failed, none are found or an error occured */
898
 
    bool bret;
899
 
    fprintf(stderr, "Going to fallback mode using getpass(3)\n");
900
 
    char *passwordbuffer = getpass("Password: ");
901
 
    bret = print_out_password(passwordbuffer, strlen(passwordbuffer));
902
 
    if(not bret){
903
 
      perror("print_out_password");
904
 
      exitstatus = EXIT_FAILURE;
905
 
      goto end;
906
 
    }
907
 
  }
908
 
  
909
600
  /* Restore old signal handler */
910
601
  sigaction(SIGCHLD, &old_sigchld_action, NULL);
911
602
  
912
 
  free(custom_argv);
913
 
  
914
603
  /* Free the plugin list */
915
604
  for(plugin *next; plugin_list != NULL; plugin_list = next){
916
605
    next = plugin_list->next;
917
606
    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
 
      }
922
 
    }
923
 
    free(plugin_list->environ);
924
607
    free(plugin_list);
925
608
  }
926
609
  
932
615
  for(process *next; process_list != NULL; process_list = next){
933
616
    next = process_list->next;
934
617
    close(process_list->fd);
935
 
    ret = kill(process_list->pid, SIGTERM);
936
 
    if(ret == -1 and errno != ESRCH){
937
 
      /* set-uid proccesses migth not get closed */
938
 
      perror("kill");
939
 
    }
 
618
    kill(process_list->pid, SIGTERM);
940
619
    free(process_list->buffer);
941
620
    free(process_list);
942
621
  }