/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-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:
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>              /* fprintf(), stderr, fwrite(), stdout,
38
 
                                   ferror() */
 
37
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
 
38
                                   stdout, ferror() */
39
39
#include <stdint.h>             /* uint16_t, uint32_t */
40
40
#include <stddef.h>             /* NULL, size_t, ssize_t */
41
41
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
42
42
                                   srand() */
43
43
#include <stdbool.h>            /* bool, true */
44
44
#include <string.h>             /* memset(), strcmp(), strlen(),
45
 
                                   strerror(), memcpy(), strcpy() */
 
45
                                   strerror(), asprintf(), strcpy() */
46
46
#include <sys/ioctl.h>          /* ioctl */
47
 
#include <net/if.h>             /* ifreq, SIOCGIFFLAGS, SIOCSIFFLAGS,
48
 
                                   IFF_UP */
49
47
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
50
48
                                   sockaddr_in6, PF_INET6,
51
49
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
52
50
                                   uid_t, gid_t */
 
51
#include <inttypes.h>           /* PRIu16 */
53
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
54
53
                                   struct in6_addr, inet_pton(),
55
54
                                   connect() */
82
81
#include <avahi-common/error.h>
83
82
 
84
83
/* GnuTLS */
85
 
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and functions
 
84
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and
 
85
                                   functions:
86
86
                                   gnutls_*
87
87
                                   init_gnutls_session(),
88
88
                                   GNUTLS_* */
90
90
                                   GNUTLS_OPENPGP_FMT_BASE64 */
91
91
 
92
92
/* GPGME */
93
 
#include <gpgme.h>              /* All GPGME types, constants and functions
 
93
#include <gpgme.h>              /* All GPGME types, constants and
 
94
                                   functions:
94
95
                                   gpgme_*
95
96
                                   GPGME_PROTOCOL_OpenPGP,
96
97
                                   GPG_ERR_NO_* */
100
101
bool debug = false;
101
102
static const char *keydir = "/conf/conf.d/mandos";
102
103
static const char mandos_protocol_version[] = "1";
103
 
const char *argp_program_version = "mandosclient 1.0";
 
104
const char *argp_program_version = "password-request 1.0";
104
105
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
105
106
 
106
107
/* Used for passing in values through the Avahi callback functions */
213
214
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
214
215
            gpgme_strsource(rc), gpgme_strerror(rc));
215
216
    plaintext_length = -1;
 
217
    if (debug){
 
218
      gpgme_decrypt_result_t result;
 
219
      result = gpgme_op_decrypt_result(ctx);
 
220
      if (result == NULL){
 
221
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
222
      } else {
 
223
        fprintf(stderr, "Unsupported algorithm: %s\n",
 
224
                result->unsupported_algorithm);
 
225
        fprintf(stderr, "Wrong key usage: %u\n",
 
226
                result->wrong_key_usage);
 
227
        if(result->file_name != NULL){
 
228
          fprintf(stderr, "File name: %s\n", result->file_name);
 
229
        }
 
230
        gpgme_recipient_t recipient;
 
231
        recipient = result->recipients;
 
232
        if(recipient){
 
233
          while(recipient != NULL){
 
234
            fprintf(stderr, "Public key algorithm: %s\n",
 
235
                    gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
236
            fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
237
            fprintf(stderr, "Secret key available: %s\n",
 
238
                    recipient->status == GPG_ERR_NO_SECKEY
 
239
                    ? "No" : "Yes");
 
240
            recipient = recipient->next;
 
241
          }
 
242
        }
 
243
      }
 
244
    }
216
245
    goto decrypt_end;
217
246
  }
218
247
  
220
249
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
221
250
  }
222
251
  
