/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 plugins.d/password-request.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:
32
32
#define _LARGEFILE_SOURCE
33
33
#define _FILE_OFFSET_BITS 64
34
34
 
35
 
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY() */
 
35
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
36
36
 
37
 
#include <stdio.h>
38
 
#include <assert.h>
39
 
#include <stdlib.h>
40
 
#include <time.h>
41
 
#include <net/if.h>             /* if_nametoindex */
42
 
#include <sys/ioctl.h>          /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
43
 
                                   SIOCSIFFLAGS */
 
37
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
 
38
                                   stdout, ferror() */
 
39
#include <stdint.h>             /* uint16_t, uint32_t */
 
40
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
41
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
 
42
                                   srand() */
 
43
#include <stdbool.h>            /* bool, true */
 
44
#include <string.h>             /* memset(), strcmp(), strlen(),
 
45
                                   strerror(), asprintf(), strcpy() */
 
46
#include <sys/ioctl.h>          /* ioctl */
 
47
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
 
48
                                   sockaddr_in6, PF_INET6,
 
49
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
 
50
                                   uid_t, gid_t */
 
51
#include <inttypes.h>           /* PRIu16 */
 
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
53
                                   struct in6_addr, inet_pton(),
 
54
                                   connect() */
 
55
#include <assert.h>             /* assert() */
 
56
#include <errno.h>              /* perror(), errno */
 
57
#include <time.h>               /* time() */
44
58
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
45
 
                                   SIOCSIFFLAGS */
 
59
                                   SIOCSIFFLAGS, if_indextoname(),
 
60
                                   if_nametoindex(), IF_NAMESIZE */
 
61
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
 
62
                                   getuid(), getgid(), setuid(),
 
63
                                   setgid() */
 
64
#include <netinet/in.h>
 
65
#include <arpa/inet.h>          /* inet_pton(), htons */
 
66
#include <iso646.h>             /* not, and */
 
67
#include <argp.h>               /* struct argp_option, error_t, struct
 
68
                                   argp_state, struct argp,
 
69
                                   argp_parse(), ARGP_KEY_ARG,
 
70
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
46
71
 
 
72
/* Avahi */
 
73
/* All Avahi types, constants and functions
 
74
 Avahi*, avahi_*,
 
75
 AVAHI_* */
47
76
#include <avahi-core/core.h>
48
77
#include <avahi-core/lookup.h>
49
78
#include <avahi-core/log.h>
51
80
#include <avahi-common/malloc.h>
52
81
#include <avahi-common/error.h>
53
82
 
54
 
/* Mandos client part */
55
 
#include <sys/types.h>          /* socket(), inet_pton() */
56
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
57
 
                                   struct in6_addr, inet_pton() */
58
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
59
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
 
83
/* GnuTLS */
 
84
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and
 
85
                                   functions:
 
86
                                   gnutls_*
 
87
                                   init_gnutls_session(),
 
88
                                   GNUTLS_* */
 
89
#include <gnutls/openpgp.h>     /* gnutls_certificate_set_openpgp_key_file(),
 
90
                                   GNUTLS_OPENPGP_FMT_BASE64 */
60
91
 
61
 
#include <unistd.h>             /* close() */
62
 
#include <netinet/in.h>
63
 
#include <stdbool.h>            /* true */
64
 
#include <string.h>             /* memset */
65
 
#include <arpa/inet.h>          /* inet_pton() */
66
 
#include <iso646.h>             /* not */
67
 
#include <net/if.h>             /* IF_NAMESIZE */
68
 
#include <argp.h>               /* struct argp_option,
69
 
                                   struct argp_state, struct argp,
70
 
                                   argp_parse() */
71
92
/* GPGME */
72
 
#include <errno.h>              /* perror() */
73
 
#include <gpgme.h>
 
93
#include <gpgme.h>              /* All GPGME types, constants and
 
94
                                   functions:
 
95
                                   gpgme_*
 
96
                                   GPGME_PROTOCOL_OpenPGP,
 
97
                                   GPG_ERR_NO_* */
74
98
 
75
99
#define BUFFER_SIZE 256
76
100
 
77
101
bool debug = false;
78
102
static const char *keydir = "/conf/conf.d/mandos";
79
103
static const char mandos_protocol_version[] = "1";
80
 
const char *argp_program_version = "mandosclient 0.9";
 
104
const char *argp_program_version = "password-request 1.0";
81
105
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
82
106
 
