/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 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
 
const char *argp_program_version = "mandosclient 0.9";
 
103
static const char mandos_protocol_version[] = "1";
 
104
const char *argp_program_version = "password-request 1.0";
80
105
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
81
 
static const char mandos_protocol_version[] = "1";
82
106
 
83
107
/* Used for passing in values through the Avahi callback functions */
84
108
typedef struct {
90
114
  const char *priority;
91
115
} mandos_context;
92
116
 
93
 
/* Make room in "buffer" for at least BUFFER_SIZE additional bytes.
 
117
/*
 
118
 * Make room in "buffer" for at least BUFFER_SIZE additional bytes.
94
119
 * "buffer_capacity" is how much is currently allocated,
95
 
 * "buffer_length" is how much is already used. */
 
120
 * "buffer_length" is how much is already used.
 
121
 */
96
122
size_t adjustbuffer(char **buffer, size_t buffer_length,
97
123
                  size_t buffer_capacity){
98
124
  if (buffer_length + BUFFER_SIZE > buffer_capacity){
203
229
    } else {
204
230
      fprintf(stderr, "Unsupported algorithm: %s\n",
205
231
              result->unsupported_algorithm);
206
 
      fprintf(stderr, "Wrong key usage: %d\n",
 
232
      fprintf(stderr, "Wrong key usage: %u\n",
207
233
              result->wrong_key_usage);
208
234
      if(result->file_name != NULL){
209
235
        fprintf(stderr, "File name: %s\n", result->file_name);
289
315
}
290
316
 
291
317
static int init_gnutls_global(mandos_context *mc,
292
 
                              const char *pubkeyfile,
293
 
                              const char *seckeyfile){
 
318
                              const char *pubkeyfilename,
 
319
                              const char *seckeyfilename){
294
320
  int ret;
295
321
  
296
322
  if(debug){
297
323
    fprintf(stderr, "Initializing GnuTLS\n");
298
324
  }
299
 
 
300
 
  if ((ret = gnutls_global_init ())
301
 
      != GNUTLS_E_SUCCESS) {
 
325
  
 
326
  ret = gnutls_global_init();
 
327
  if (ret != GNUTLS_E_SUCCESS) {
302
328
    fprintf (stderr, "GnuTLS global_init: %s\n",
303
329
             safer_gnutls_strerror(ret));
304
330
    return -1;
313
339
  }
314
340
  
315
341
  /* OpenPGP credentials */
316
 
  if ((ret = gnutls_certificate_allocate_credentials (&mc->cred))
317
 
      != GNUTLS_E_SUCCESS) {
 
342
  gnutls_certificate_allocate_credentials(&mc->cred);
 
343
  if (ret != GNUTLS_E_SUCCESS){
318
344
    fprintf (stderr, "GnuTLS memory error: %s\n",
319
345
             safer_gnutls_strerror(ret));
 
346
    gnutls_global_deinit ();
320
347
    return -1;
321
348
  }
322
349
  
323
350
  if(debug){
324
351
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
325
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
326
 
            seckeyfile);
 
352
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
 
353
            seckeyfilename);
327
354
  }
328
355
  
329
356
  ret = gnutls_certificate_set_openpgp_key_file
330
 
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
357
    (mc->cred, pubkeyfilename, seckeyfilename,
 
358
     GNUTLS_OPENPGP_FMT_BASE64);
331
359
  if (ret != GNUTLS_E_SUCCESS) {
332
360
    fprintf(stderr,
333
361
            "Error[%d] while reading the OpenPGP key pair ('%s',"
334
 
            " '%s')\n", ret, pubkeyfile, seckeyfile);
 
362
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
335
363
    fprintf(stdout, "The GnuTLS error is: %s\n",
336
364
            safer_gnutls_strerror(ret));
337
 
    return -1;
 
365
    goto globalfail;
338
366
  }
339
367
  
340
368
  /* GnuTLS server initialization */
342
370
  if (ret != GNUTLS_E_SUCCESS) {
343
371
    fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
344
372
             " %s\n", safer_gnutls_strerror(ret));
345
 
    return -1;
 
373
    goto globalfail;
346
374
  }
347
375
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
348
376
  if (ret != GNUTLS_E_SUCCESS) {
349
377
    fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
350
378
             safer_gnutls_strerror(ret));
351
 
    return -1;
 
379
    goto globalfail;
352
380
  }
353
381
  
354
382
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
355
383
 
356
384
  return 0;
 
385
 
 
386
 globalfail:
 
387
 
 
388
  gnutls_certificate_free_credentials(mc->cred);
 
389
  gnutls_global_deinit();
 
390
  return -1;
 
391
 
357
392
}
358
393
 
359
394
static int init_gnutls_session(mandos_context *mc,
373
408
      fprintf(stderr, "Syntax error at: %s\n", err);
374
409
      fprintf(stderr, "GnuTLS error: %s\n",
375
410
              safer_gnutls_strerror(ret));
 
411
      gnutls_deinit (*session);
376
412
      return -1;
377
413
    }
378
414
  }
