/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/mandos-client.c

Merge from Björn:

* mandos-ctl: Changed domain to "se.bsnet.fukt".

* plugin-runner.c (main): Bug fix: remove pseudo-plugin for global
                          plugin arguments after it is no longer
                          needed.

* plugins.d/mandos-client.c (adjustbuffer): Renamed to "incbuffer",
                                            all callers changed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
37
37
 
38
38
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
39
 
                                   stdout, ferror(), remove() */
 
39
                                   stdout, ferror(), sscanf(),
 
40
                                   remove() */
40
41
#include <stdint.h>             /* uint16_t, uint32_t */
41
42
#include <stddef.h>             /* NULL, size_t, ssize_t */
42
43
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
43
 
                                   srand(), strtof() */
 
44
                                   srand() */
44
45
#include <stdbool.h>            /* bool, false, true */
45
46
#include <string.h>             /* memset(), strcmp(), strlen(),
46
47
                                   strerror(), asprintf(), strcpy() */
55
56
#include <fcntl.h>              /* open() */
56
57
#include <dirent.h>             /* opendir(), struct dirent, readdir()
57
58
                                 */
58
 
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
59
 
                                   strtoimax() */
 
59
#include <inttypes.h>           /* PRIu16, intmax_t, SCNdMAX */
60
60
#include <assert.h>             /* assert() */
61
61
#include <errno.h>              /* perror(), errno */
62
62
#include <time.h>               /* nanosleep(), time() */
75
75
                                   argp_state, struct argp,
76
76
                                   argp_parse(), ARGP_KEY_ARG,
77
77
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
78
 
#include <signal.h>             /* sigemptyset(), sigaddset(),
79
 
                                   sigaction(), SIGTERM, sigaction,
80
 
                                   sig_atomic_t */
81
 
 
82
78
#ifdef __linux__
83
79
#include <sys/klog.h>           /* klogctl() */
84
 
#endif  /* __linux__ */
 
80
#endif
85
81
 
86
82
/* Avahi */
87
83
/* All Avahi types, constants and functions
133
129
  gpgme_ctx_t ctx;
134
130
} mandos_context;
135
131
 
136
 
/* global context so signal handler can reach it*/
137
 
mandos_context mc = { .simple_poll = NULL, .server = NULL,
138
 
                      .dh_bits = 1024, .priority = "SECURE256"
139
 
                      ":!CTYPE-X.509:+CTYPE-OPENPGP" };
140
 
 
141
132
/*
142
 
 * Make additional room in "buffer" for at least BUFFER_SIZE more
143
 
 * bytes. "buffer_capacity" is how much is currently allocated,
144
 
 * "buffer_length" is how much is already used.
 
133
 * Make additional room in "buffer" for at least BUFFER_SIZE
 
134
 * additional bytes. "buffer_capacity" is how much is currently
 
135
 * allocated, "buffer_length" is how much is already used.
145
136
 */
146
137
size_t incbuffer(char **buffer, size_t buffer_length,
147
138
                  size_t buffer_capacity){
158
149
/* 
159
150
 * Initialize GPGME.
160
151
 */
161
 
static bool init_gpgme(const char *seckey,
 
152
static bool init_gpgme(mandos_context *mc, const char *seckey,
162
153
                       const char *pubkey, const char *tempdir){
163
154
  int ret;
164
155
  gpgme_error_t rc;
185
176
      return false;
186
177
    }
187
178
    
188
 
    rc = gpgme_op_import(mc.ctx, pgp_data);
 
179
    rc = gpgme_op_import(mc->ctx, pgp_data);
189
180
    if(rc != GPG_ERR_NO_ERROR){
190
181
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
191
182
              gpgme_strsource(rc), gpgme_strerror(rc));
201
192
  }
202
193
  
203
194
  if(debug){
204
 
    fprintf(stderr, "Initializing GPGME\n");
 
195
    fprintf(stderr, "Initialize gpgme\n");
205
196
  }
206
197
  
207
198
  /* Init GPGME */
234
225
  }
235
226
  
236
227
  /* Create new GPGME "context" */
237
 
  rc = gpgme_new(&(mc.ctx));
 
228
  rc = gpgme_new(&(mc->ctx));
238
229
  if(rc != GPG_ERR_NO_ERROR){
239
230
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
240
231
            gpgme_strsource(rc), gpgme_strerror(rc));