83
107
/* Used for passing in values through the Avahi callback functions */
205
229
    } else {
206
230
      fprintf(stderr, "Unsupported algorithm: %s\n",
207
231
              result->unsupported_algorithm);
208
 
      fprintf(stderr, "Wrong key usage: %d\n",
 
232
      fprintf(stderr, "Wrong key usage: %u\n",
209
233
              result->wrong_key_usage);
210
234
      if(result->file_name != NULL){
211
235
        fprintf(stderr, "File name: %s\n", result->file_name);
291
315
}
292
316
 
293
317
static int init_gnutls_global(mandos_context *mc,
294
 
                              const char *pubkeyfile,
295
 
                              const char *seckeyfile){
 
318
                              const char *pubkeyfilename,
 
319
                              const char *seckeyfilename){
296
320
  int ret;
297
321
  
298
322
  if(debug){
299
323
    fprintf(stderr, "Initializing GnuTLS\n");
300
324
  }
301
 
 
302
 
  if ((ret = gnutls_global_init ())
303
 
      != GNUTLS_E_SUCCESS) {
 
325
  
 
326
  ret = gnutls_global_init();
 
327
  if (ret != GNUTLS_E_SUCCESS) {
304
328
    fprintf (stderr, "GnuTLS global_init: %s\n",
305
329
             safer_gnutls_strerror(ret));
306
330
    return -1;
315
339
  }
316
340
  
317
341
  /* OpenPGP credentials */
318
 
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
319
 
      != GNUTLS_E_SUCCESS) {
 
342
  gnutls_certificate_allocate_credentials(&mc->cred);
 
343
  if (ret != GNUTLS_E_SUCCESS){
320
344
    fprintf (stderr, "GnuTLS memory error: %s\n",
321
345
             safer_gnutls_strerror(ret));
 
346
    gnutls_global_deinit ();
322
347
    return -1;
323
348
  }
324
349
  
325
350
  if(debug){
326
351
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
327
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
328
 
            seckeyfile);
 
352
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
 
353
            seckeyfilename);
329
354
  }
330
355
  
331
356
  ret = gnutls_certificate_set_openpgp_key_file
332
 
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
357
    (mc->cred, pubkeyfilename, seckeyfilename,
 
358
     GNUTLS_OPENPGP_FMT_BASE64);
333
359
  if (ret != GNUTLS_E_SUCCESS) {
334
360
    fprintf(stderr,
335
361
            "Error[%d] while reading the OpenPGP key pair ('%s',"
336
 
            " '%s')\n", ret, pubkeyfile, seckeyfile);
 
362
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
337
363
    fprintf(stdout, "The GnuTLS error is: %s\n",
338
364
            safer_gnutls_strerror(ret));
339
 
    return -1;
 
365
    goto globalfail;
340
366
  }
341
367
  
342
368
  /* GnuTLS server initialization */
344
370
  if (ret != GNUTLS_E_SUCCESS) {
345
371
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
346
372
             " %s\n", safer_gnutls_strerror(ret));
347
 
    return -1;
 
373
    goto globalfail;
348
374
  }
349
375
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
350
376
  if (ret != GNUTLS_E_SUCCESS) {
351
377
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
352
378
             safer_gnutls_strerror(ret));
353
 
    return -1;
 
379
    goto globalfail;
354
380
  }
355
381
  
356
382
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
357
383
 
358
384
  return 0;
 
385
 
 
386
 globalfail:
 
387
 
 
388
  gnutls_certificate_free_credentials(mc->cred);
 
389
  gnutls_global_deinit();
 
390
  return -1;
 
391
 
359
392
}
360
393
 
361
394
static int init_gnutls_session(mandos_context *mc,
375
408
      fprintf(stderr, "Syntax error at: %s\n", err);
376
409
      fprintf(stderr, "GnuTLS error: %s\n",
377
410
              safer_gnutls_strerror(ret));
 
411
      gnutls_deinit (*session);
378
412
      return -1;
379
413
    }
380
414
  }
384
418
  if (ret != GNUTLS_E_SUCCESS) {
385
419
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
386
420
            safer_gnutls_strerror(ret));
 
421
    gnutls_deinit (*session);
387
422
    return -1;
388
423
  }
389
424
  
422
457
  }
423
458
  
424
459
  if(debug){
425
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
426
 
            ip, port);
 
460
    fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16
 
461
            "\n", ip, port);
427
462
  }
428
463
  
429
464
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
440
475
    fprintf(stderr, "Binding to interface %s\n", interface);
441
476
  }
442
477
  
443
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
 
478
  memset(&to, 0, sizeof(to));   /* Spurious warning */
444
479
  to.in6.sin6_family = AF_INET6;
445
480
  /* It would be nice to have a way to detect if we were passed an
446
481
     IPv4 address here.   Now we assume an IPv6 address. */
453
488
    fprintf(stderr, "Bad address: %s\n", ip);
