/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

Show diffs side-by-side

added added

removed removed

Lines of Context:
80
80
                                   argp_parse(), ARGP_KEY_ARG,
81
81
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
82
82
#include <signal.h>             /* sigemptyset(), sigaddset(),
83
 
                                   sigaction(), SIGTERM, sig_atomic_t,
84
 
                                   raise() */
 
83
                                   sigaction(), SIGTERM, sigaction,
 
84
                                   sig_atomic_t */
85
85
 
86
86
#ifdef __linux__
87
87
#include <sys/klog.h>           /* klogctl() */
249
249
    return false;
250
250
  }
251
251
  
252
 
  return true;
 
252
  return true; 
253
253
}
254
254
 
255
255
/* 
514
514
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
515
515
                      __attribute__((unused)) const char *txt){}
516
516
 
517
 
sig_atomic_t quit_now = 0;
518
 
int signal_received = 0;
519
 
 
520
517
/* Called when a Mandos server is found */
521
518
static int start_mandos_communication(const char *ip, uint16_t port,
522
519
                                      AvahiIfIndex if_index,
523
520
                                      int af){
524
 
  int ret, tcp_sd = -1;
 
521
  int ret, tcp_sd;
525
522
  ssize_t sret;
526
523
  union {
527
524
    struct sockaddr_in in;
537
534
  gnutls_session_t session;
538
535
  int pf;                       /* Protocol family */
539
536
  
540
 
  if(quit_now){
541
 
    return -1;
542
 
  }
543
 
  
544
537
  switch(af){
545
538
  case AF_INET6:
546
539
    pf = PF_INET6;
566
559
  tcp_sd = socket(pf, SOCK_STREAM, 0);
567
560
  if(tcp_sd < 0){
568
561
    perror("socket");
569
 
    retval = -1;
570
 
    goto mandos_end;
571
 
  }
572
 
  
573
 
  if(quit_now){
574
 
    goto mandos_end;
 
562
    return -1;
575
563
  }
576
564
  
577
565
  memset(&to, 0, sizeof(to));
584
572
  }
585
573
  if(ret < 0 ){
586
574
    perror("inet_pton");
587
 
    retval = -1;
588
 
    goto mandos_end;
 
575
    return -1;
589
576
  }
590
577
  if(ret == 0){
591
578
    fprintf(stderr, "Bad address: %s\n", ip);
592
 
    retval = -1;
593
 
    goto mandos_end;
 
579
    return -1;
594
580
  }
595
581
  if(af == AF_INET6){
596
582
    to.in6.sin6_port = htons(port); /* Spurious warnings from
603
589
      if(if_index == AVAHI_IF_UNSPEC){
604
590
        fprintf(stderr, "An IPv6 link-local address is incomplete"
605
591
                " without a network interface\n");
606
 
        retval = -1;
607
 
        goto mandos_end;
 
592
        return -1;
608
593
      }
609
594
      /* Set the network interface number as scope */
610
595
      to.in6.sin6_scope_id = (uint32_t)if_index;
615
600
                                     -Wunreachable-code */
616
601
  }
617
602
  
618
 
  if(quit_now){
619
 
    goto mandos_end;
620
 
  }
621
 
  
622
603
  if(debug){
623
604
    if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
624
605
      char interface[IF_NAMESIZE];
651
632
    }
652
633
  }
653
634
  
654
 
  if(quit_now){
655
 
    goto mandos_end;
656
 
  }
657
 
  
658
635
  if(af == AF_INET6){
659
636
    ret = connect(tcp_sd, &to.in6, sizeof(to));
660
637
  } else {
662
639
  }
663
640
  if(ret < 0){
664
641
    perror("connect");
665
 
    retval = -1;
666
 
    goto mandos_end;
667
 
  }
668
 
  
669
 
  if(quit_now){
670
 
    goto mandos_end;
 
642
    return -1;
671
643
  }
672
644
  
673
645
  const char *out = mandos_protocol_version;
692
664
        break;
693
665
      }
694
666
    }
695
 
  
696
 
    if(quit_now){
697
 
      goto mandos_end;
698
 
    }
699
667
  }
700
668
  
701
669
  if(debug){
702
670
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
703
671
  }
704
672
  
