/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

  • Committer: Teddy Hogeborn
  • Date: 2012-06-16 22:38:54 UTC
  • mto: (301.1.1 release) (237.7.272 trunk)
  • mto: This revision was merged to the branch mainline in revision 302.
  • Revision ID: teddy@recompile.se-20120616223854-mfxkg6fgqr56sma5
* plugins.d/mandos-client (mandos_context): Removed "simple_poll"
                                            member.
  (simple_poll): New global variable.  All users changed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
165
165
 
166
166
/* global so signal handler can reach it*/
167
167
AvahiSimplePoll *simple_poll;
 
168
mandos_context mc = { .server = NULL, .dh_bits = 1024,
 
169
                      .priority = "SECURE256:!CTYPE-X.509:"
 
170
                      "+CTYPE-OPENPGP", .current_server = NULL };
168
171
 
169
172
sig_atomic_t quit_now = 0;
170
173
int signal_received = 0;
207
210
 
208
211
/* Add server to set of servers to retry periodically */
209
212
bool add_server(const char *ip, in_port_t port, AvahiIfIndex if_index,
210
 
                int af, server **current_server){
 
213
                int af){
211
214
  int ret;
212
215
  server *new_server = malloc(sizeof(server));
213
216
  if(new_server == NULL){
223
226
    return false;
224
227
  }
225
228
  /* Special case of first server */
226
 
  if(*current_server == NULL){
 
229
  if (mc.current_server == NULL){
227
230
    new_server->next = new_server;
228
231
    new_server->prev = new_server;
229
 
    *current_server = new_server;
 
232
    mc.current_server = new_server;
230
233
  /* Place the new server last in the list */
231
234
  } else {
232
 
    new_server->next = *current_server;
233
 
    new_server->prev = (*current_server)->prev;
 
235
    new_server->next = mc.current_server;
 
236
    new_server->prev = mc.current_server->prev;
234
237
    new_server->prev->next = new_server;
235
 
    (*current_server)->prev = new_server;
 
238
    mc.current_server->prev = new_server;
236
239
  }
237
 
  ret = clock_gettime(CLOCK_MONOTONIC, &(*current_server)->last_seen);
 
240
  ret = clock_gettime(CLOCK_MONOTONIC, &mc.current_server->last_seen);
238
241
  if(ret == -1){
239
242
    perror_plus("clock_gettime");
240
243
    return false;
246
249
 * Initialize GPGME.
247
250
 */
248
251
static bool init_gpgme(const char *seckey, const char *pubkey,
249
 
                       const char *tempdir, mandos_context *mc){
 
252
                       const char *tempdir){
250
253
  gpgme_error_t rc;
251
254
  gpgme_engine_info_t engine_info;
252
255
  
271
274
      return false;
272
275
    }
273
276
    
274
 
    rc = gpgme_op_import(mc->ctx, pgp_data);
 
277
    rc = gpgme_op_import(mc.ctx, pgp_data);
275
278
    if(rc != GPG_ERR_NO_ERROR){
276
279
      fprintf_plus(stderr, "bad gpgme_op_import: %s: %s\n",
277
280
                   gpgme_strsource(rc), gpgme_strerror(rc));
321
324
  }
322
325
  
323
326
  /* Create new GPGME "context" */
324
 
  rc = gpgme_new(&(mc->ctx));
 
327
  rc = gpgme_new(&(mc.ctx));
325
328
  if(rc != GPG_ERR_NO_ERROR){
326
329
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
327
330
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
342
345
 */
343
346
static ssize_t pgp_packet_decrypt(const char *cryptotext,
344
347
                                  size_t crypto_size,
345
 
                                  char **plaintext,
346
 
                                  mandos_context *mc){
 
348
                                  char **plaintext){
347
349
  gpgme_data_t dh_crypto, dh_plain;
348
350
  gpgme_error_t rc;
349
351
  ssize_t ret;
375
377
  
376
378
  /* Decrypt data from the cryptotext data buffer to the plaintext
377
379
     data buffer */
378
 
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
 
380
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
379
381
  if(rc != GPG_ERR_NO_ERROR){
380
382
    fprintf_plus(stderr, "bad gpgme_op_decrypt: %s: %s\n",
381
383
                 gpgme_strsource(rc), gpgme_strerror(rc));
382
384
    plaintext_length = -1;
383
385
    if(debug){
384
386
      gpgme_decrypt_result_t result;
385
 
      result = gpgme_op_decrypt_result(mc->ctx);
 
387
      result = gpgme_op_decrypt_result(mc.ctx);
386
388
      if(result == NULL){
387
389
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
388
390
      } else {
479
481
}
480
482
 
481
483
static int init_gnutls_global(const char *pubkeyfilename,
482
 
                              const char *seckeyfilename,
483
 
                              mandos_context *mc){
 
484
                              const char *seckeyfilename){
484
485
  int ret;
485
486
  
486
487
  if(debug){
503
504
  }
504
505
  
505
506
  /* OpenPGP credentials */
506
 
  ret = gnutls_certificate_allocate_credentials(&mc->cred);
 
507
  ret = gnutls_certificate_allocate_credentials(&mc.cred);
507
508
  if(ret != GNUTLS_E_SUCCESS){
508
509
    fprintf_plus(stderr, "GnuTLS memory error: %s\n",
509
510
                 safer_gnutls_strerror(ret));
519
520
  }
520
521
  
521
522
  ret = gnutls_certificate_set_openpgp_key_file
522
 
    (mc->cred, pubkeyfilename, seckeyfilename,
 
523
    (mc.cred, pubkeyfilename, seckeyfilename,
523
524
     GNUTLS_OPENPGP_FMT_BASE64);
524
525
  if(ret != GNUTLS_E_SUCCESS){
525
526
    fprintf_plus(stderr,
531
532
  }
532
533
  
533
534
  /* GnuTLS server initialization */
534
 
  ret = gnutls_dh_params_init(&mc->dh_params);
 
535
  ret = gnutls_dh_params_init(&mc.dh_params);
535
536
  if(ret != GNUTLS_E_SUCCESS){
536
537
    fprintf_plus(stderr, "Error in GnuTLS DH parameter"
537
538
                 " initialization: %s\n",
538
539
                 safer_gnutls_strerror(ret));
539
540
    goto globalfail;
540
541
  }
541
 
  ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
542
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
542
543
  if(ret != GNUTLS_E_SUCCESS){
543
544
    fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
544
545
                 safer_gnutls_strerror(ret));
545
546
    goto globalfail;
546
547
  }
547
548
  
548
 
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
 
549
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
549
550
  
550
551
  return 0;
551
552
  
552
553
 globalfail:
553
554
  
554
 
  gnutls_certificate_free_credentials(mc->cred);
 
555
  gnutls_certificate_free_credentials(mc.cred);
555
556
  gnutls_global_deinit();
556
 
  gnutls_dh_params_deinit(mc->dh_params);
 
557
  gnutls_dh_params_deinit(mc.dh_params);
557
558
  return -1;
558
559
}
559
560
 
560
 
static int init_gnutls_session(gnutls_session_t *session,
561
 
                               mandos_context *mc){
 
561
static int init_gnutls_session(gnutls_session_t *session){
562
562
  int ret;
563
563
  /* GnuTLS session creation */
564
564
  do {
576
576
  {
577
577
    const char *err;
578
578
    do {
579
 
      ret = gnutls_priority_set_direct(*session, mc->priority, &err);
 
579
      ret = gnutls_priority_set_direct(*session, mc.priority, &err);
580
580
      if(quit_now){
581
581
        gnutls_deinit(*session);
582
582
        return -1;
593
593
  
594
594
  do {
595
595
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
596
 
                                 mc->cred);
 
596
                                 mc.cred);
597
597
    if(quit_now){
598
598
      gnutls_deinit(*session);
599
599
      return -1;
609
609
  /* ignore client certificate if any. */
610
610
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
611
611
  
612
 
  gnutls_dh_set_prime_bits(*session, mc->dh_bits);
 
612
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
613
613
  
614
614
  return 0;
615
615
}
621
621
/* Called when a Mandos server is found */
622
622
static int start_mandos_communication(const char *ip, in_port_t port,
623
623
                                      AvahiIfIndex if_index,
624
 
                                      int af, mandos_context *mc){
 
624
                                      int af){
625
625
  int ret, tcp_sd = -1;
626
626
  ssize_t sret;
627
627
  union {
657
657
    return -1;
658
658
  }
659
659
  
660
 
  ret = init_gnutls_session(&session, mc);
 
660
  ret = init_gnutls_session(&session);
661
661
  if(ret != 0){
662
662
    return -1;
663
663
  }
935
935
  if(buffer_length > 0){
936
936
    ssize_t decrypted_buffer_size;
937
937
    decrypted_buffer_size = pgp_packet_decrypt(buffer, buffer_length,
938
 
                                               &decrypted_buffer, mc);
 
938
                                               &decrypted_buffer);
939
939
    if(decrypted_buffer_size >= 0){
940
940
      
941
941
      written = 0;
1002
1002
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
1003
1003
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
1004
1004
                             flags,
1005
 
                             void* mc){
 
1005
                             AVAHI_GCC_UNUSED void* userdata){
1006
1006
  if(r == NULL){
1007
1007
    return;
1008
1008
  }
1020
1020
    fprintf_plus(stderr, "(Avahi Resolver) Failed to resolve service "
1021
1021
                 "'%s' of type '%s' in domain '%s': %s\n", name, type,
1022
1022
                 domain,
1023
 
                 avahi_strerror(avahi_server_errno
1024
 
                                (((mandos_context*)mc)->server)));
 
1023
                 avahi_strerror(avahi_server_errno(mc.server)));
1025
1024
    break;
1026
1025
    
1027
1026
  case AVAHI_RESOLVER_FOUND:
1035
1034
      }
1036
1035
      int ret = start_mandos_communication(ip, (in_port_t)port,
1037
1036
                                           interface,
1038
 
                                           avahi_proto_to_af(proto),
1039
 
                                           mc);
 
1037
                                           avahi_proto_to_af(proto));
1040
1038
      if(ret == 0){
1041
1039
        avahi_simple_poll_quit(simple_poll);
1042
1040
      } else {
1043
1041
        if(not add_server(ip, (in_port_t)port, interface,
1044
 
                          avahi_proto_to_af(proto),
1045
 
                          &((mandos_context*)mc)->current_server)){
 
1042
                          avahi_proto_to_af(proto))){
1046
1043
          fprintf_plus(stderr, "Failed to add server \"%s\" to server"
1047
1044
                       " list\n", name);
1048
1045
        }
1061
1058
                            const char *domain,
1062
1059
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
1063
1060
                            flags,
1064
 
                            void* mc){
 
1061
                            AVAHI_GCC_UNUSED void* userdata){
1065
1062
  if(b == NULL){
1066
1063
    return;
1067
1064
  }
1078
1075
  case AVAHI_BROWSER_FAILURE:
1079
1076
    
1080
1077
    fprintf_plus(stderr, "(Avahi browser) %s\n",
1081
 
                 avahi_strerror(avahi_server_errno
1082
 
                                (((mandos_context*)mc)->server)));
 
1078
                 avahi_strerror(avahi_server_errno(mc.server)));
1083
1079
    avahi_simple_poll_quit(simple_poll);
1084
1080
    return;
1085
1081
    
1089
1085
       the callback function is called the Avahi server will free the
1090
1086
       resolver for us. */
1091
1087
    
1092
 
    if(avahi_s_service_resolver_new(((mandos_context*)mc)->server,
1093
 
                                    interface, protocol, name, type,
1094
 
                                    domain, protocol, 0,
1095
 
                                    resolve_callback, mc) == NULL)
 
1088
    if(avahi_s_service_resolver_new(mc.server, interface, protocol,
 
1089
                                    name, type, domain, protocol, 0,
 
1090
                                    resolve_callback, NULL) == NULL)
1096
1091
      fprintf_plus(stderr, "Avahi: Failed to resolve service '%s':"
1097
1092
                   " %s\n", name,
1098
 
                   avahi_strerror(avahi_server_errno
1099
 
                                  (((mandos_context*)mc)->server)));
 
1093
                   avahi_strerror(avahi_server_errno(mc.server)));
1100
1094
    break;
1101
1095
    
1102
1096
  case AVAHI_BROWSER_REMOVE:
1322
1316
  return 1;
1323
1317
}
1324
1318
 
1325
 
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval,
1326
 
                            mandos_context *mc){
 
1319
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval){
1327
1320
  int ret;
1328
1321
  struct timespec now;
1329
1322
  struct timespec waited_time;
1330
1323
  intmax_t block_time;
1331
1324
  
1332
1325
  while(true){
1333
 
    if(mc->current_server == NULL){
 
1326
    if(mc.current_server == NULL){
1334
1327
      if (debug){
1335
1328
        fprintf_plus(stderr, "Wait until first server is found."
1336
1329
                     " No timeout!\n");
1350
1343
      /* Calculating in ms how long time between now and server
1351
1344
         who we visted longest time ago. Now - last seen.  */
1352
1345
      waited_time.tv_sec = (now.tv_sec
1353
 
                            - mc->current_server->last_seen.tv_sec);
 
1346
                            - mc.current_server->last_seen.tv_sec);
1354
1347
      waited_time.tv_nsec = (now.tv_nsec
1355
 
                             - mc->current_server->last_seen.tv_nsec);
 
1348
                             - mc.current_server->last_seen.tv_nsec);
1356
1349
      /* total time is 10s/10,000ms.
1357
1350
         Converting to s from ms by dividing by 1,000,
1358
1351
         and ns to ms by dividing by 1,000,000. */
1366
1359
      }
1367
1360
      
1368
1361
      if(block_time <= 0){
1369
 
        ret = start_mandos_communication(mc->current_server->ip,
1370
 
                                         mc->current_server->port,
1371
 
                                         mc->current_server->if_index,
1372
 
                                         mc->current_server->af, mc);
 
1362
        ret = start_mandos_communication(mc.current_server->ip,
 
1363
                                         mc.current_server->port,
 
1364
                                         mc.current_server->if_index,
 
1365
                                         mc.current_server->af);
1373
1366
        if(ret == 0){
1374
 
          avahi_simple_poll_quit(s);
 
1367
          avahi_simple_poll_quit(simple_poll);
1375
1368
          return 0;
1376
1369
        }
1377
1370
        ret = clock_gettime(CLOCK_MONOTONIC,
1378
 
                            &mc->current_server->last_seen);
 
1371
                            &mc.current_server->last_seen);
1379
1372
        if(ret == -1){
1380
1373
          perror_plus("clock_gettime");
1381
1374
          return -1;
1382
1375
        }
1383
 
        mc->current_server = mc->current_server->next;
 
1376
        mc.current_server = mc.current_server->next;
1384
1377
        block_time = 0;         /* Call avahi to find new Mandos
1385
1378
                                   servers, but don't block */
1386
1379
      }
1753
1746
}
1754
1747
 
1755
1748
int main(int argc, char *argv[]){
1756
 
  mandos_context mc = { .server = NULL, .dh_bits = 1024,
1757
 
                        .priority = "SECURE256:!CTYPE-X.509:"
1758
 
                        "+CTYPE-OPENPGP", .current_server = NULL };
1759
1749
  AvahiSServiceBrowser *sb = NULL;
1760
1750
  error_t ret_errno;
1761
1751
  int ret;
2195
2185
    goto end;
2196
2186
  }
2197
2187
  
2198
 
  ret = init_gnutls_global(pubkey, seckey, &mc);
 
2188
  ret = init_gnutls_global(pubkey, seckey);
2199
2189
  if(ret == -1){
2200
2190
    fprintf_plus(stderr, "init_gnutls_global failed\n");
2201
2191
    exitcode = EX_UNAVAILABLE;
2218
2208
    goto end;
2219
2209
  }
2220
2210
  
2221
 
  if(not init_gpgme(pubkey, seckey, tempdir, &mc)){
 
2211
  if(not init_gpgme(pubkey, seckey, tempdir)){
2222
2212
    fprintf_plus(stderr, "init_gpgme failed\n");
2223
2213
    exitcode = EX_UNAVAILABLE;
2224
2214
    goto end;
2281
2271
    }
2282
2272
    
2283
2273
    while(not quit_now){
2284
 
      ret = start_mandos_communication(address, port, if_index, af,
2285
 
                                       &mc);
 
2274
      ret = start_mandos_communication(address, port, if_index, af);
2286
2275
      if(quit_now or ret == 0){
2287
2276
        break;
2288
2277
      }
2336
2325
  /* Create the Avahi service browser */
2337
2326
  sb = avahi_s_service_browser_new(mc.server, if_index,
2338
2327
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
2339
 
                                   NULL, 0, browse_callback,
2340
 
                                   (void *)&mc);
 
2328
                                   NULL, 0, browse_callback, NULL);
2341
2329
  if(sb == NULL){
2342
2330
    fprintf_plus(stderr, "Failed to create service browser: %s\n",
2343
2331
                 avahi_strerror(avahi_server_errno(mc.server)));
2356
2344
  }
2357
2345
 
2358
2346
  ret = avahi_loop_with_timeout(simple_poll,
2359
 
                                (int)(retry_interval * 1000), &mc);
 
2347
                                (int)(retry_interval * 1000));
2360
2348
  if(debug){
2361
2349
    fprintf_plus(stderr, "avahi_loop_with_timeout exited %s\n",
2362
2350
                 (ret == 0) ? "successfully" : "with error");