/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:

* plugin-runner.c (main): Bug fix: For the "--options-for" option, do
                          not mangle arguments with colon characters.
                          Also support adding empty arguments.

* plugins.d/mandos-client.c: (mc): New global variable; moved from
                                   "main".
  (init_gpgme, pgp_packet_decrypt, init_gnutls_global,
  init_gnutls_session, start_mandos_communication): Removed "mc"
                                                    argument.  All
                                                    callers changed.

  (resolve_callback, browse_callback): Ignore "userdata" argument.
                                       All callers changed.
  (handle_sigterm): New function.
  (main): Add "handle_sigterm" as signal handler for SIGTERM before
          starting the main loop.

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
 
78
81
#ifdef __linux__
79
82
#include <sys/klog.h>           /* klogctl() */
80
83
#endif
129
132
  gpgme_ctx_t ctx;
130
133
} mandos_context;
131
134
 
 
135
/* global context so signal handler can reach it*/
 
136
mandos_context mc;
 
137
 
132
138
/*
133
139
 * Make additional room in "buffer" for at least BUFFER_SIZE
134
140
 * additional bytes. "buffer_capacity" is how much is currently
149
155
/* 
150
156
 * Initialize GPGME.
151
157
 */
152
 
static bool init_gpgme(mandos_context *mc, const char *seckey,
 
158
static bool init_gpgme(const char *seckey,
153
159
                       const char *pubkey, const char *tempdir){
154
160
  int ret;
155
161
  gpgme_error_t rc;
176
182
      return false;
177
183
    }
178
184
    
179
 
    rc = gpgme_op_import(mc->ctx, pgp_data);
 
185
    rc = gpgme_op_import(mc.ctx, pgp_data);
180
186
    if(rc != GPG_ERR_NO_ERROR){
181
187
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
182
188
              gpgme_strsource(rc), gpgme_strerror(rc));
192
198
  }
193
199
  
194
200
  if(debug){
195
 
    fprintf(stderr, "Initialize gpgme\n");
 
201
    fprintf(stderr, "Initializing GPGME\n");
196
202
  }
197
203
  
198
204
  /* Init GPGME */
225
231
  }
226
232
  
227
233
  /* Create new GPGME "context" */
228
 
  rc = gpgme_new(&(mc->ctx));
 
234
  rc = gpgme_new(&(mc.ctx));
229
235
  if(rc != GPG_ERR_NO_ERROR){
230
236
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
231
237
            gpgme_strsource(rc), gpgme_strerror(rc));
243
249
 * Decrypt OpenPGP data.
244
250
 * Returns -1 on error
245
251
 */
246
 