382
418
  if (ret != GNUTLS_E_SUCCESS) {
383
419
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
384
420
            safer_gnutls_strerror(ret));
 
421
    gnutls_deinit (*session);
385
422
    return -1;
386
423
  }
387
424
  
420
457
  }
421
458
  
422
459
  if(debug){
423
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
424
 
            ip, port);
 
460
    fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16
 
461
            "\n", ip, port);
425
462
  }
426
463
  
427
464
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
438
475
    fprintf(stderr, "Binding to interface %s\n", interface);
439
476
  }
440
477
  
441
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
 
478
  memset(&to, 0, sizeof(to));   /* Spurious warning */
442
479
  to.in6.sin6_family = AF_INET6;
443
480
  /* It would be nice to have a way to detect if we were passed an
444
481
     IPv4 address here.   Now we assume an IPv6 address. */
451
488
    fprintf(stderr, "Bad address: %s\n", ip);
452
489
    return -1;
453
490
  }
454
 
  to.in6.sin6_port = htons(port);       /* Spurious warning */
 
491
  to.in6.sin6_port = htons(port); /* Spurious warning */
455
492
  
456
493
  to.in6.sin6_scope_id = (uint32_t)if_index;
457
494
  
458
495
  if(debug){
459
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
 
496
    fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
497
            port);
460
498
    char addrstr[INET6_ADDRSTRLEN] = "";
461
499
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
462
500
                 sizeof(addrstr)) == NULL){
503
541
  }
504
542
  
505
543
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
506
 
  
507
 
  ret = gnutls_handshake (session);
 
544
 
 
545
  do{
 
546
    ret = gnutls_handshake (session);
 
547
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
508
548
  
509
549
  if (ret != GNUTLS_E_SUCCESS){
510
550
    if(debug){
542
582
      case GNUTLS_E_AGAIN:
543
583
        break;
544
584
      case GNUTLS_E_REHANDSHAKE:
545
 
        ret = gnutls_handshake (session);
 
585
        do{
 
586
          ret = gnutls_handshake (session);
 
587
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
546
588
        if (ret < 0){
547
589
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
548
590
          gnutls_perror (ret);
601
643
  free(buffer);
602
644
  close(tcp_sd);
603
645
  gnutls_deinit (session);
604
 
  gnutls_certificate_free_credentials (mc->cred);
605
 
  gnutls_global_deinit ();
606
646
  return retval;
607
647
}
608
648
 
639
679
      char ip[AVAHI_ADDRESS_STR_MAX];
640
680
      avahi_address_snprint(ip, sizeof(ip), address);
641
681
      if(debug){
642
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %d) on"
643
 
                " 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);
644
685
      }
645
686
      int ret = start_mandos_communication(ip, port, interface, mc);
646
687
      if (ret == 0){
647
 
        exit(EXIT_SUCCESS);
 
688
        avahi_simple_poll_quit(mc->simple_poll);
648
689
      }
649
690
    }
650
691
  }
704
745
 
705
746
/* Combines file name and path and returns the malloced new
706
747
   string. some sane checks could/should be added */
707
 
static const char *combinepath(const char *first, const char *second){
708
 
  size_t f_len = strlen(first);
709
 
  size_t s_len = strlen(second);
710
 
  char *tmp = malloc(f_len + s_len + 2);
711
 
  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){
712
752
    return NULL;
713
753
  }
714
 
  if(f_len > 0){
715
 
    memcpy(tmp, first, f_len);  /* Spurious warning */
716
 
  }
717
 
  tmp[f_len] = '/';
718
 
  if(s_len > 0){
719
 
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
720
 
  }
721
 
  tmp[f_len + 1 + s_len] = '\0';
722
754
  return tmp;
723
755
}
724
756
 