252
243
 * Decrypt OpenPGP data.
253
244
 * Returns -1 on error
254
245
 */
255
 
static ssize_t pgp_packet_decrypt(const char *cryptotext,
 
246
static ssize_t pgp_packet_decrypt(const mandos_context *mc,
 
247
                                  const char *cryptotext,
256
248
                                  size_t crypto_size,
257
249
                                  char **plaintext){
258
250
  gpgme_data_t dh_crypto, dh_plain;
285
277
  
286
278
  /* Decrypt data from the cryptotext data buffer to the plaintext
287
279
     data buffer */
288
 
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
280
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
289
281
  if(rc != GPG_ERR_NO_ERROR){
290
282
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
291
283
            gpgme_strsource(rc), gpgme_strerror(rc));
292
284
    plaintext_length = -1;
293
285
    if(debug){
294
286
      gpgme_decrypt_result_t result;
295
 
      result = gpgme_op_decrypt_result(mc.ctx);
 
287
      result = gpgme_op_decrypt_result(mc->ctx);
296
288
      if(result == NULL){
297
289
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
298
290
      } else {
390
382
  fprintf(stderr, "GnuTLS: %s", string);
391
383
}
392
384
 
393
 
static int init_gnutls_global(const char *pubkeyfilename,
 
385
static int init_gnutls_global(mandos_context *mc,
 
386
                              const char *pubkeyfilename,
394
387
                              const char *seckeyfilename){
395
388
  int ret;
396
389
  
414
407
  }
415
408
  
416
409
  /* OpenPGP credentials */
417
 
  gnutls_certificate_allocate_credentials(&mc.cred);
 
410
  gnutls_certificate_allocate_credentials(&mc->cred);
418
411
  if(ret != GNUTLS_E_SUCCESS){
419
412
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
420
413
                                                    from
432
425
  }
433
426
  
434
427
  ret = gnutls_certificate_set_openpgp_key_file
435
 
    (mc.cred, pubkeyfilename, seckeyfilename,
 
428
    (mc->cred, pubkeyfilename, seckeyfilename,
436
429
     GNUTLS_OPENPGP_FMT_BASE64);
437
430
  if(ret != GNUTLS_E_SUCCESS){
438
431
    fprintf(stderr,
444
437
  }
445
438
  
446
439
  /* GnuTLS server initialization */
447
 
  ret = gnutls_dh_params_init(&mc.dh_params);
 
440
  ret = gnutls_dh_params_init(&mc->dh_params);
448
441
  if(ret != GNUTLS_E_SUCCESS){
449
442
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
450
443
            " %s\n", safer_gnutls_strerror(ret));
451
444
    goto globalfail;
452
445
  }
453
 
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
446
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
454
447
  if(ret != GNUTLS_E_SUCCESS){
455
448
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
456
449
            safer_gnutls_strerror(ret));
457
450
    goto globalfail;
458
451
  }
459
452
  
460
 
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
453
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
461
454
  
462
455
  return 0;
463
456
  
464
457
 globalfail:
465
458
  
466
 
  gnutls_certificate_free_credentials(mc.cred);
 
459
  gnutls_certificate_free_credentials(mc->cred);
467
460
  gnutls_global_deinit();
468
 
  gnutls_dh_params_deinit(mc.dh_params);
 
461
  gnutls_dh_params_deinit(mc->dh_params);
469
462
  return -1;
470
463
}
471
464
 
472
 
static int init_gnutls_session(gnutls_session_t *session){
 
465
static int init_gnutls_session(mandos_context *mc,
 
466
                               gnutls_session_t *session){
473
467
  int ret;
474
468
  /* GnuTLS session creation */
475
469
  ret = gnutls_init(session, GNUTLS_SERVER);
480
474
  
481
475
  {
482
476
    const char *err;
483
 
    ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
477
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
484
478
    if(ret != GNUTLS_E_SUCCESS){
485
479
      fprintf(stderr, "Syntax error at: %s\n", err);
486
480
      fprintf(stderr, "GnuTLS error: %s\n",
491
485
  }
492
486
  
493
487
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
494
 
                               mc.cred);
 
488
                               mc->cred);
495
489
  if(ret != GNUTLS_E_SUCCESS){
496
490
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
497
491
            safer_gnutls_strerror(ret));
503
497
  gnutls_certificate_server_set_request(*session,
504
498
                                        GNUTLS_CERT_IGNORE);
505
499
  
506
 
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
 
500
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
507
501
  
508
502
  return 0;
509
503
}
515
509
/* Called when a Mandos server is found */
516
510
static int start_mandos_communication(const char *ip, uint16_t port,
517
511
                                      AvahiIfIndex if_index,
518
 
                                      int af){
 
512
                                      mandos_context *mc, int af){
519
513
  int ret, tcp_sd;
520
514
  ssize_t sret;
521
515
  union {
544
538
    return -1;
545
539
  }
546
540
  
547
 
  ret = init_gnutls_session(&session);
 
541
  ret = init_gnutls_session(mc, &session);
548
542
  if(ret != 0){
549
543
    return -1;
550
544
  }
739
733
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
740
734
  
741
735
  if(buffer_length > 0){
742
 
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
 
736
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
743
737
                                               buffer_length,
744
738
                                               &decrypted_buffer);
745
739
    if(decrypted_buffer_size >= 0){
791
785
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
792
786
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
793
787
                             flags,
794
 
                             AVAHI_GCC_UNUSED void* userdata){
 
788
                             void* userdata){
 
789
  mandos_context *mc = userdata;
795
790
  assert(r);
796
791
  
797
792
  /* Called whenever a service has been resolved successfully or
802
797
  case AVAHI_RESOLVER_FAILURE:
803
798
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
804
799
            " of type '%s' in domain '%s': %s\n", name, type, domain,
805
 
            avahi_strerror(avahi_server_errno(mc.server)));
 
800
            avahi_strerror(avahi_server_errno(mc->server)));
806
801
    break;
807
802
    
808
803
  case AVAHI_RESOLVER_FOUND:
814
809
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
815
810
                ip, (intmax_t)interface, port);
816
811
      }
817
 
      int ret = start_mandos_communication(ip, port, interface,
 
812
      int ret = start_mandos_communication(ip, port, interface, mc,
818
813
                                           avahi_proto_to_af(proto));
819
814
      if(ret == 0){
820
 
        avahi_simple_poll_quit(mc.simple_poll);
 
815
        avahi_simple_poll_quit(mc->simple_poll);
821
816
      }
822
817
    }
823
818
  }
833
828
                            const char *domain,
834
829
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
835
830
                            flags,
836
 
                            AVAHI_GCC_UNUSED void* userdata){
 
831
                            void* userdata){
 
832
  mandos_context *mc = userdata;
837
833
  assert(b);
838
834
  
839
835
  /* Called whenever a new services becomes available on the LAN or
844
840
  case AVAHI_BROWSER_FAILURE:
845
841
    
846
842
    fprintf(stderr, "(Avahi browser) %s\n",
847
 
            avahi_strerror(avahi_server_errno(mc.server)));
848
 
    avahi_simple_poll_quit(mc.simple_poll);
 
843
            avahi_strerror(avahi_server_errno(mc->server)));
 
844
    avahi_simple_poll_quit(mc->simple_poll);
849
845
    return;
850
846
    
851
847
  case AVAHI_BROWSER_NEW:
854
850
       the callback function is called the Avahi server will free the
855
851
       resolver for us. */
856
852
    
857
 
    if(!(avahi_s_service_resolver_new(mc.server, interface,
 
853
    if(!(avahi_s_service_resolver_new(mc->server, interface,
858
854
                                       protocol, name, type, domain,
859
855
                                       AVAHI_PROTO_INET6, 0,
860
 
                                       resolve_callback, NULL)))
 
856
                                       resolve_callback, mc)))
861
857
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
862
 
              name, avahi_strerror(avahi_server_errno(mc.server)));
 
858
              name, avahi_strerror(avahi_server_errno(mc->server)));
863
859
    break;
864
860
    
865
861
  case AVAHI_BROWSER_REMOVE:
874
870
  }
875
871
}
876
872
 
877
 
sig_atomic_t quit_now = 0;
878
 
 
879
 
/* stop main loop after sigterm has been called */
880
 
static void handle_sigterm(__attribute__((unused)) int sig){
881
 
  if(quit_now){
882
 
    return;
883
 
  }
884
 
  quit_now = 1;
885
 
  int old_errno = errno;
886
 
  if(mc.simple_poll != NULL){
887
 
    avahi_simple_poll_quit(mc.simple_poll);
888
 
  }
889
 
  errno = old_errno;
890
 
}
891
 
 
892
873
int main(int argc, char *argv[]){
893
874
  AvahiSServiceBrowser *sb = NULL;
894
875
  int error;
895
876
  int ret;
896
877
  intmax_t tmpmax;
897
 
  char *tmp;
 
878
  int numchars;
898
879
  int exitcode = EXIT_SUCCESS;
899
880
  const char *interface = "eth0";
900
881
  struct ifreq network;
908
889
  const char *seckey = PATHDIR "/" SECKEY;
909
890
  const char *pubkey = PATHDIR "/" PUBKEY;
910
891
  
911
 
  /* Initialize Mandos context */
912
 
  mc = (mandos_context){ .simple_poll = NULL, .server = NULL,
913
 
                         .dh_bits = 1024, .priority = "SECURE256"
914
 
                         ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
892
  mandos_context mc = { .simple_poll = NULL, .server = NULL,
 
893
                        .dh_bits = 1024, .priority = "SECURE256"
 
894
                        ":!CTYPE-X.509:+CTYPE-OPENPGP" };
915
895
  bool gnutls_initialized = false;
916
896
  bool gpgme_initialized = false;
917
 
  float delay = 2.5f;
918
 
  
919
 
  struct sigaction old_sigterm_action;
920
 
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
 
897
  double delay = 2.5;
921
898
  
922
899
  {
923
900
    struct argp_option options[] = {
975
952
        pubkey = arg;
976
953
        break;
977
954
      case 129:                 /* --dh-bits */
978
 
        errno = 0;
979
 
        tmpmax = strtoimax(arg, &tmp, 10);
980
 
        if(errno != 0 or tmp == arg or *tmp != '\0'
981
 
           or tmpmax != (typeof(mc.dh_bits))tmpmax){
 
955
        ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
 
956
        if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
 
957
           or arg[numchars] != '\0'){
982
958
          fprintf(stderr, "Bad number of DH bits\n");
983
959
          exit(EXIT_FAILURE);
984
960
        }
988
964
        mc.priority = arg;
989
965
        break;
990
966
      case 131:                 /* --delay */
991
 
        errno = 0;
992
 
        delay = strtof(arg, &tmp);
993
 
        if(errno != 0 or tmp == arg or *tmp != '\0'){
 
967
        ret = sscanf(arg, "%lf%n", &delay, &numchars);
 
968
        if(ret < 1 or arg[numchars] != '\0'){
994
969
          fprintf(stderr, "Bad delay\n");
995
970
          exit(EXIT_FAILURE);
996
971
        }
1017
992
    }
1018
993
  }
1019
994
  
1020
 
  if(not debug){
1021
 
    avahi_set_log_function(empty_log);
1022
 
  }
1023
 
  
1024
 
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
1025
 
     from the signal handler */
1026
 
  /* Initialize the pseudo-RNG for Avahi */
1027
 
  srand((unsigned int) time(NULL));
1028
 
  mc.simple_poll = avahi_simple_poll_new();
1029
 
  if(mc.simple_poll == NULL){
1030
 
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1031
 
    exitcode = EXIT_FAILURE;
1032
 
    goto end;
1033
 
  }
1034
 
  
1035
 
  sigemptyset(&sigterm_action.sa_mask);
1036
 
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1037
 
  if(ret == -1){
1038
 
    perror("sigaddset");
1039
 
    exitcode = EXIT_FAILURE;
1040
 
    goto end;
1041
 
  }
1042
 
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1043
 
  if(ret == -1){
1044
 
    perror("sigaddset");
1045
 
    exitcode = EXIT_FAILURE;
1046
 
    goto end;
1047
 
  }
1048
 
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1049
 
  if(ret == -1){
1050
 
    perror("sigaddset");
1051
 
    exitcode = EXIT_FAILURE;
1052
 
    goto end;
1053
 
  }
1054
 
  ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
1055
 
  if(ret == -1){
1056
 
    perror("sigaction");
1057
 
    exitcode = EXIT_FAILURE;
1058
 
    goto end;
1059
 
  }  
1060
 
  
1061
995
  /* If the interface is down, bring it up */
1062
996
  if(interface[0] != '\0'){
1063
997
#ifdef __linux__
1069
1003
      restore_loglevel = false;
1070
1004
      perror("klogctl");
1071
1005
    }
1072
 
#endif  /* __linux__ */
 
1006
#endif
1073
1007
    
1074
1008
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1075
1009
    if(sd < 0){
1082
1016
          perror("klogctl");
1083
1017
        }
1084
1018
      }
1085
 
#endif  /* __linux__ */
 
1019
#endif
1086
1020
      goto end;
1087
1021
    }
1088
1022
    strcpy(network.ifr_name, interface);
1096
1030
          perror("klogctl");
1097
1031
        }
1098
1032
      }
1099
 
#endif  /* __linux__ */
 
1033
#endif
1100
1034
      exitcode = EXIT_FAILURE;
1101
1035
      goto end;
1102
1036
    }