454
489
    return -1;
455
490
  }
456
 
  to.in6.sin6_port = htons(port);       /* Spurious warning */
 
491
  to.in6.sin6_port = htons(port); /* Spurious warning */
457
492
  
458
493
  to.in6.sin6_scope_id = (uint32_t)if_index;
459
494
  
460
495
  if(debug){
461
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
 
496
    fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
497
            port);
462
498
    char addrstr[INET6_ADDRSTRLEN] = "";
463
499
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
464
500
                 sizeof(addrstr)) == NULL){
505
541
  }
506
542
  
507
543
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
508
 
  
509
 
  ret = gnutls_handshake (session);
 
544
 
 
545
  do{
 
546
    ret = gnutls_handshake (session);
 
547
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
510
548
  
511
549
  if (ret != GNUTLS_E_SUCCESS){
512
550
    if(debug){
544
582
      case GNUTLS_E_AGAIN:
545
583
        break;
546
584
      case GNUTLS_E_REHANDSHAKE:
547
 
        ret = gnutls_handshake (session);
 
585
        do{
 
586
          ret = gnutls_handshake (session);
 
587
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
548
588
        if (ret < 0){
549
589
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
550
590
          gnutls_perror (ret);
603
643
  free(buffer);
604
644
  close(tcp_sd);
605
645
  gnutls_deinit (session);
606
 
  gnutls_certificate_free_credentials (mc->cred);
607
 
  gnutls_global_deinit ();
608
646
  return retval;
609
647
}
610
648
 
641
679
      char ip[AVAHI_ADDRESS_STR_MAX];
642
680
      avahi_address_snprint(ip, sizeof(ip), address);
643
681
      if(debug){
644
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %d) on"
645
 
                " port %d\n", name, host_name, ip, interface, port);
 
682
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
 
683
                PRIu16 ") on port %d\n", name, host_name, ip,
 
684
                interface, port);
646
685
      }
647
686
      int ret = start_mandos_communication(ip, port, interface, mc);
648
687
      if (ret == 0){
649
 
        exit(EXIT_SUCCESS);
 
688
        avahi_simple_poll_quit(mc->simple_poll);
650
689
      }
651
690
    }
652
691
  }
706
745
 
707
746
/* Combines file name and path and returns the malloced new
708
747
   string. some sane checks could/should be added */
709
 
static const char *combinepath(const char *first, const char *second){
710
 
  size_t f_len = strlen(first);
711
 
  size_t s_len = strlen(second);
712
 
  char *tmp = malloc(f_len + s_len + 2);
713
 
  if (tmp == NULL){
 
748
static char *combinepath(const char *first, const char *second){
 
749
  char *tmp;
 
750
  int ret = asprintf(&tmp, "%s/%s", first, second);
 
751
  if(ret < 0){
714
752
    return NULL;
715
753
  }
716
 
  if(f_len > 0){
717
 
    memcpy(tmp, first, f_len);  /* Spurious warning */
718
 
  }
719
 
  tmp[f_len] = '/';
720
 
  if(s_len > 0){
721
 
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
722
 
  }
723
 
  tmp[f_len + 1 + s_len] = '\0';
724
754
  return tmp;
725
755
}
726
756
 
737
767
    gid_t gid;
738
768
    char *connect_to = NULL;
739
769
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
740
 
    const char *pubkeyfile = "pubkey.txt";
741
 
    const char *seckeyfile = "seckey.txt";
 
770
    char *pubkeyfilename = NULL;
 
771
    char *seckeyfilename = NULL;
 
772
    const char *pubkeyname = "pubkey.txt";
 
773
    const char *seckeyname = "seckey.txt";
742
774
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
743
775
                          .dh_bits = 1024, .priority = "SECURE256"};
 
776
    bool gnutls_initalized = false;
744
777
    
745
778
    {
746
779
      struct argp_option options[] = {
795
828
          keydir = arg;
796
829
          break;
797
830
        case 's':
798
 
          seckeyfile = arg;
 
831
          seckeyname = arg;
799
832
          break;
800
833
        case 'p':
801
 
          pubkeyfile = arg;
 
834
          pubkeyname = arg;
802
835
          break;
803
836
        case 129:
804
837
          errno = 0;
813
846
          break;
814
847
        case ARGP_KEY_ARG:
815
848
          argp_usage (state);
 
849
        case ARGP_KEY_END:
816
850
          break;
817
 
          case ARGP_KEY_END:
818
 
            break;
819
851
        default:
820
852
          return ARGP_ERR_UNKNOWN;
821
853
        }
826
858
                           .args_doc = "",
827
859
                           .doc = "Mandos client -- Get and decrypt"
828
860
                           " passwords from mandos server" };
829
 
      argp_parse (&argp, argc, argv, 0, 0, NULL);
 
861
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
862
      if (ret == ARGP_ERR_UNKNOWN){
 
863
        fprintf(stderr, "Unknown error while parsing arguments\n");
 
864
        exitcode = EXIT_FAILURE;
 
865
        goto end;
 
866
      }
830
867
    }