static ssize_t pgp_packet_decrypt(const mandos_context *mc,
247
 
                                  const char *cryptotext,
 
252
static ssize_t pgp_packet_decrypt(const char *cryptotext,
248
253
                                  size_t crypto_size,
249
254
                                  char **plaintext){
250
255
  gpgme_data_t dh_crypto, dh_plain;
277
282
  
278
283
  /* Decrypt data from the cryptotext data buffer to the plaintext
279
284
     data buffer */
280
 
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
 
285
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
281
286
  if(rc != GPG_ERR_NO_ERROR){
282
287
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
283
288
            gpgme_strsource(rc), gpgme_strerror(rc));
284
289
    plaintext_length = -1;
285
290
    if(debug){
286
291
      gpgme_decrypt_result_t result;
287
 
      result = gpgme_op_decrypt_result(mc->ctx);
 
292
      result = gpgme_op_decrypt_result(mc.ctx);
288
293
      if(result == NULL){
289
294
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
290
295
      } else {
382
387
  fprintf(stderr, "GnuTLS: %s", string);
383
388
}
384
389
 
385
 
static int init_gnutls_global(mandos_context *mc,
386
 
                              const char *pubkeyfilename,
 
390
static int init_gnutls_global(const char *pubkeyfilename,
387
391
                              const char *seckeyfilename){
388
392
  int ret;
389
393
  
407
411
  }
408
412
  
409
413
  /* OpenPGP credentials */
410
 
  gnutls_certificate_allocate_credentials(&mc->cred);
 
414
  gnutls_certificate_allocate_credentials(&mc.cred);
411
415
  if(ret != GNUTLS_E_SUCCESS){
412
416
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
413
417
                                                    from
425
429
  }
426
430
  
427
431
  ret = gnutls_certificate_set_openpgp_key_file
428
 
    (mc->cred, pubkeyfilename, seckeyfilename,
 
432
    (mc.cred, pubkeyfilename, seckeyfilename,
429
433
     GNUTLS_OPENPGP_FMT_BASE64);
430
434
  if(ret != GNUTLS_E_SUCCESS){
431
435
    fprintf(stderr,
437
441
  }
438
442
  
439
443
  /* GnuTLS server initialization */
440
 
  ret = gnutls_dh_params_init(&mc->dh_params);
 
444
  ret = gnutls_dh_params_init(&mc.dh_params);
441
445
  if(ret != GNUTLS_E_SUCCESS){
442
446
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
443
447
            " %s\n", safer_gnutls_strerror(ret));
444
448
    goto globalfail;
445
449
  }
446
 
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
450
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
447
451
  if(ret != GNUTLS_E_SUCCESS){
448
452
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
449
453
            safer_gnutls_strerror(ret));
450
454
    goto globalfail;
451
455
  }
452
456
  
453
 
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
 
457
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
454
458
  
455
459
  return 0;
456
460
  
457
461
 globalfail:
458
462
  
459
 
  gnutls_certificate_free_credentials(mc->cred);
 
463
  gnutls_certificate_free_credentials(mc.cred);
460
464
  gnutls_global_deinit();
461
 
  gnutls_dh_params_deinit(mc->dh_params);
 
465
  gnutls_dh_params_deinit(mc.dh_params);
462
466
  return -1;
463
467
}
464
468
 
465
 
static int init_gnutls_session(mandos_context *mc,
466
 
                               gnutls_session_t *session){
 
469
static int init_gnutls_session(gnutls_session_t *session){
467
470
  int ret;
468
471
  /* GnuTLS session creation */
469
472
  ret = gnutls_init(session, GNUTLS_SERVER);
474
477
  
475
478
  {
476
479
    const char *err;
477
 
    ret = gnutls_priority_set_direct(*session, mc->priority, &err);
 
480
    ret = gnutls_priority_set_direct(*session, mc.priority, &err);
478
481
    if(ret != GNUTLS_E_SUCCESS){
479
482
      fprintf(stderr, "Syntax error at: %s\n", err);
480
483
      fprintf(stderr, "GnuTLS error: %s\n",
485
488
  }
486
489
  
487
490
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
488
 
                               mc->cred);
 
491
                               mc.cred);
489
492
  if(ret != GNUTLS_E_SUCCESS){
490
493
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
491
494
            safer_gnutls_strerror(ret));
497
500
  gnutls_certificate_server_set_request(*session,
498
501
                                        GNUTLS_CERT_IGNORE);
499
502
  
500
 
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
 
503
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
501
504
  
502
505
  return 0;
503
506
}
509
512
/* Called when a Mandos server is found */
510
513
static int start_mandos_communication(const char *ip, uint16_t port,
511
514
                                      AvahiIfIndex if_index,
512
 
                                      mandos_context *mc, int af){
 
515
                                      int af){
513
516
  int ret, tcp_sd;
514
517
  ssize_t sret;
515
518
  union {
538
541
    return -1;
539
542
  }
540
543
  
541
 
  ret = init_gnutls_session(mc, &session);
 
544
  ret = init_gnutls_session(&session);
542
545
  if(ret != 0){
543
546
    return -1;
544
547
  }
733
736
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
734
737
  
735
738
  if(buffer_length > 0){
736
 
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
 
739
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
737
740
                                               buffer_length,
738
741
                                               &decrypted_buffer);
739
742
    if(decrypted_buffer_size >= 0){
785
788
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
786
789
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
787
790
                             flags,
788
 
                             void* userdata){
789
 
  mandos_context *mc = userdata;
 
791
                             AVAHI_GCC_UNUSED void* userdata){
790
792
  assert(r);
791
793
  
792
794
  /* Called whenever a service has been resolved successfully or
797
799
  case AVAHI_RESOLVER_FAILURE:
798
800
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
799
801
            " of type '%s' in domain '%s': %s\n", name, type, domain,
800
 
            avahi_strerror(avahi_server_errno(mc->server)));
 
802
            avahi_strerror(avahi_server_errno(mc.server)));
801
803
    break;
802
804
    
803
805
  case AVAHI_RESOLVER_FOUND:
809
811
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
810
812
                ip, (intmax_t)interface, port);
811
813
      }
812
 
      int ret = start_mandos_communication(ip, port, interface, mc,
 
814
      int ret = start_mandos_communication(ip, port, interface,
813
815
                                           avahi_proto_to_af(proto));
814
816
      if(ret == 0){
815
 
        avahi_simple_poll_quit(mc->simple_poll);
 
817
        avahi_simple_poll_quit(mc.simple_poll);
816
818
      }
817
819
    }
818
820
  }
828
830
                            const char *domain,
829
831
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
830
832
                            flags,
831
 
                            void* userdata){
832
 
  mandos_context *mc = userdata;
 
833
                            AVAHI_GCC_UNUSED void* userdata){
833
834
  assert(b);
834
835
  
835
836
  /* Called whenever a new services becomes available on the LAN or
840
841
  case AVAHI_BROWSER_FAILURE:
841
842
    
842
843
    fprintf(stderr, "(Avahi browser) %s\n",
843
 
            avahi_strerror(avahi_server_errno(mc->server)));
844
 
    avahi_simple_poll_quit(mc->simple_poll);
 
844
            avahi_strerror(avahi_server_errno(mc.server)));
 
845
    avahi_simple_poll_quit(mc.simple_poll);
845
846
    return;
846
847
    
847
848
  case AVAHI_BROWSER_NEW:
850
851
       the callback function is called the Avahi server will free the
851
852
       resolver for us. */
852
853
    
853
 
    if(!(avahi_s_service_resolver_new(mc->server, interface,
 
854
    if(!(avahi_s_service_resolver_new(mc.server, interface,
854
855
                                       protocol, name, type, domain,
855
856
                                       AVAHI_PROTO_INET6, 0,
856
 
                                       resolve_callback, mc)))
 
857
                                       resolve_callback, NULL)))
857
858
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
858
 
              name, avahi_strerror(avahi_server_errno(mc->server)));
 
859
              name, avahi_strerror(avahi_server_errno(mc.server)));
859
860
    break;
860
861
    
861
862
  case AVAHI_BROWSER_REMOVE:
870
871
  }
871
872
}
872
873
 
 
874
static void handle_sigterm(__attribute__((unused)) int sig){
 
875
  int old_errno = errno;
 
876
  avahi_simple_poll_quit(mc.simple_poll);
 
877
  errno = old_errno;
 
878
}
 
879
 
873
880
int main(int argc, char *argv[]){
874
881
  AvahiSServiceBrowser *sb = NULL;
875
882
  int error;
889
896
  const char *seckey = PATHDIR "/" SECKEY;
890
897
  const char *pubkey = PATHDIR "/" PUBKEY;
891
898
  
892
 
  mandos_context mc = { .simple_poll = NULL, .server = NULL,
893
 
                        .dh_bits = 1024, .priority = "SECURE256"
894
 
                        ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
899
  /* Initialize Mandos context */
 
900
  mc = (mandos_context){ .simple_poll = NULL, .server = NULL,
 
901
                         .dh_bits = 1024, .priority = "SECURE256"
 
902
                         ":!CTYPE-X.509:+CTYPE-OPENPGP" };
895
903
  bool gnutls_initialized = false;
896
904
  bool gpgme_initialized = false;
897
905
  double delay = 2.5;
 
906
 
 
907
  struct sigaction old_sigterm_action;
 
908
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
898
909
  
899
910
  {
900
911
    struct argp_option options[] = {
1094
1105
    perror("setuid");
1095
1106
  }
1096
1107
  
1097
 
  ret = init_gnutls_global(&mc, pubkey, seckey);
 
1108
  ret = init_gnutls_global(pubkey, seckey);
1098
1109
  if(ret == -1){
1099
1110
    fprintf(stderr, "init_gnutls_global failed\n");
1100
1111
    exitcode = EXIT_FAILURE;
1109
1120
  }
1110
1121
  tempdir_created = true;
1111
1122
  
1112
 
  if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
 
1123
  if(not init_gpgme(pubkey, seckey, tempdir)){
1113
1124
    fprintf(stderr, "init_gpgme failed\n");
1114
1125
    exitcode = EXIT_FAILURE;
1115
1126
    goto end;
1153
1164
    } else {
1154
1165
      af = AF_INET;
1155
1166
    }
1156
 
    ret = start_mandos_communication(address, port, if_index, &mc,
1157
 
                                     af);
 
1167
    ret = start_mandos_communication(address, port, if_index, af);
1158
1168
    if(ret < 0){
1159
1169
      exitcode = EXIT_FAILURE;
1160
1170
    } else {
1207
1217
  /* Create the Avahi service browser */
1208
1218
  sb = avahi_s_service_browser_new(mc.server, if_index,
1209
1219
                                   AVAHI_PROTO_INET6, "_mandos._tcp",
1210
 
                                   NULL, 0, browse_callback, &mc);
 
1220
                                   NULL, 0, browse_callback, NULL);
1211
1221
  if(sb == NULL){
1212
1222
    fprintf(stderr, "Failed to create service browser: %s\n",
1213
1223
            avahi_strerror(avahi_server_errno(mc.server)));
1215
1225
    goto end;
1216
1226
  }
1217
1227
  
 
1228
  sigemptyset(&sigterm_action.sa_mask);
 
1229
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
 
1230
  if(ret == -1){
 
1231
    perror("sigaddset");
 
1232
    exitcode = EXIT_FAILURE;
 
1233
    goto end;
 
1234
  }
 
1235
  ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
 
1236
  if(ret == -1){
 
1237
    perror("sigaction");
 
1238
    exitcode = EXIT_FAILURE;
 
1239
    goto end;
 
1240
  }  
 
1241
  
1218
1242
  /* Run the main loop */
1219
1243
  
1220
1244
  if(debug){