57
57
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
58
58
inet_pton(), connect(),
60
#include <fcntl.h> /* open(), unlinkat(), AT_REMOVEDIR */
60
#include <fcntl.h> /* open(), unlinkat() */
61
61
#include <dirent.h> /* opendir(), struct dirent, readdir()
63
63
#include <inttypes.h> /* PRIu16, PRIdMAX, intmax_t,
65
#include <errno.h> /* perror(), errno, EINTR, EINVAL,
66
EAI_SYSTEM, ENETUNREACH,
67
EHOSTUNREACH, ECONNREFUSED, EPROTO,
68
EIO, ENOENT, ENXIO, ENOMEM, EISDIR,
65
#include <errno.h> /* perror(), errno,
70
66
program_invocation_short_name */
71
67
#include <time.h> /* nanosleep(), time(), sleep() */
72
68
#include <net/if.h> /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
517
508
fprintf_plus(stderr, "GnuTLS: %s", string);
520
__attribute__((nonnull(1, 2, 4), warn_unused_result))
511
__attribute__((nonnull, warn_unused_result))
521
512
static int init_gnutls_global(const char *pubkeyfilename,
522
513
const char *seckeyfilename,
523
const char *dhparamsfilename,
524
514
mandos_context *mc){
529
518
fprintf_plus(stderr, "Initializing GnuTLS\n");
521
ret = gnutls_global_init();
522
if(ret != GNUTLS_E_SUCCESS){
523
fprintf_plus(stderr, "GnuTLS global_init: %s\n",
524
safer_gnutls_strerror(ret));
533
529
/* "Use a log level over 10 to enable all debugging options."
534
530
* - GnuTLS manual
572
569
safer_gnutls_strerror(ret));
575
/* If a Diffie-Hellman parameters file was given, try to use it */
576
if(dhparamsfilename != NULL){
577
gnutls_datum_t params = { .data = NULL, .size = 0 };
579
int dhpfile = open(dhparamsfilename, O_RDONLY);
582
dhparamsfilename = NULL;
585
size_t params_capacity = 0;
587
params_capacity = incbuffer((char **)¶ms.data,
589
(size_t)params_capacity);
590
if(params_capacity == 0){
591
perror_plus("incbuffer");
594
dhparamsfilename = NULL;
597
ssize_t bytes_read = read(dhpfile,
598
params.data + params.size,
604
/* check bytes_read for failure */
609
dhparamsfilename = NULL;
612
params.size += (unsigned int)bytes_read;
614
if(params.data == NULL){
615
dhparamsfilename = NULL;
617
if(dhparamsfilename == NULL){
620
ret = gnutls_dh_params_import_pkcs3(mc->dh_params, ¶ms,
621
GNUTLS_X509_FMT_PEM);
622
if(ret != GNUTLS_E_SUCCESS){
623
fprintf_plus(stderr, "Failed to parse DH parameters in file"
624
" \"%s\": %s\n", dhparamsfilename,
625
safer_gnutls_strerror(ret));
626
dhparamsfilename = NULL;
630
if(dhparamsfilename == NULL){
631
if(mc->dh_bits == 0){
632
/* Find out the optimal number of DH bits */
633
/* Try to read the private key file */
634
gnutls_datum_t buffer = { .data = NULL, .size = 0 };
636
int secfile = open(seckeyfilename, O_RDONLY);
641
size_t buffer_capacity = 0;
643
buffer_capacity = incbuffer((char **)&buffer.data,
645
(size_t)buffer_capacity);
646
if(buffer_capacity == 0){
647
perror_plus("incbuffer");
652
ssize_t bytes_read = read(secfile,
653
buffer.data + buffer.size,
659
/* check bytes_read for failure */
666
buffer.size += (unsigned int)bytes_read;
670
/* If successful, use buffer to parse private key */
671
gnutls_sec_param_t sec_param = GNUTLS_SEC_PARAM_ULTRA;
672
if(buffer.data != NULL){
674
gnutls_openpgp_privkey_t privkey = NULL;
675
ret = gnutls_openpgp_privkey_init(&privkey);
676
if(ret != GNUTLS_E_SUCCESS){
677
fprintf_plus(stderr, "Error initializing OpenPGP key"
679
safer_gnutls_strerror(ret));
683
ret = gnutls_openpgp_privkey_import
684
(privkey, &buffer, GNUTLS_OPENPGP_FMT_BASE64, "", 0);
685
if(ret != GNUTLS_E_SUCCESS){
686
fprintf_plus(stderr, "Error importing OpenPGP key : %s",
687
safer_gnutls_strerror(ret));
693
/* Use private key to suggest an appropriate
695
sec_param = gnutls_openpgp_privkey_sec_param(privkey);
696
gnutls_openpgp_privkey_deinit(privkey);
698
fprintf_plus(stderr, "This OpenPGP key implies using"
699
" a GnuTLS security parameter \"%s\".\n",
700
safe_string(gnutls_sec_param_get_name
706
if(sec_param == GNUTLS_SEC_PARAM_UNKNOWN){
707
/* Err on the side of caution */
708
sec_param = GNUTLS_SEC_PARAM_ULTRA;
710
fprintf_plus(stderr, "Falling back to security parameter"
712
safe_string(gnutls_sec_param_get_name
717
uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
721
fprintf_plus(stderr, "A \"%s\" GnuTLS security parameter"
722
" implies %u DH bits; using that.\n",
723
safe_string(gnutls_sec_param_get_name
728
fprintf_plus(stderr, "Failed to get implied number of DH"
729
" bits for security parameter \"%s\"): %s\n",
730
safe_string(gnutls_sec_param_get_name
732
safer_gnutls_strerror(ret));
736
fprintf_plus(stderr, "DH bits explicitly set to %u\n",
739
ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
740
if(ret != GNUTLS_E_SUCCESS){
741
fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
742
" bits): %s\n", mc->dh_bits,
743
safer_gnutls_strerror(ret));
572
ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
573
if(ret != GNUTLS_E_SUCCESS){
574
fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
575
safer_gnutls_strerror(ret));
747
579
gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
1126
960
goto mandos_end;
963
memset(&to, 0, sizeof(to));
1129
964
if(af == AF_INET6){
1130
struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&to;
1131
*to6 = (struct sockaddr_in6){ .sin6_family = (sa_family_t)af };
1132
ret = inet_pton(af, ip, &to6->sin6_addr);
965
((struct sockaddr_in6 *)&to)->sin6_family = (sa_family_t)af;
966
ret = inet_pton(af, ip, &((struct sockaddr_in6 *)&to)->sin6_addr);
1133
967
} else { /* IPv4 */
1134
struct sockaddr_in *to4 = (struct sockaddr_in *)&to;
1135
*to4 = (struct sockaddr_in){ .sin_family = (sa_family_t)af };
1136
ret = inet_pton(af, ip, &to4->sin_addr);
968
((struct sockaddr_in *)&to)->sin_family = (sa_family_t)af;
969
ret = inet_pton(af, ip, &((struct sockaddr_in *)&to)->sin_addr);
3028
2838
free(interfaces_to_take_down);
3029
2839
free(interfaces_hooks);
3031
void clean_dir_at(int base, const char * const dirname,
3033
struct dirent **direntries = NULL;
3035
int dir_fd = (int)TEMP_FAILURE_RETRY(openat(base, dirname,
3041
perror_plus("open");
3043
int numentries = scandirat(dir_fd, ".", &direntries,
3044
notdotentries, alphasort);
3045
if(numentries >= 0){
3046
for(int i = 0; i < numentries; i++){
3048
fprintf_plus(stderr, "Unlinking \"%s/%s\"\n",
3049
dirname, direntries[i]->d_name);
3051
dret = unlinkat(dir_fd, direntries[i]->d_name, 0);
3053
if(errno == EISDIR){
3054
dret = unlinkat(dir_fd, direntries[i]->d_name,
3057
if((dret == -1) and (errno == ENOTEMPTY)
3058
and (strcmp(direntries[i]->d_name, "private-keys-v1.d")
3059
== 0) and (level == 0)){
3060
/* Recurse only in this special case */
3061
clean_dir_at(dir_fd, direntries[i]->d_name, level+1);
3065
fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
3066
direntries[i]->d_name, strerror(errno));
3069
free(direntries[i]);
3072
/* need to clean even if 0 because man page doesn't specify */
3074
if(numentries == -1){
3075
perror_plus("scandirat");
3077
dret = unlinkat(base, dirname, AT_REMOVEDIR);
3078
if(dret == -1 and errno != ENOENT){
3079
perror_plus("rmdir");
3082
perror_plus("scandirat");
3087
2841
/* Removes the GPGME temp directory and all files inside */
3088
2842
if(tempdir != NULL){
3089
clean_dir_at(-1, tempdir, 0);
2843
struct dirent **direntries = NULL;
2844
int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY
2848
if(tempdir_fd == -1){
2849
perror_plus("open");
2852
#if __GLIBC_PREREQ(2, 15)
2853
int numentries = scandirat(tempdir_fd, ".", &direntries,
2854
notdotentries, alphasort);
2855
#else /* not __GLIBC_PREREQ(2, 15) */
2856
int numentries = scandir(tempdir, &direntries, notdotentries,
2858
#endif /* not __GLIBC_PREREQ(2, 15) */
2859
#else /* not __GLIBC__ */
2860
int numentries = scandir(tempdir, &direntries, notdotentries,
2862
#endif /* not __GLIBC__ */
2863
if(numentries >= 0){
2864
for(int i = 0; i < numentries; i++){
2865
ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0);
2867
fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY),"
2868
" \"%s\", 0): %s\n", tempdir,
2869
direntries[i]->d_name, strerror(errno));
2871
free(direntries[i]);
2874
/* need to clean even if 0 because man page doesn't specify */
2876
if(numentries == -1){
2877
perror_plus("scandir");
2879
ret = rmdir(tempdir);
2880
if(ret == -1 and errno != ENOENT){
2881
perror_plus("rmdir");
2884
TEMP_FAILURE_RETRY(close(tempdir_fd));