223
 
  if (debug){
224
 
    gpgme_decrypt_result_t result;
225
 
    result = gpgme_op_decrypt_result(ctx);
226
 
    if (result == NULL){
227
 
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
228
 
    } else {
229
 
      fprintf(stderr, "Unsupported algorithm: %s\n",
230
 
              result->unsupported_algorithm);
231
 
      fprintf(stderr, "Wrong key usage: %d\n",
232
 
              result->wrong_key_usage);
233
 
      if(result->file_name != NULL){
234
 
        fprintf(stderr, "File name: %s\n", result->file_name);
235
 
      }
236
 
      gpgme_recipient_t recipient;
237
 
      recipient = result->recipients;
238
 
      if(recipient){
239
 
        while(recipient != NULL){
240
 
          fprintf(stderr, "Public key algorithm: %s\n",
241
 
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
242
 
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
243
 
          fprintf(stderr, "Secret key available: %s\n",
244
 
                  recipient->status == GPG_ERR_NO_SECKEY
245
 
                  ? "No" : "Yes");
246
 
          recipient = recipient->next;
247
 
        }
248
 
      }
249
 
    }
250
 
  }
251
 
  
252
252
  /* Seek back to the beginning of the GPGME plaintext data buffer */
253
253
  if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
254
254
    perror("pgpme_data_seek");
301
301
}
302
302
 
303
303
static const char * safer_gnutls_strerror (int value) {
304
 
  const char *ret = gnutls_strerror (value);
 
304
  const char *ret = gnutls_strerror (value); /* Spurious warning */
305
305
  if (ret == NULL)
306
306
    ret = "(unknown)";
307
307
  return ret;
314
314
}
315
315
 
316
316
static int init_gnutls_global(mandos_context *mc,
317
 
                              const char *pubkeyfile,
318
 
                              const char *seckeyfile){
 
317
                              const char *pubkeyfilename,
 
318
                              const char *seckeyfilename){
319
319
  int ret;
320
320
  
321
321
  if(debug){
340
340
  /* OpenPGP credentials */
341
341
  gnutls_certificate_allocate_credentials(&mc->cred);
342
342
  if (ret != GNUTLS_E_SUCCESS){
343
 
    fprintf (stderr, "GnuTLS memory error: %s\n",
 
343
    fprintf (stderr, "GnuTLS memory error: %s\n", /* Spurious
 
344
                                                     warning */
344
345
             safer_gnutls_strerror(ret));
345
346
    gnutls_global_deinit ();
346
347
    return -1;
348
349
  
349
350
  if(debug){
350
351
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
351
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
352
 
            seckeyfile);
 
352
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
 
353
            seckeyfilename);
353
354
  }
354
355
  
355
356
  ret = gnutls_certificate_set_openpgp_key_file
356
 
    (mc->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
 
357
    (mc->cred, pubkeyfilename, seckeyfilename,
 
358
     GNUTLS_OPENPGP_FMT_BASE64);
357
359
  if (ret != GNUTLS_E_SUCCESS) {
358
360
    fprintf(stderr,
359
361
            "Error[%d] while reading the OpenPGP key pair ('%s',"
360
 
            " '%s')\n", ret, pubkeyfile, seckeyfile);
 
362
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
361
363
    fprintf(stdout, "The GnuTLS error is: %s\n",
362
364
            safer_gnutls_strerror(ret));
363
365
    goto globalfail;
455
457
  }
456
458
  
457
459
  if(debug){
458
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
459
 
            ip, port);
 
460
    fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16
 
461
            "\n", ip, port);
460
462
  }
461
463
  
462
464
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
473
475
    fprintf(stderr, "Binding to interface %s\n", interface);
474
476
  }
475
477
  
476
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
 
478
  memset(&to, 0, sizeof(to));
477
479
  to.in6.sin6_family = AF_INET6;
478
480
  /* It would be nice to have a way to detect if we were passed an
479
481
     IPv4 address here.   Now we assume an IPv6 address. */
486
488
    fprintf(stderr, "Bad address: %s\n", ip);
487
489
    return -1;
488
490
  }
489
 
  to.in6.sin6_port = htons(port);       /* Spurious warning */
 
491
  to.in6.sin6_port = htons(port); /* Spurious warning */
490
492
  
491
493
  to.in6.sin6_scope_id = (uint32_t)if_index;
492
494
  
493
495
  if(debug){
494
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
 
496
    fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
497
            port);
495
498
    char addrstr[INET6_ADDRSTRLEN] = "";
496
499
    if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
497
500
                 sizeof(addrstr)) == NULL){
632
635
    } else {
633
636
      retval = -1;
634
637
    }
 