831
868
      
832
 
    pubkeyfile = combinepath(keydir, pubkeyfile);
833
 
    if (pubkeyfile == NULL){
 
869
    pubkeyfilename = combinepath(keydir, pubkeyname);
 
870
    if (pubkeyfilename == NULL){
834
871
      perror("combinepath");
835
872
      exitcode = EXIT_FAILURE;
836
873
      goto end;
837
874
    }
838
875
    
839
 
    seckeyfile = combinepath(keydir, seckeyfile);
840
 
    if (seckeyfile == NULL){
 
876
    seckeyfilename = combinepath(keydir, seckeyname);
 
877
    if (seckeyfilename == NULL){
841
878
      perror("combinepath");
 
879
      exitcode = EXIT_FAILURE;
842
880
      goto end;
843
881
    }
844
882
 
845
 
    ret = init_gnutls_global(&mc, pubkeyfile, seckeyfile);
 
883
    ret = init_gnutls_global(&mc, pubkeyfilename, seckeyfilename);
846
884
    if (ret == -1){
847
 
      fprintf(stderr, "init_gnutls_global\n");
 
885
      fprintf(stderr, "init_gnutls_global failed\n");
 
886
      exitcode = EXIT_FAILURE;
848
887
      goto end;
849
 
    }
850
 
 
 
888
    } else {
 
889
      gnutls_initalized = true;
 
890
    }
 
891
    
 
892
    /* If the interface is down, bring it up */
 
893
    {
 
894
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
895
      if(sd < 0) {
 
896
        perror("socket");
 
897
        exitcode = EXIT_FAILURE;
 
898
        goto end;
 
899
      }
 
900
      strcpy(network.ifr_name, interface); /* Spurious warning */
 
901
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
902
      if(ret == -1){
 
903
        perror("ioctl SIOCGIFFLAGS");
 
904
        exitcode = EXIT_FAILURE;
 
905
        goto end;
 
906
      }
 
907
      if((network.ifr_flags & IFF_UP) == 0){
 
908
        network.ifr_flags |= IFF_UP;
 
909
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
910
        if(ret == -1){
 
911
          perror("ioctl SIOCSIFFLAGS");
 
912
          exitcode = EXIT_FAILURE;
 
913
          goto end;
 
914
        }
 
915
      }
 
916
      close(sd);
 
917
    }
 
918
    
851
919
    uid = getuid();
852
920
    gid = getgid();
853
 
 
 
921
    
854
922
    ret = setuid(uid);
855
923
    if (ret == -1){
856
924
      perror("setuid");
894
962
      goto end;
895
963
    }
896
964
    
897
 
    /* If the interface is down, bring it up */
898
 
    {
899
 
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
900
 
      if(sd < 0) {
901
 
        perror("socket");
902
 
        exitcode = EXIT_FAILURE;
903
 
        goto end;
904
 
      }
905
 
      strcpy(network.ifr_name, interface); /* Spurious warning */
906
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
907
 
      if(ret == -1){
908
 
        perror("ioctl SIOCGIFFLAGS");
909
 
        exitcode = EXIT_FAILURE;
910
 
        goto end;
911
 
      }
912
 
      if((network.ifr_flags & IFF_UP) == 0){
913
 
        network.ifr_flags |= IFF_UP;
914
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
915
 
        if(ret == -1){
916
 
          perror("ioctl SIOCSIFFLAGS");
917
 
          exitcode = EXIT_FAILURE;
918
 
          goto end;
919
 
        }
920
 
      }
921
 
      close(sd);
922
 
    }
923
 
    
924
965
    if (not debug){
925
966
      avahi_set_log_function(empty_log);
926
967
    }
998
1039
 
999
1040
    if (mc.simple_poll != NULL)
1000
1041
        avahi_simple_poll_free(mc.simple_poll);
1001
 
    free(pubkeyfile);
1002
 
    free(seckeyfile);
 
1042
    free(pubkeyfilename);
 
1043
    free(seckeyfilename);
 
1044
 
 
1045
    if (gnutls_initalized){
 
1046
      gnutls_certificate_free_credentials(mc.cred);
 
1047
      gnutls_global_deinit ();
 
1048
    }
1003
1049
    
1004
1050
    return exitcode;
1005
1051
}