1113
1047
            perror("klogctl");
1114
1048
          }
1115
1049
        }
1116
 
#endif  /* __linux__ */
 
1050
#endif
1117
1051
        goto end;
1118
1052
      }
1119
1053
    }
1143
1077
        perror("klogctl");
1144
1078
      }
1145
1079
    }
1146
 
#endif  /* __linux__ */
 
1080
#endif
1147
1081
  }
1148
1082
  
1149
1083
  uid = getuid();
1160
1094
    perror("setuid");
1161
1095
  }
1162
1096
  
1163
 
  ret = init_gnutls_global(pubkey, seckey);
 
1097
  ret = init_gnutls_global(&mc, pubkey, seckey);
1164
1098
  if(ret == -1){
1165
1099
    fprintf(stderr, "init_gnutls_global failed\n");
1166
1100
    exitcode = EXIT_FAILURE;
1175
1109
  }
1176
1110
  tempdir_created = true;
1177
1111
  
1178
 
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
1112
  if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
1179
1113
    fprintf(stderr, "init_gpgme failed\n");
1180
1114
    exitcode = EXIT_FAILURE;
1181
1115
    goto end;
1202
1136
      goto end;
1203
1137
    }
1204
1138
    uint16_t port;
1205
 
    errno = 0;
1206
 
    tmpmax = strtoimax(address+1, &tmp, 10);