638
  } else {
 
639
    retval = -1;
635
640
  }
636
641
  
637
642
  /* Shutdown procedure */
658
663
                             flags,
659
664
                             void* userdata) {
660
665
  mandos_context *mc = userdata;
661
 
  assert(r);                    /* Spurious warning */
 
666
  assert(r);
662
667
  
663
668
  /* Called whenever a service has been resolved successfully or
664
669
     timed out */
676
681
      char ip[AVAHI_ADDRESS_STR_MAX];
677
682
      avahi_address_snprint(ip, sizeof(ip), address);
678
683
      if(debug){
679
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %d) on"
680
 
                " port %d\n", name, host_name, ip, interface, port);
 
684
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
 
685
                PRIu16 ") on port %d\n", name, host_name, ip,
 
686
                interface, port);
681
687
      }
682
688
      int ret = start_mandos_communication(ip, port, interface, mc);
683
689
      if (ret == 0){
684
 
        exit(EXIT_SUCCESS);
 
690
        avahi_simple_poll_quit(mc->simple_poll);
685
691
      }
686
692
    }
687
693
  }
699
705
                             flags,
700
706
                             void* userdata) {
701
707
  mandos_context *mc = userdata;
702
 
  assert(b);                    /* Spurious warning */
 
708
  assert(b);
703
709
  
704
710
  /* Called whenever a new services becomes available on the LAN or
705
711
     is removed from the LAN */
741
747
 
742
748
/* Combines file name and path and returns the malloced new
743
749
   string. some sane checks could/should be added */
744
 
static const char *combinepath(const char *first, const char *second){
745
 
  size_t f_len = strlen(first);
746
 
  size_t s_len = strlen(second);
747
 
  char *tmp = malloc(f_len + s_len + 2);
748
 
  if (tmp == NULL){
 
750
static char *combinepath(const char *first, const char *second){
 
751
  char *tmp;
 
752
  int ret = asprintf(&tmp, "%s/%s", first, second);
 
753
  if(ret < 0){
749
754
    return NULL;
750
755
  }
751
 
  if(f_len > 0){
752
 
    memcpy(tmp, first, f_len);  /* Spurious warning */
753
 
  }
754
 
  tmp[f_len] = '/';
755
 
  if(s_len > 0){
756
 
    memcpy(tmp + f_len + 1, second, s_len); /* Spurious warning */
757
 
  }
758
 
  tmp[f_len + 1 + s_len] = '\0';
759
756
  return tmp;
760
757
}
761
758
 
772
769
    gid_t gid;
773
770
    char *connect_to = NULL;
774
771
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
775
 
    const char *pubkeyfile = "pubkey.txt";
776
 
    const char *seckeyfile = "seckey.txt";
 
772
    char *pubkeyfilename = NULL;
 
773
    char *seckeyfilename = NULL;
 
774
    const char *pubkeyname = "pubkey.txt";
 
775
    const char *seckeyname = "seckey.txt";
777
776
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
778
777
                          .dh_bits = 1024, .priority = "SECURE256"};
779
778
    bool gnutls_initalized = false;
831
830
          keydir = arg;
832
831
          break;
833
832
        case 's':
834
 
          seckeyfile = arg;
 
833
          seckeyname = arg;
835
834
          break;
836
835
        case 'p':
837
 
          pubkeyfile = arg;
 
836
          pubkeyname = arg;
838
837
          break;
839
838
        case 129:
840
839
          errno = 0;
849
848
          break;
850
849
        case ARGP_KEY_ARG:
851
850
          argp_usage (state);
 
851
        case ARGP_KEY_END:
852
852
          break;
853
 
          case ARGP_KEY_END:
854
 
            break;
855
853
        default:
856
854
          return ARGP_ERR_UNKNOWN;
857
855
        }
864
862
                           " passwords from mandos server" };
865
863
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
866
864
      if (ret == ARGP_ERR_UNKNOWN){
867
 
        fprintf(stderr, "Unkown error while parsing arguments\n");
 
865
        fprintf(stderr, "Unknown error while parsing arguments\n");
868
866
        exitcode = EXIT_FAILURE;
869
867
        goto end;
870
868
      }
