/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 plugbasedclient.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-01 20:03:03 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080801200303-3xjn9gjewg87365i
* plugbasedclient.c (main): Check if plugin dir could be opened.  Set
                            FD_CLOEXEC on the directory, if possible,
                            and also on both ends of the pipe.  Do not
                            allocate buffer for process in advance.
                            Free the plugin list.  Bug fix: exit if no
                            plugins found, not if any found.  Set
                            "exitstatus" in many places.  Simplify and
                            un-indent the loop reading process pipes.
                            Renamed process list iterator to "proc".
                            Bug fix:  retry password write on EINTR.
                            Free the process list properly, including
                            the process structs themselves.

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() */
 
25
 
24
26
#include <stdio.h>              /* popen(), fileno(), fprintf(),
25
27
                                   stderr, STDOUT_FILENO */
26
28
#include <iso646.h>             /* and, or, not */
27
 
#include <sys/types.h>         /* DIR, opendir(), stat(), struct stat,
28
 
                                  waitpid(), WIFEXITED(),
29
 
                                  WEXITSTATUS(), wait() */
 
29
#include <sys/types.h>          /* DIR, opendir(), stat(),
 
30
                                   struct stat, waitpid(),
 
31
                                   WIFEXITED(), WEXITSTATUS(),
 
32
                                   wait() */
30
33
#include <sys/wait.h>           /* wait() */
31
34
#include <dirent.h>             /* DIR, struct dirent, opendir(),
32
35
                                   readdir(), closedir() */
229
232
  }
230
233
  
231
234
  dir = opendir(plugindir);
232
 
  /* Set the FD_CLOEXEC flag on the directory */
233
 
  ret = set_cloexec_flag(dirfd(dir));
