/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:
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;
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
897
  double delay = 2.5;
918
 
 
919
 
  struct sigaction old_sigterm_action;
920
 
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
921
898
  
922
899
  {
923
900
    struct argp_option options[] = {
1015
992
    }
1016
993
  }
1017
994
  
1018
 
  if(not debug){
1019
 
    avahi_set_log_function(empty_log);
1020
 
  }
1021
 
  
1022
 
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
1023
 
     from the signal handler */
1024
 
  /* Initialize the pseudo-RNG for Avahi */
1025
 
  srand((unsigned int) time(NULL));
1026
 
  mc.simple_poll = avahi_simple_poll_new();
1027
 
  if(mc.simple_poll == NULL){
1028
 
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1029
 
    exitcode = EXIT_FAILURE;
1030
 
    goto end;
1031
 
  }
1032
 
  
1033
 
  sigemptyset(&sigterm_action.sa_mask);
1034
 
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1035
 
  if(ret == -1){
1036
 
    perror("sigaddset");
1037
 
    exitcode = EXIT_FAILURE;
1038
 
    goto end;
1039
 
  }
1040
 
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1041
 
  if(ret == -1){
1042
 
    perror("sigaddset");
1043
 
    exitcode = EXIT_FAILURE;
1044
 
    goto end;
1045
 
  }
1046
 
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1047
 
  if(ret == -1){
1048
 
    perror("sigaddset");
1049
 
    exitcode = EXIT_FAILURE;
1050
 
    goto end;
1051
 
  }
1052
 
  ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
1053
 
  if(ret == -1){
1054
 
    perror("sigaction");
1055
 
    exitcode = EXIT_FAILURE;
1056
 
    goto end;
1057
 
  }  
1058
 
  
1059
995
  /* If the interface is down, bring it up */
1060
996
  if(interface[0] != '\0'){
1061
997
#ifdef __linux__
1067
1003
      restore_loglevel = false;
1068
1004
      perror("klogctl");
1069
1005
    }
1070
 
#endif  /* __linux__ */
 
1006
#endif
1071
1007
    
1072
1008
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1073
1009
    if(sd < 0){
1080
1016
          perror("klogctl");
1081
1017
        }
1082
1018
      }
1083
 
#endif  /* __linux__ */
 
1019
#endif
1084
1020
      goto end;
1085
1021
    }
1086
1022
    strcpy(network.ifr_name, interface);
1094
1030
          perror("klogctl");
1095
1031
        }
1096
1032
      }
1097
 
#endif  /* __linux__ */
 
1033
#endif
1098
1034
      exitcode = EXIT_FAILURE;
1099
1035
      goto end;
1100
1036
    }
1111
1047
            perror("klogctl");
1112
1048
          }
1113
1049
        }
1114
 
#endif  /* __linux__ */
 
1050
#endif
1115
1051
        goto end;
1116
1052
      }
1117
1053
    }
1141
1077
        perror("klogctl");
1142
1078
      }
1143
1079
    }
1144
 
#endif  /* __linux__ */
 
1080
#endif
1145
1081
  }
1146
1082
  
1147
1083
  uid = getuid();
1158
1094
    perror("setuid");
1159
1095
  }
1160
1096
  
1161
 
  ret = init_gnutls_global(pubkey, seckey);
 
1097
  ret = init_gnutls_global(&mc, pubkey, seckey);
1162
1098
  if(ret == -1){
1163
1099
    fprintf(stderr, "init_gnutls_global failed\n");
1164
1100
    exitcode = EXIT_FAILURE;
1173
1109
  }
1174
1110
  tempdir_created = true;
1175
1111
  
1176
 
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
1112
  if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
1177
1113
    fprintf(stderr, "init_gpgme failed\n");
1178
1114
    exitcode = EXIT_FAILURE;
1179
1115
    goto end;
1217
1153
    } else {
1218
1154
      af = AF_INET;
1219
1155
    }
1220
 
    ret = start_mandos_communication(address, port, if_index, af);
 
1156
    ret = start_mandos_communication(address, port, if_index, &mc,
 
1157
                                     af);
1221
1158
    if(ret < 0){
1222
1159
      exitcode = EXIT_FAILURE;
1223
1160
    } else {
1225
1162
    }
1226
1163
    goto end;
1227
1164
  }
1228
 
    
 
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
  
1229
1181
  {
1230
1182
    AvahiServerConfig config;
1231
1183
    /* Do not publish any local Zeroconf records */
1255
1207
  /* Create the Avahi service browser */
1256
1208
  sb = avahi_s_service_browser_new(mc.server, if_index,
1257
1209
                                   AVAHI_PROTO_INET6, "_mandos._tcp",
1258
 
                                   NULL, 0, browse_callback, NULL);
 
1210
                                   NULL, 0, browse_callback, &mc);
1259
1211
  if(sb == NULL){
1260
1212
    fprintf(stderr, "Failed to create service browser: %s\n",
1261
1213
            avahi_strerror(avahi_server_errno(mc.server)));