871
869
    }
872
870
      
873
 
    pubkeyfile = combinepath(keydir, pubkeyfile);
874
 
    if (pubkeyfile == NULL){
 
871
    pubkeyfilename = combinepath(keydir, pubkeyname);
 
872
    if (pubkeyfilename == NULL){
875
873
      perror("combinepath");
876
874
      exitcode = EXIT_FAILURE;
877
875
      goto end;
878
876
    }
879
877
    
880
 
    seckeyfile = combinepath(keydir, seckeyfile);
881
 
    if (seckeyfile == NULL){
 
878
    seckeyfilename = combinepath(keydir, seckeyname);
 
879
    if (seckeyfilename == NULL){
882
880
      perror("combinepath");
 
881
      exitcode = EXIT_FAILURE;
883
882
      goto end;
884
883
    }
885
884
 
886
 
    ret = init_gnutls_global(&mc, pubkeyfile, seckeyfile);
 
885
    ret = init_gnutls_global(&mc, pubkeyfilename, seckeyfilename);
887
886
    if (ret == -1){
888
 
      fprintf(stderr, "init_gnutls_global\n");
 
887
      fprintf(stderr, "init_gnutls_global failed\n");
 
888
      exitcode = EXIT_FAILURE;
889
889
      goto end;
890
890
    } else {
891
891
      gnutls_initalized = true;
892
892
    }
893
 
 
 
893
    
 
894
    /* If the interface is down, bring it up */
 
895
    {
 
896
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
897
      if(sd < 0) {
 
898
        perror("socket");
 
899
        exitcode = EXIT_FAILURE;
 
900
        goto end;
 
901
      }
 
902
      strcpy(network.ifr_name, interface);
 
903
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
904
      if(ret == -1){
 
905
        perror("ioctl SIOCGIFFLAGS");
 
906
        exitcode = EXIT_FAILURE;
 
907
        goto end;
 
908
      }
 
909
      if((network.ifr_flags & IFF_UP) == 0){
 
910
        network.ifr_flags |= IFF_UP;
 
911
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
912
        if(ret == -1){
 
913
          perror("ioctl SIOCSIFFLAGS");
 
914
          exitcode = EXIT_FAILURE;
 
915
          goto end;
 
916
        }
 
917
      }
 
918
      close(sd);
 
919
    }
 
920
    
894
921
    uid = getuid();
895
922
    gid = getgid();
896
 
 
 
923
    
897
924
    ret = setuid(uid);
898
925
    if (ret == -1){
899
926
      perror("setuid");
937
964
      goto end;
938
965
    }
939
966
    
940
 
    /* If the interface is down, bring it up */
941
 
    {
942
 
      sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
943
 
      if(sd < 0) {
944
 
        perror("socket");
945
 
        exitcode = EXIT_FAILURE;
946
 
        goto end;
947
 
      }
948
 
      strcpy(network.ifr_name, interface); /* Spurious warning */
949
 
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
950
 
      if(ret == -1){
951
 
        perror("ioctl SIOCGIFFLAGS");
952
 
        exitcode = EXIT_FAILURE;
953
 
        goto end;
954
 
      }
955
 
      if((network.ifr_flags & IFF_UP) == 0){
956
 
        network.ifr_flags |= IFF_UP;
957
 
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
958
 
        if(ret == -1){
959
 
          perror("ioctl SIOCSIFFLAGS");
960
 
          exitcode = EXIT_FAILURE;
961
 
          goto end;
962
 
        }
963
 
      }
964
 
      close(sd);
965
 
    }
966
 
    
967
967
    if (not debug){
968
968
      avahi_set_log_function(empty_log);
969
969
    }
1041
1041
 
1042
1042
    if (mc.simple_poll != NULL)
1043
1043
        avahi_simple_poll_free(mc.simple_poll);
1044
 
    free(pubkeyfile);
1045
 
    free(seckeyfile);
 
1044
    free(pubkeyfilename);
 
1045
    free(seckeyfilename);
1046
1046
 
1047
1047
    if (gnutls_initalized){
1048
1048
      gnutls_certificate_free_credentials(mc.cred);