705
 
  if(quit_now){
706
 
    goto mandos_end;
707
 
  }
708
 
  
709
673
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
710
674
  
711
 
  if(quit_now){
712
 
    goto mandos_end;
713
 
  }
714
 
  
715
675
  do{
716
676
    ret = gnutls_handshake(session);
717
 
    if(quit_now){
718
 
      goto mandos_end;
719
 
    }
720
677
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
721
678
  
722
679
  if(ret != GNUTLS_E_SUCCESS){
736
693
  }
737
694
  
738
695
  while(true){
739
 
    
740
 
    if(quit_now){
741
 
      goto mandos_end;
742
 
    }
743
 
    
744
696
    buffer_capacity = incbuffer(&buffer, buffer_length,
745
697
                                   buffer_capacity);
746
698
    if(buffer_capacity == 0){
749
701
      goto mandos_end;
750
702
    }
751
703
    
752
 
    if(quit_now){
753
 
      goto mandos_end;
754
 
    }
755
 
    
756
704
    sret = gnutls_record_recv(session, buffer+buffer_length,
757
705
                              BUFFER_SIZE);
758
706
    if(sret == 0){
766
714
      case GNUTLS_E_REHANDSHAKE:
767
715
        do{
768
716
          ret = gnutls_handshake(session);
769
 
          
770
 
          if(quit_now){
771
 
            goto mandos_end;
772
 
          }
773
717
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
774
718
        if(ret < 0){
775
719
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
794
738
    fprintf(stderr, "Closing TLS session\n");
795
739
  }
796
740
  
797
 
  if(quit_now){
798
 
    goto mandos_end;
799
 
  }
800
 
  
801
741
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
802
742
  
803
 
  if(quit_now){
804
 
    goto mandos_end;
805
 
  }
806
 
  
807
743
  if(buffer_length > 0){
808
744
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
809
745
                                               buffer_length,
811
747
    if(decrypted_buffer_size >= 0){
812
748
      written = 0;
813
749
      while(written < (size_t) decrypted_buffer_size){
814
 
        if(quit_now){
815
 
          goto mandos_end;
816
 
        }
817
 
        
818
750
        ret = (int)fwrite(decrypted_buffer + written, 1,
819
751
                          (size_t)decrypted_buffer_size - written,
820
752
                          stdout);
840
772
  
841
773
 mandos_end:
842
774
  free(buffer);
843
 
  if(tcp_sd >= 0){
844
 
    ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
845
 
  }
 
775
  ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
846
776
  if(ret == -1){
847
777
    perror("close");
848
778
  }
849
779
  gnutls_deinit(session);
850
 
  if(quit_now){
851
 
    retval = -1;
852
 
  }
853
780
  return retval;
854
781
}
855
782
 
872
799
  /* Called whenever a service has been resolved successfully or
873
800
     timed out */
874
801
  
875
 
  if(quit_now){
876
 
    return;
877
 
  }
878
 
  
879
802
  switch(event){
880
803
  default:
881
804
  case AVAHI_RESOLVER_FAILURE:
918
841
  /* Called whenever a new services becomes available on the LAN or
919
842
     is removed from the LAN */
920
843
  
921
 
  if(quit_now){
922
 
    return;
923
 
  }
924
 
  
925
844
  switch(event){
926
845
  default:
927
846
  case AVAHI_BROWSER_FAILURE:
956
875
  }
957
876
}
958
877
 
 
878
sig_atomic_t quit_now = 0;
 
879
 
959
880
/* stop main loop after sigterm has been called */
960
 
static void handle_sigterm(int sig){
 
881
static void handle_sigterm(__attribute__((unused)) int sig){
961
882
  if(quit_now){
962
883
    return;
963
884
  }
964
885
  quit_now = 1;
965
 
  signal_received = sig;
966
886
  int old_errno = errno;
967
887
  if(mc.simple_poll != NULL){
968
888
    avahi_simple_poll_quit(mc.simple_poll);
980
900
  const char *interface = "eth0";
981
901
  struct ifreq network;
982
902
  int sd = -1;
983
 
  bool take_down_interface = false;
 
903
  bool interface_taken_up = false;
984
904
  uid_t uid;
985
905
  gid_t gid;
986
906
  char *connect_to = NULL;
1129
1049
    exitcode = EXIT_FAILURE;
1130
1050
    goto end;
1131
1051
  }
1132
 
  /* Need to check if the handler is SIG_IGN before handling:
1133
 
     | [[info:libc:Initial Signal Actions]] |
1134
 
     | [[info:libc:Basic Signal Handling]]  |
1135
 
  */
1136
 
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1137
 
  if(ret == -1){
1138
 
    perror("sigaction");
1139
 
    return EXIT_FAILURE;
1140
 
  }
1141
 
  if(old_sigterm_action.sa_handler != SIG_IGN){
1142
 
    ret = sigaction(SIGINT, &sigterm_action, NULL);
1143
 
    if(ret == -1){
1144
 
      perror("sigaction");
1145
 
      exitcode = EXIT_FAILURE;
1146
 
      goto end;
1147
 
    }
1148
 
  }
1149
 
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1150
 
  if(ret == -1){
1151
 
    perror("sigaction");
1152
 
    return EXIT_FAILURE;
1153
 
  }
1154
 
  if(old_sigterm_action.sa_handler != SIG_IGN){
1155
 
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
1156
 
    if(ret == -1){
1157
 
      perror("sigaction");
1158
 
      exitcode = EXIT_FAILURE;
1159
 
      goto end;
1160
 
    }
1161
 
  }
1162
 
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1163
 
  if(ret == -1){
1164
 
    perror("sigaction");
1165
 
    return EXIT_FAILURE;
1166
 
  }
1167
 
  if(old_sigterm_action.sa_handler != SIG_IGN){
1168
 
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
1169
 
    if(ret == -1){
1170
 
      perror("sigaction");
1171
 
      exitcode = EXIT_FAILURE;
1172
 
      goto end;
1173
 
    }
1174
 
  }
 
1052
  ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
 
1053
  if(ret == -1){
 
1054
    perror("sigaction");
 
1055
    exitcode = EXIT_FAILURE;
 
1056
    goto end;
 
1057
  }  
1175
1058
  
1176
1059
  /* If the interface is down, bring it up */
1177
1060
  if(interface[0] != '\0'){
1178
 
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1179
 
    if(if_index == 0){
1180
 
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1181
 
      exitcode = EXIT_FAILURE;
1182
 
      goto end;
1183
 
    }
1184
 
    
1185
 
    if(quit_now){
1186
 
      goto end;
1187
 
    }
1188
 
    
1189
1061
#ifdef __linux__
1190
1062
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1191
1063
       messages to mess up the prompt */
1228
1100
    }
1229
1101
    if((network.ifr_flags & IFF_UP) == 0){
1230
1102
      network.ifr_flags |= IFF_UP;
1231
 
      take_down_interface = true;
1232
1103
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
1233
1104
      if(ret == -1){
1234
 
        take_down_interface = false;
1235
1105
        perror("ioctl SIOCSIFFLAGS");
1236
1106
        exitcode = EXIT_FAILURE;
1237
1107
#ifdef __linux__
1244
1114
#endif  /* __linux__ */
1245
1115
        goto end;
1246
1116
      }
 
1117
      interface_taken_up = true;
1247
1118
    }
1248
1119
    /* sleep checking until interface is running */
1249
1120
    for(int i=0; i < delay * 4; i++){
1259
1130
        perror("nanosleep");
1260
1131
      }
1261
1132
    }
1262
 
    if(not take_down_interface){
1263
 
      /* We won't need the socket anymore */
 
1133
    if(not interface_taken_up){
1264
1134
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1265
1135
      if(ret == -1){
1266
1136
        perror("close");
1277
1147
#endif  /* __linux__ */
1278
1148
  }
1279
1149
  
1280
 
  if(quit_now){
1281
 
    goto end;
1282
 
  }
1283
 
  
1284
1150
  uid = getuid();
1285
1151
  gid = getgid();
1286
1152
  
1295
1161
    perror("setuid");
1296
1162
  }
1297
1163
  
1298
 
  if(quit_now){
1299
 
    goto end;
1300
 
  }
1301
 
  
1302
1164
  ret = init_gnutls_global(pubkey, seckey);
1303
1165
  if(ret == -1){
1304
1166
    fprintf(stderr, "init_gnutls_global failed\n");
1308
1170
    gnutls_initialized = true;
1309
1171
  }
1310
1172
  
1311
 
  if(quit_now){
1312
 
    goto end;
1313
 
  }
1314
 
  
1315
 
  tempdir_created = true;
1316
1173
  if(mkdtemp(tempdir) == NULL){
1317
 
    tempdir_created = false;
1318
1174
    perror("mkdtemp");
1319
1175
    goto end;
1320
1176
  }
1321
 
  
1322
 
  if(quit_now){
1323
 
    goto end;
1324
 
  }
 
1177
  tempdir_created = true;
1325
1178
  
1326
1179
  if(not init_gpgme(pubkey, seckey, tempdir)){
1327
1180
    fprintf(stderr, "init_gpgme failed\n");
1331
1184
    gpgme_initialized = true;
1332
1185
  }
1333
1186
  
1334
 
  if(quit_now){
1335
 
    goto end;
 
1187
  if(interface[0] != '\0'){
 
1188
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
1189
    if(if_index == 0){
 
1190
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
1191
      exitcode = EXIT_FAILURE;
 
1192
      goto end;
 
1193
    }
1336
1194
  }
1337
1195
  
1338
1196
  if(connect_to != NULL){
1344
1202
      exitcode = EXIT_FAILURE;
1345
1203
      goto end;
1346
1204
    }
1347
 
    
1348
 
    if(quit_now){
1349
 
      goto end;
1350
 
    }
1351
 
    
1352
1205
    uint16_t port;
1353
1206
    errno = 0;
1354
1207
    tmpmax = strtoimax(address+1, &tmp, 10);
1358
1211
      exitcode = EXIT_FAILURE;
1359
1212
      goto end;
1360
1213
    }
1361
 
  
1362
 
    if(quit_now){
1363
 
      goto end;
1364
 
    }
1365
 
    
1366
1214
    port = (uint16_t)tmpmax;
1367
1215
    *address = '\0';
1368
1216
    address = connect_to;
1373
1221
    } else {
1374
1222
      af = AF_INET;
1375
1223
    }
1376
 
    
1377
 
    if(quit_now){
1378
 
      goto end;
1379
 
    }
1380
 
    
1381
1224
    ret = start_mandos_communication(address, port, if_index, af);
1382
1225
    if(ret < 0){
1383
1226
      exitcode = EXIT_FAILURE;
1386
1229
    }
1387
1230
    goto end;
1388
1231
  }
1389
 
  
1390
 
  if(quit_now){
1391
 
    goto end;
1392
 
  }
1393
 
  
 
1232
    
1394
1233
  {
1395
1234
    AvahiServerConfig config;
1396
1235
    /* Do not publish any local Zeroconf records */
1417
1256
    goto end;
1418
1257
  }
1419
1258
  
1420
 
  if(quit_now){
1421
 
    goto end;
1422
 
  }
1423
 
  
1424
1259
  /* Create the Avahi service browser */
1425
1260
  sb = avahi_s_service_browser_new(mc.server, if_index,
1426
1261
                                   AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1432
1267
    goto end;
1433
1268
  }
1434
1269
  
1435
 
  if(quit_now){
1436
 
    goto end;
1437
 
  }
1438
 
  
1439
1270
  /* Run the main loop */
1440
1271
  
1441
1272
  if(debug){
1471
1302
  }
1472
1303
  
1473
1304
  /* Take down the network interface */
1474
 
  if(take_down_interface){
 
1305
  if(interface_taken_up){
1475
1306
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
1476
1307
    if(ret == -1){
1477
1308
      perror("ioctl SIOCGIFFLAGS");
1532
1363
    }
1533
1364
  }
1534
1365
  
1535
 
  if(quit_now){
1536
 
    sigemptyset(&old_sigterm_action.sa_mask);
1537
 
    old_sigterm_action.sa_handler = SIG_DFL;
1538
 
    ret = sigaction(signal_received, &old_sigterm_action, NULL);
1539
 
    if(ret == -1){
1540
 
      perror("sigaction");
1541
 
    }
1542
 
    raise(signal_received);
1543
 
  }
1544
 
  
1545
1366
  return exitcode;
1546
1367
}