1207
 
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
1208
 
       or tmpmax != (uint16_t)tmpmax){
 
1139
    ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
 
1140
    if(ret < 1 or tmpmax != (uint16_t)tmpmax
 
1141
       or address[numchars+1] != '\0'){
1209
1142
      fprintf(stderr, "Bad port number\n");
1210
1143
      exitcode = EXIT_FAILURE;
1211
1144
      goto end;
1220
1153
    } else {
1221
1154
      af = AF_INET;
1222
1155
    }
1223
 
    ret = start_mandos_communication(address, port, if_index, af);
 
1156
    ret = start_mandos_communication(address, port, if_index, &mc,
 
1157
                                     af);
1224
1158
    if(ret < 0){
1225
1159
      exitcode = EXIT_FAILURE;
1226
1160
    } else {
1228
1162
    }
1229
1163
    goto end;
1230
1164
  }
1231
 
    
 
1165
  
 
1166
  if(not debug){
 
1167
    avahi_set_log_function(empty_log);
 
1168
  }
 
1169
  
 
1170
  /* Initialize the pseudo-RNG for Avahi */
 
1171
  srand((unsigned int) time(NULL));
 
1172
  
 
1173
  /* Allocate main Avahi loop object */
 
1174
  mc.simple_poll = avahi_simple_poll_new();
 
1175
  if(mc.simple_poll == NULL){
 
1176
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
 
1177
    exitcode = EXIT_FAILURE;
 
1178
    goto end;
 
1179
  }
 
1180
  
1232
1181
  {
1233
1182
    AvahiServerConfig config;
1234
1183
    /* Do not publish any local Zeroconf records */
1258
1207
  /* Create the Avahi service browser */
1259
1208
  sb = avahi_s_service_browser_new(mc.server, if_index,
1260
1209
                                   AVAHI_PROTO_INET6, "_mandos._tcp",
1261
 
                                   NULL, 0, browse_callback, NULL);
 
1210
                                   NULL, 0, browse_callback, &mc);
1262
1211
  if(sb == NULL){
1263
1212
    fprintf(stderr, "Failed to create service browser: %s\n",
1264
1213
            avahi_strerror(avahi_server_errno(mc.server)));