735
767
    gid_t gid;
736
768
    char *connect_to = NULL;
737
769
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
738
 
    const char *pubkeyfile = "pubkey.txt";
739
 
    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";
740
774
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
741
775
                          .dh_bits = 1024, .priority = "SECURE256"};
 
776
    bool gnutls_initalized = false;
742
777
    
743
778
    {
744
779
      struct argp_option options[] = {
793
828
          keydir = arg;
794
829
          break;
795
830
        case 's':
796
 
          seckeyfile = arg;
 
831
          seckeyname = arg;
797
832
          break;
798
833
        case 'p':
799
 
          pubkeyfile = arg;
 
834
          pubkeyname = arg;
800
835
          break;
801
836
        case 129:
802
837
          errno = 0;
811
846
          break;
812
847
        case ARGP_KEY_ARG:
813
848
          argp_usage (state);
 
849
        case ARGP_KEY_END:
814
850
          break;
815
 
          case ARGP_KEY_END:
816
 
            break;
817
851
        default:
818
852
          return ARGP_ERR_UNKNOWN;
819
853
        }
824
858
                           .args_doc = "",
825
859
                           .doc = "Mandos client -- Get and decrypt"
826
860
                           " passwords from mandos server" };
827
 
      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
      }
828
867
    }
829
868
      
830
 
    pubkeyfile = combinepath(keydir, pubkeyfile);
831
 
    if (pubkeyfile == NULL){
 
869
    pubkeyfilename = combinepath(keydir, pubkeyname);
 
870
    if (pubkeyfilename == NULL){
832
871
      perror("combinepath");
833
872
      exitcode = EXIT_FAILURE;
834
873
      goto end;
835
874
    }
836
875
    
837
 
    seckeyfile = combinepath(keydir, seckeyfile);
838
 
    if (seckeyfile == NULL){
 
876
    seckeyfilename = combinepath(keydir, seckeyname);
 
877
    if (seckeyfilename == NULL){
839
878
      perror("combinepath");
 
879
      exitcode = EXIT_FAILURE;
840
880
      goto end;
841
881
    }
842
882
 
843
 
    ret = init_gnutls_global(&mc, pubkeyfile, seckeyfile);
 
883
    ret = init_gnutls_global(&mc, pubkeyfilename, seckeyfilename);
844
884
    if (ret == -1){
845
 
      fprintf(stderr, "init_gnutls_global\n");
 
885
      fprintf(stderr, "init_gnutls_global failed\n");
 
886
      exitcode = EXIT_FAILURE;
846
887
      goto end;
847
 
    }
848
 
 
 
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
    
849
919
    uid = getuid();
850
920
    gid = getgid();
851
 
 
 
921
    
852
922
    ret = setuid(uid);
853
923
    if (ret == -1){
854
924
      perror("setuid");
892
962
      goto end;
893
963
    }
894
964
    
895
 
    /* If the interface is down, bring it up */
896
 
    {
897
 
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
898
 
      if(sd < 0) {
899
 
        perror("socket");
900
 
        exitcode = EXIT_FAILURE;
901
 
        goto end;
902
 
      }
903
 
      strcpy(network.ifr_name, interface); /* Spurious warning */
904
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
905
 
      if(ret == -1){
906
 
        perror("ioctl SIOCGIFFLAGS");
907
 
        exitcode = EXIT_FAILURE;
908
 
        goto end;
909
 
      }
910
 
      if((network.ifr_flags & IFF_UP) == 0){
911
 
        network.ifr_flags |= IFF_UP;
912
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
913
 
        if(ret == -1){
914
 
          perror("ioctl SIOCSIFFLAGS");
915
 
          exitcode = EXIT_FAILURE;
916
 
          goto end;
917
 
        }
918
 
      }
919
 
      close(sd);
920
 
    }
921
 
    
922
965
    if (not debug){
923
966
      avahi_set_log_function(empty_log);
924
967
    }
996
1039
 
997
1040
    if (mc.simple_poll != NULL)
998
1041
        avahi_simple_poll_free(mc.simple_poll);
999
 
    free(pubkeyfile);
1000
 
    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
    }
1001
1049
    
1002
1050
    return exitcode;
1003
1051
}