234
 
  if(ret < 0){
235
 
    perror("set_cloexec_flag");
 
235
  if(dir == NULL){
 
236
    perror("Could not open plugin dir");
 
237
    exitstatus = EXIT_FAILURE;
236
238
    goto end;
237
239
  }
 
240
  /* Set the FD_CLOEXEC flag on the directory, if possible */
 
241
  {
 
242
    int dir_fd = dirfd(dir);
 
243
    if(dir_fd >= 0){
 
244
      ret = set_cloexec_flag(dir_fd);
 
245
      if(ret < 0){
 
246
        perror("set_cloexec_flag");
 
247
        exitstatus = EXIT_FAILURE;
 
248
        goto end;
 
249
      }
 
250
    }
 
251
  }
238
252
  
239
253
  if(dir == NULL){
240
254
    fprintf(stderr, "Can not open directory\n");
267
281
        if((d_name_len >= pre_len)
268
282
           and strncmp((dirst->d_name), *pre, pre_len) == 0){
269
283
          if(debug){
270
 
            fprintf(stderr, "Ignoring plugin dir entry name \"%s\""
 
284
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
271
285
                    " with bad prefix %s\n", dirst->d_name, *pre);
272
286
          }
273
287
          bad_name = true;
285
299
           and (strcmp((dirst->d_name)+d_name_len-suf_len, *suf)
286
300
                == 0)){
287
301
          if(debug){
288
 
            fprintf(stderr, "Ignoring plugin dir entry name \"%s\""
 
302
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
289
303
                    " with bad suffix %s\n", dirst->d_name, *suf);
290
304
          }
291
305
          bad_name = true;
301
315
    char *filename = malloc(d_name_len + strlen(plugindir) + 2);
302
316
    if (filename == NULL){
303
317
      perror("malloc");
304
 
      exitstatus =EXIT_FAILURE;
 
318
      exitstatus = EXIT_FAILURE;
305
319
      goto end;
306
320
    }
307
321
    strcpy(filename, plugindir);
312
326
 
313
327
    if (not S_ISREG(st.st_mode) or (access(filename, X_OK) != 0)){
314
328
      if(debug){
315
 
        fprintf(stderr, "Ignoring plugin dir entry name \"%s\""
 
329
        fprintf(stderr, "Ignoring plugin dir entry \"%s\""
316
330
                " with bad type or mode\n", filename);
317
331
      }
318
332
      continue;
319
333
    }
320
334
    if(getplugin(dirst->d_name, &plugin_list)->disabled){
321
335
      if(debug){
322
 
        fprintf(stderr, "Ignoring disabled plugin \"%s\"",
 
336
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
323
337
                dirst->d_name);
324
338
      }
325
339
      continue;
326
340
    }
327
 
    // Starting a new process to be watched
328
 
    int pipefd[2]; 
329
 
    ret = pipe(pipefd);
330
 
    if (ret == -1){
331
 
      perror("pipe");
332
 
      goto end;
333
 
    }
334
341
    plugin *p = getplugin(dirst->d_name, &plugin_list);
335
342
    {
336
343
      /* Add global arguments to argument list for this plugin */
339
346
        addargument(p, *a);
340
347
      }
341
348
    }
 
349
    int pipefd[2]; 
 
350
    ret = pipe(pipefd);
 
351
    if (ret == -1){
 
352
      perror("pipe");
 
353
      exitstatus = EXIT_FAILURE;
 
354
      goto end;
 
355
    }
 
356
    ret = set_cloexec_flag(pipefd[0]);
 
357
    if(ret < 0){
 
358
      perror("set_cloexec_flag");
 
359
      exitstatus = EXIT_FAILURE;
 
360
      goto end;
 
361
    }
 
362
    ret = set_cloexec_flag(pipefd[1]);
 
363
    if(ret < 0){
 
364
      perror("set_cloexec_flag");
 
365
      exitstatus = EXIT_FAILURE;
 
366
      goto end;
 
367
    }
 
368
    // Starting a new process to be watched
342
369
    pid_t pid = fork();
343
370
    if(pid == 0){
344
371
      /* this is the child process */
345
 
      closedir(dir);
346
 
      close(pipefd[0]); /* close unused read end of pipe */
347
372
      dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
348
 
      if(pipefd[1] > 2){
349
 
        close(pipefd[1]);
 
373
      
 
374
      if(dirfd(dir) < 0){
 
375
        /* If dir has no file descriptor, we could not set FD_CLOEXEC
 
376
           and must close it manually  */
 
377
        closedir(dir);
350
378
      }
351
 
      
352
379
      if(execv(filename, p->argv) < 0){
353
 
        perror(argv[0]);
354
 
        close(pipefd[1]);
 
380
        perror("execv");
355
381
        _exit(EXIT_FAILURE);
356
382
      }
357
383
      /* no return */
358
384
    }
 
385
    /* parent process */
359
386
    close(pipefd[1]);           /* close unused write end of pipe */
360
387
    process *new_process = malloc(sizeof(process));
361
388
    if (new_process == NULL){
364
391
      goto end;
365
392
    }
366
393
    
367
 
    new_process->fd = pipefd[0];
368
 
    new_process->buffer = malloc(BUFFER_SIZE);
369
 
    if (new_process->buffer == NULL){
370
 
      perror("malloc");
371
 
      exitstatus = EXIT_FAILURE;
372
 
      goto end;
373
 
    }
374
 
    new_process->buffer_size = BUFFER_SIZE;
375
 
    new_process->buffer_length = 0;
 
394
    *new_process = (struct process){ .pid = pid,
 
395
                                     .fd = pipefd[0],
 
396
                                     .next = process_list };
376
397
    FD_SET(new_process->fd, &rfds_all);
377
 
      
 
398
    
378
399
    if (maxfd < new_process->fd){
379
400
      maxfd = new_process->fd;
380
401
    }
381
402
    
382
403
    //List handling
383
 
    new_process->next = process_list;
384
404
    process_list = new_process;
385
405
  }
386
406
  
 
407
  /* Free the plugin list */
 
408
  for(plugin *next; plugin_list != NULL; plugin_list = next){
 
409
    next = plugin_list->next;
 
410
    free(plugin_list->argv);
 
411
    free(plugin_list);
 
412
  }
 
413
  
387
414
  closedir(dir);
388
415
  
389
 
  if (process_list != NULL){
390
 
    while(true){
391
 
      fd_set rfds = rfds_all;
392
 
      int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
393
 
      if (select_ret == -1){
394
 
        perror(argv[0]);
 
416
  if (process_list == NULL){
 
417
    fprintf(stderr, "No plugin processes started, exiting\n");
 
418
    return EXIT_FAILURE;
 
419
  }
 
420
  while(true){
 
421
    fd_set rfds = rfds_all;
 
422
    int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
 
423
    if (select_ret == -1){
 
424
      perror("select");
 
425
      exitstatus = EXIT_FAILURE;
 
426
      goto end;
 
427
    }
 
428
    for(process *proc = process_list; proc ; proc = proc->next){
 
429
      if(not FD_ISSET(proc->fd, &rfds)){
 
430
        continue;
 
431
      }
 
432
      if(proc->buffer_length + BUFFER_SIZE > proc->buffer_size){
 
433
        proc->buffer = realloc(proc->buffer, proc->buffer_size
 
434
                               + (size_t) BUFFER_SIZE);
 
435
        if (proc->buffer == NULL){
 
436
          perror("malloc");
 
437
          exitstatus = EXIT_FAILURE;
 
438
          goto end;
 
439
        }
 
440
        proc->buffer_size += BUFFER_SIZE;
 
441
      }
 
442
      ret = read(proc->fd, proc->buffer + proc->buffer_length,
 
443
                 BUFFER_SIZE);
 
444
      if(ret < 0){
 
445
        /* Read error from this process; ignore it */
 
446
        continue;
 
447
      }
 
448
      proc->buffer_length += (size_t) ret;
 
449
      if(ret == 0){
 
450
        /* got EOF */
 
451
        /* wait for process exit */
 
452
        int status;
 
453
        waitpid(proc->pid, &status, 0);
 
454
        if(not WIFEXITED(status) or WEXITSTATUS(status) != 0){
 
455
          FD_CLR(proc->fd, &rfds_all);
 
456
          continue;
 
457
        }
 
458
        for(size_t written = 0;
 
459
            written < proc->buffer_length; written += (size_t)ret){
 
460
          ret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO,
 
461
                                         proc->buffer + written,
 
462
                                         proc->buffer_length
 
463
                                         - written));
 
464
          if(ret < 0){
 
465
            perror("write");
 
466
            exitstatus = EXIT_FAILURE;
 
467
            goto end;
 
468
          }
 
469
        }
395
470
        goto end;
396
 
      }else{    
397
 
        for(process *process_itr = process_list; process_itr != NULL;
398
 
            process_itr = process_itr->next){
399
 
          if(FD_ISSET(process_itr->fd, &rfds)){
400
 
            if(process_itr->buffer_length + BUFFER_SIZE
401
 
               > process_itr->buffer_size){
402
 
                process_itr->buffer = realloc(process_itr->buffer,
403
 
                                              process_itr->buffer_size
404
 
                                              + (size_t) BUFFER_SIZE);
405
 
                if (process_itr->buffer == NULL){
406
 
                  perror(argv[0]);
407
 
                  goto end;
408
 
                }
409
 
                process_itr->buffer_size += BUFFER_SIZE;
410
 
            }
411
 
            ret = read(process_itr->fd, process_itr->buffer
412
 
                       + process_itr->buffer_length, BUFFER_SIZE);
413
 
            if(ret < 0){
414
 
              /* Read error from this process; ignore it */
415
 
              continue;
416
 
            }
417
 
            process_itr->buffer_length += (size_t) ret;
418
 
            if(ret == 0){
419
 
              /* got EOF */
420
 
              /* wait for process exit */
421
 
              int status;
422
 
              waitpid(process_itr->pid, &status, 0);
423
 
              if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
424
 
                for(size_t written = 0;
425
 
                    written < process_itr->buffer_length;){
426
 
                  ret = write(STDOUT_FILENO,
427
 
                              process_itr->buffer + written,
428
 
                              process_itr->buffer_length - written);
429
 
                  if(ret < 0){
430
 
                    perror(argv[0]);
431
 
                    goto end;
432
 
                  }
433
 
                  written += (size_t)ret;
434
 
                }
435
 
                goto end;
436
 
              } else {
437
 
                FD_CLR(process_itr->fd, &rfds_all);
438
 
              }
439
 
            }
440
 
          }
441
 
        }
442
471
      }
443
472
    }
444
473
  }
445
474
  
446
475
 end:
447
 
  for(process *process_itr = process_list; process_itr != NULL;
448
 
      process_itr = process_itr->next){
449
 
    close(process_itr->fd);
450
 
    kill(process_itr->pid, SIGTERM);
451
 
    free(process_itr->buffer);
 
476
  for(process *next; process_list != NULL; process_list = next){
 
477
    close(process_list->fd);
 
478
    kill(process_list->pid, SIGTERM);
 
479
    free(process_list->buffer);
 
480
    free(process_list);
452
481
  }
453
482
  
454
483
  while(true){