Writability test for application data

This commit is contained in:
Willem Toorop 2017-09-16 18:16:21 +02:00
parent aa74c0a3d5
commit 463855d274
3 changed files with 183 additions and 52 deletions

View File

@ -1029,9 +1029,9 @@ static void tas_doc_read(getdns_context *context, tas_connection *a)
else { else {
context->trust_anchors = tas; context->trust_anchors = tas;
context->trust_anchors_len = tas_len; context->trust_anchors_len = tas_len;
_getdns_context_write_priv_file( (void) _getdns_context_write_priv_file(
context, "root-anchors.xml", &a->xml); context, "root-anchors.xml", &a->xml);
_getdns_context_write_priv_file( (void) _getdns_context_write_priv_file(
context, "root-anchors.p7s", &p7s_bd); context, "root-anchors.p7s", &p7s_bd);
tas_success(context, a); tas_success(context, a);
return; return;
@ -1403,7 +1403,7 @@ static void tas_connect(getdns_context *context, tas_connection *a)
GETDNS_SCHEDULE_EVENT(a->loop, a->fd, 2000, GETDNS_SCHEDULE_EVENT(a->loop, a->fd, 2000,
getdns_eventloop_event_init(&a->event, a->req->owner, getdns_eventloop_event_init(&a->event, a->req->owner,
NULL, tas_write_cb, tas_timeout_cb)); NULL, tas_write_cb, tas_timeout_cb));
DEBUG_ANCHOR("Scheduled write\n"); DEBUG_ANCHOR("Scheduled write with event\n");
return; return;
} else } else
DEBUG_ANCHOR("Connect error: %s\n", strerror(errno)); DEBUG_ANCHOR("Connect error: %s\n", strerror(errno));
@ -1420,8 +1420,11 @@ static void tas_happy_eyeballs_cb(void *userarg)
assert(dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_A); assert(dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_A);
if (tas_fetching(&context->aaaa)) if (tas_fetching(&context->aaaa))
return; return;
else else {
DEBUG_ANCHOR("AAAA came too late, clearing Happy Eyeballs timer\n");
GETDNS_CLEAR_EVENT(context->a.loop, &context->a.event);
tas_connect(context, &context->a); tas_connect(context, &context->a);
}
} }
static void _tas_hostname_lookup_cb(getdns_dns_req *dnsreq) static void _tas_hostname_lookup_cb(getdns_dns_req *dnsreq)
@ -1494,7 +1497,12 @@ void _getdns_start_fetching_ta(getdns_context *context, getdns_eventloop *loop)
const char *verify_CA; const char *verify_CA;
const char *verify_email; const char *verify_email;
if ((r = _getdns_get_tas_url_hostname(context, tas_hostname, NULL))) { if (!_getdns_context_can_write_appdata(context)) {
DEBUG_ANCHOR("NOTICE %s(): Not fetching TA, because "
"non writeable appdata directory\n", __FUNC__);
return;
} else if ((r = _getdns_get_tas_url_hostname(context, tas_hostname, NULL))) {
DEBUG_ANCHOR("ERROR %s(): Could not get_tas_url_hostname" DEBUG_ANCHOR("ERROR %s(): Could not get_tas_url_hostname"
": \"%s\"", __FUNC__ ": \"%s\"", __FUNC__
, getdns_get_errorstr_by_id(r)); , getdns_get_errorstr_by_id(r));

View File

@ -41,6 +41,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/time.h> #include <sys/time.h>
#include <netdb.h> #include <netdb.h>
#include <pwd.h>
#else #else
#include <winsock2.h> #include <winsock2.h>
#include <iphlpapi.h> #include <iphlpapi.h>
@ -4601,82 +4602,202 @@ getdns_context_config(getdns_context *context, const getdns_dict *config_dict)
return r; return r;
} }
static size_t _getdns_get_appdata(char *path)
{
size_t len;
#ifdef USE_WINSOCK
# define APPDATA_SUBDIR "getdns"
if (! SUCCEEDED(SHGetFolderPath(NULL,
CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path)))
DEBUG_ANCHOR("ERROR %s(): Could not get \%AppData\% directory\n"
, __FUNC__);
else if ((len = strlen(path)) + sizeof(APPDATA_SUBDIR) + 2 >= PATH_MAX)
DEBUG_ANCHOR("ERROR %s(): Home path too long for appdata\n"
, __FUNC__);
#else
# define APPDATA_SUBDIR ".getdns"
struct passwd *p = getpwuid(getuid());
char *home = NULL;
if (!(home = p ? p->pw_dir : getenv("HOME")))
DEBUG_ANCHOR("ERROR %s(): Could not get home directory\n"
, __FUNC__);
else if ((len = strlen(home)) + sizeof(APPDATA_SUBDIR) + 2 >= PATH_MAX)
DEBUG_ANCHOR("ERROR %s(): Home path too long for appdata\n"
, __FUNC__);
else if (!strcpy(path, home))
; /* strcpy returns path always */
#endif
else {
if (len == 0 || ( path[len - 1] != '/'
&& path[len - 1] != '\\')) {
path[len++] = '/';
path[len ] = '\0';
}
(void) strcpy(path + len, APPDATA_SUBDIR);
len += sizeof(APPDATA_SUBDIR) - 1;
if (mkdir(path, 0755) < 0 && errno != EEXIST)
DEBUG_ANCHOR("ERROR %s(): Could not mkdir %s: %s\n"
, __FUNC__, path, strerror(errno));
else {
path[len++] = '/';
path[len ] = '\0';
return len;
}
}
return 0;
}
uint8_t *_getdns_context_get_priv_file(getdns_context *context, uint8_t *_getdns_context_get_priv_file(getdns_context *context,
const char *fn, uint8_t *buf, size_t buf_len, size_t *file_sz) const char *fn, uint8_t *buf, size_t buf_len, size_t *file_sz)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
int n; FILE *f = NULL;
FILE *f; size_t len;
n = snprintf(path, sizeof(path), "%s/.getdns/%s", getenv("HOME"), fn); if (!(len = _getdns_get_appdata(path)))
if (n < 0 || n > PATH_MAX) DEBUG_ANCHOR("ERROR %s(): Could nog get application data path\n"
return NULL; , __FUNC__);
if (!(f = fopen(path, "r"))) else if (len + strlen(fn) >= sizeof(path))
return NULL; DEBUG_ANCHOR("ERROR %s(): Application data too long\n", __FUNC__);
if ((*file_sz = fread(buf, 1, buf_len, f)) < (buf_len - 1) && feof(f)) else if (!strcpy(path + len, fn))
; /* strcpy returns path + len always */
else if (!(f = fopen(path, "r")))
DEBUG_ANCHOR("ERROR %s(): Opening \"%s\": %s\n"
, __FUNC__, path, strerror(errno));
else if ((*file_sz = fread(buf, 1, buf_len, f)) < (buf_len - 1) && feof(f)) {
buf[*file_sz] = 0; buf[*file_sz] = 0;
(void) fclose(f);
return buf;
}
else if (fseek(f, 0, SEEK_END) < 0) else if (fseek(f, 0, SEEK_END) < 0)
buf = NULL; DEBUG_ANCHOR("ERROR %s(): Determining size of \"%s\": %s\n"
, __FUNC__, path, strerror(errno));
else if ((buf = GETDNS_XMALLOC( else if (!(buf = GETDNS_XMALLOC(
context->mf, uint8_t, (buf_len = ftell(f) + 1)))) { context->mf, uint8_t, (buf_len = ftell(f) + 1))))
DEBUG_ANCHOR("ERROR %s(): Allocating %d memory for \"%s\"\n"
, __FUNC__, (int)buf_len, path);
else {
rewind(f); rewind(f);
if ((*file_sz = fread(buf, 1, buf_len, f)) >= buf_len || !feof(f)) { if ((*file_sz = fread(buf, 1, buf_len, f)) >= buf_len || !feof(f)) {
GETDNS_FREE(context->mf, buf); GETDNS_FREE(context->mf, buf);
buf = NULL; DEBUG_ANCHOR("ERROR %s(): Reading \"%s\": %s\n"
, __FUNC__, path, strerror(errno));
} }
else else {
buf[*file_sz] = 0; buf[*file_sz] = 0;
(void) fclose(f);
return buf;
}
} }
(void) fclose(f); if (f)
return buf; (void) fclose(f);
return NULL;
} }
void _getdns_context_write_priv_file(getdns_context *context,
int _getdns_context_write_priv_file(getdns_context *context,
const char *fn, getdns_bindata *content) const char *fn, getdns_bindata *content)
{ {
char path[PATH_MAX], tmpfn[PATH_MAX]; char path[PATH_MAX], tmpfn[PATH_MAX];
int n, fd; int fd = -1;
FILE *f; FILE *f = NULL;
size_t len;
(void)context; if (!(len = _getdns_get_appdata(path)))
DEBUG_ANCHOR("ERROR %s(): Could nog get application data path\n"
, __FUNC__);
DEBUG_ANCHOR("%s\n", __FUNC__); else if (len + 6 >= sizeof(tmpfn)
|| len + strlen(fn) >= sizeof(path))
DEBUG_ANCHOR("ERROR %s(): Application data too long\n", __FUNC__);
n = snprintf( path, sizeof( path), "%s/.getdns/%s" , getenv("HOME"), fn);
if (n < 0 || n > PATH_MAX) {
DEBUG_ANCHOR("Could not create filename for writing\n");
return;
}
n = snprintf(tmpfn, sizeof(tmpfn), "%s/.getdns/XXXXXX", getenv("HOME")); else if (snprintf(tmpfn, sizeof(tmpfn), "%sXXXXXX", path) < 0)
if (n < 0 || n > PATH_MAX) { DEBUG_ANCHOR("ERROR %s(): Creating temporary filename template\n"
DEBUG_ANCHOR("Could not create tmpfn for writing\n"); , __FUNC__);
return;
}
if ((fd = mkstemp(tmpfn)) < 0) { else if (!strcpy(path + len, fn))
DEBUG_ANCHOR("Could not create temporary file from \"%s\": %s\n", ; /* strcpy returns path + len always */
tmpfn, strerror(errno));
return;
}
if (!(f = fdopen(fd, "w"))) { else if ((fd = mkstemp(tmpfn)) < 0)
close(fd); DEBUG_ANCHOR("ERROR %s(): Creating temporary file: %s\n"
return; , __FUNC__, strerror(errno));
}
if (fwrite(content->data, 1, content->size, f) != content->size) else if (!(f = fdopen(fd, "w")))
fclose(f); DEBUG_ANCHOR("ERROR %s(): Opening temporary file: %s\n"
, __FUNC__, strerror(errno));
else if (fwrite(content->data, 1, content->size, f) < content->size)
DEBUG_ANCHOR("ERROR %s(): Writing temporary file: %s\n"
, __FUNC__, strerror(errno));
else if (fclose(f) < 0)
DEBUG_ANCHOR("ERROR %s(): Closing temporary file: %s\n"
, __FUNC__, strerror(errno));
else if (rename(tmpfn, path) < 0)
DEBUG_ANCHOR("ERROR %s(): Renaming temporary file: %s\n"
, __FUNC__, strerror(errno));
else { else {
fclose(f); context->can_write_appdata = PROP_ABLE;
if (rename(tmpfn, path) == -1) return 1;
DEBUG_ANCHOR("Could not mv \"%s\" \"%s\": %s\n",
tmpfn, path, strerror(errno));
} }
if (f)
(void) fclose(f);
else if (fd >= 0)
(void) close(fd);
context->can_write_appdata = PROP_UNABLE;
return 0;
}
int _getdns_context_can_write_appdata(getdns_context *context)
{
char test_fn[30], path[PATH_MAX];
size_t len;
getdns_bindata test_content = { 4, (void *)"TEST" };
if (context->can_write_appdata == PROP_ABLE)
return 1;
else if (context->can_write_appdata == PROP_UNABLE)
return 0;
(void) snprintf( test_fn, sizeof(test_fn)
, "write-test-%d.tmp", arc4random());
if (!_getdns_context_write_priv_file(context, test_fn, &test_content))
return 0;
if (!(len = _getdns_get_appdata(path)))
DEBUG_ANCHOR("ERROR %s(): Could nog get application data path\n"
, __FUNC__);
else if (len + strlen(test_fn) >= sizeof(path))
DEBUG_ANCHOR("ERROR %s(): Application data too long\n", __FUNC__);
else if (!strcpy(path + len, test_fn))
; /* strcpy returns path + len always */
else if (unlink(path) < 0)
DEBUG_ANCHOR("ERROR %s(): Unlinking write test file \"%s\": %s\n"
, __FUNC__, path, strerror(errno));
return 1;
} }
getdns_return_t getdns_return_t

View File

@ -548,9 +548,11 @@ void _getdns_upstream_shutdown(getdns_upstream *upstream);
uint8_t *_getdns_context_get_priv_file(getdns_context *context, uint8_t *_getdns_context_get_priv_file(getdns_context *context,
const char *fn, uint8_t *buf, size_t buf_len, size_t *file_sz); const char *fn, uint8_t *buf, size_t buf_len, size_t *file_sz);
void _getdns_context_write_priv_file(getdns_context *context, int _getdns_context_write_priv_file(getdns_context *context,
const char *fn, getdns_bindata *content); const char *fn, getdns_bindata *content);
int _getdns_context_can_write_appdata(getdns_context *context);
void _getdns_upstream_reset(getdns_upstream *upstream); void _getdns_upstream_reset(getdns_upstream *upstream);
#endif /* _GETDNS_CONTEXT_H_ */ #endif /* _GETDNS_CONTEXT_H_ */