aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2013-12-19 23:59:41 +0000
committerRob Austein <sra@hactrn.net>2013-12-19 23:59:41 +0000
commit47bf2cf77e8a585fd592b31aedacd1e1f8a8bc36 (patch)
tree64bd82a4e0db5d0335720414df06dc90f35a2959
parentc6fc6fd2c0521d9ad44a62d9ff11065886bb122c (diff)
Rewrite all uses of readdir() to avoid using on dirent d_type field.
Some of this code was fairly unreadable, so this turned into a general clean up of the affected functions. See #660. svn path=/trunk/; revision=5610
-rw-r--r--rcynic/rcynic.c168
1 files changed, 73 insertions, 95 deletions
diff --git a/rcynic/rcynic.c b/rcynic/rcynic.c
index 4a4f2a72..fc20682d 100644
--- a/rcynic/rcynic.c
+++ b/rcynic/rcynic.c
@@ -1627,55 +1627,45 @@ static int set_directory(const rcynic_ctx_t *rc, path_t *out, const char *in, co
}
/**
+ * Test whether a filesystem path points to a directory.
+ */
+static int is_directory(const path_t *name)
+{
+ struct stat st;
+
+ assert(name);
+ return lstat(name->s, &st) == 0 && S_ISDIR(st.st_mode);
+}
+
+/**
* Remove a directory tree, like rm -rf.
*/
static int rm_rf(const path_t *name)
{
path_t path;
struct dirent *d;
- size_t len;
DIR *dir;
- int ret = 0, need_slash;
+ int ret = 0;
assert(name);
- len = strlen(name->s);
- assert(len > 0 && len < sizeof(path.s));
- need_slash = name->s[len - 1] != '/';
-
- if (rmdir(name->s) == 0)
- return 1;
- switch (errno) {
- case ENOENT:
- return 1;
- case ENOTEMPTY:
- break;
- default:
- return 0;
- }
+ if (!is_directory(name))
+ return unlink(name->s) == 0;
if ((dir = opendir(name->s)) == NULL)
return 0;
while ((d = readdir(dir)) != NULL) {
- if (d->d_name[0] == '.' && (d->d_name[1] == '\0' || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
- if (len + strlen(d->d_name) + need_slash >= sizeof(path.s))
+ if (snprintf(path.s, sizeof(path.s), "%s/%s", name->s, d->d_name) >= sizeof(path.s))
goto done;
- strcpy(path.s, name->s);
- if (need_slash)
- strcat(path.s, "/");
- strcat(path.s, d->d_name);
- switch (d->d_type) {
- case DT_DIR:
- if (!rm_rf(&path))
- goto done;
+ if (unlink(path.s) == 0)
continue;
- default:
- if (unlink(path.s) < 0)
- goto done;
+ else if (rm_rf(&path))
continue;
- }
+ else
+ goto done;
}
ret = rmdir(name->s) == 0;
@@ -1719,7 +1709,7 @@ static int construct_directory_names(rcynic_ctx_t *rc)
if (!set_directory(rc, &rc->old_authenticated, rc->authenticated.s, 1))
return 0;
- if (lstat(rc->authenticated.s, &st) == 0 && (st.st_mode & S_IFDIR) != 0 &&
+ if (lstat(rc->authenticated.s, &st) == 0 && S_ISDIR((st.st_mode)) &&
strlen(rc->authenticated.s) + sizeof(".old") < sizeof(p.s)) {
p = rc->authenticated;
strcat(p.s, ".old");
@@ -1727,7 +1717,7 @@ static int construct_directory_names(rcynic_ctx_t *rc)
(void) rename(rc->authenticated.s, p.s);
}
- if (lstat(rc->authenticated.s, &st) == 0 && (st.st_mode & S_IFDIR) != 0) {
+ if (lstat(rc->authenticated.s, &st) == 0 && S_ISDIR(st.st_mode)) {
logmsg(rc, log_usage_err,
"Existing %s directory is in the way, please remove it",
rc->authenticated.s);
@@ -1848,7 +1838,7 @@ static STACK_OF(OPENSSL_STRING) *directory_filenames(const rcynic_ctx_t *rc,
const uri_t *uri)
{
STACK_OF(OPENSSL_STRING) *result = NULL;
- path_t path;
+ path_t dpath, fpath;
const path_t *prefix = NULL;
DIR *dir = NULL;
struct dirent *d;
@@ -1867,14 +1857,20 @@ static STACK_OF(OPENSSL_STRING) *directory_filenames(const rcynic_ctx_t *rc,
goto done;
}
- if (!uri_to_filename(rc, uri, &path, prefix) ||
- (dir = opendir(path.s)) == NULL ||
+ if (!uri_to_filename(rc, uri, &dpath, prefix) ||
+ (dir = opendir(dpath.s)) == NULL ||
(result = sk_OPENSSL_STRING_new(uri_cmp)) == NULL)
goto done;
while ((d = readdir(dir)) != NULL)
- if (d->d_type != DT_DIR && !sk_OPENSSL_STRING_push_strdup(result, d->d_name))
+ if (snprintf(fpath.s, sizeof(fpath.s), "%s/%s", dpath.s, d->d_name) >= sizeof(fpath.s)) {
+ logmsg(rc, log_data_err, "Local path name %s/%s too long", dpath.s, d->d_name);
goto done;
+ }
+ else if (!is_directory(&fpath) && !sk_OPENSSL_STRING_push_strdup(result, d->d_name)) {
+ logmsg(rc, log_sys_err, "sk_OPENSSL_STRING_push_strdup() failed, probably memory exhaustion");
+ goto done;
+ }
ok = 1;
@@ -2993,71 +2989,53 @@ static int prune_unauthenticated(const rcynic_ctx_t *rc,
{
path_t path;
struct dirent *d;
- size_t len;
DIR *dir;
- int need_slash;
+ const char *slash;
- assert(rc && name && baselen > 0);
- len = strlen(name->s);
- assert(len >= baselen && len < sizeof(path.s));
- need_slash = name->s[len - 1] != '/';
+ assert(rc && name && baselen > 0 && strlen(name->s) >= baselen);
- if (validation_status_find_filename(rc, name->s + baselen)) {
- logmsg(rc, log_debug, "prune: cache hit for %s, not cleaning", name->s);
- return 1;
- }
-
- if (rmdir(name->s) == 0) {
- logmsg(rc, log_debug, "prune: removed %s", name->s);
- return 1;
+ if (!is_directory(name)) {
+ logmsg(rc, log_usage_err, "prune: %s is not a directory", name->s);
+ return 0;
}
- switch (errno) {
- case ENOENT:
- logmsg(rc, log_debug, "prune: nonexistant %s", name->s);
- return 1;
- case ENOTEMPTY:
- break;
- default:
- logmsg(rc, log_debug, "prune: other error %s: %s", name->s, strerror(errno));
+ if ((dir = opendir(name->s)) == NULL) {
+ logmsg(rc, log_sys_err, "prune: opendir() failed on %s: %s", name->s, strerror(errno));
return 0;
}
- if ((dir = opendir(name->s)) == NULL)
- return 0;
+ slash = endswith(name->s, "/") ? "" : "/";
while ((d = readdir(dir)) != NULL) {
- if (d->d_name[0] == '.' && (d->d_name[1] == '\0' || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
- if (len + strlen(d->d_name) + need_slash >= sizeof(path)) {
- logmsg(rc, log_debug, "prune: %s%s%s too long", name->s, (need_slash ? "/" : ""), d->d_name);
+
+ if (snprintf(path.s, sizeof(path.s), "%s%s%s", name->s, slash, d->d_name) >= sizeof(path.s)) {
+ logmsg(rc, log_debug, "prune: %s%s%s too long", name->s, slash, d->d_name);
goto done;
}
- strcpy(path.s, name->s);
- if (need_slash)
- strcat(path.s, "/");
- strcat(path.s, d->d_name);
- switch (d->d_type) {
- case DT_DIR:
- if (!prune_unauthenticated(rc, &path, baselen))
- goto done;
+
+ if (validation_status_find_filename(rc, path.s + baselen)) {
+ logmsg(rc, log_debug, "prune: cache hit %s", path.s);
continue;
- default:
- if (validation_status_find_filename(rc, path.s + baselen)) {
- logmsg(rc, log_debug, "prune: cache hit %s", path.s);
- continue;
- }
- if (unlink(path.s) < 0) {
- logmsg(rc, log_debug, "prune: removing %s failed: %s", path.s, strerror(errno));
- goto done;
- }
+ }
+
+ if (unlink(path.s) == 0) {
logmsg(rc, log_debug, "prune: removed %s", path.s);
continue;
}
+
+ if (prune_unauthenticated(rc, &path, baselen))
+ continue;
+
+ logmsg(rc, log_sys_err, "prune: removing %s failed: %s", path.s, strerror(errno));
+ goto done;
}
- if (rmdir(name->s) < 0 && errno != ENOTEMPTY)
- logmsg(rc, log_debug, "prune: couldn't remove %s: %s", name->s, strerror(errno));
+ if (rmdir(name->s) == 0)
+ logmsg(rc, log_debug, "prune: removed %s", name->s);
+ else if (errno != ENOTEMPTY)
+ logmsg(rc, log_sys_err, "prune: couldn't remove %s: %s", name->s, strerror(errno));
done:
closedir(dir);
@@ -5409,35 +5387,35 @@ static int check_ta_dir(rcynic_ctx_t *rc,
DIR *dir = NULL;
struct dirent *d;
path_t path;
- int ok = 1;
+ int is_cer, is_tal;
assert(rc && dn);
if ((dir = opendir(dn)) == NULL) {
logmsg(rc, log_sys_err, "Couldn't open trust anchor directory %s: %s",
dn, strerror(errno));
- ok = 0;
+ return 0;
}
- while (ok && (d = readdir(dir)) != NULL) {
- if (d->d_type != DT_REG && d->d_type != DT_LNK)
- continue;
+ while ((d = readdir(dir)) != NULL) {
if (snprintf(path.s, sizeof(path.s), "%s/%s", dn, d->d_name) >= sizeof(path.s)) {
logmsg(rc, log_data_err, "Pathname %s/%s too long", dn, d->d_name);
- ok = 0;
- } else if (endswith(path.s, ".cer")) {
- ok = check_ta_cer(rc, path.s);
- } else if (endswith(path.s, ".tal")) {
- ok = check_ta_tal(rc, path.s);
- } else {
- logmsg(rc, log_verbose, "Skipping non-trust-anchor %s", path.s);
+ break;
}
+ is_cer = endswith(path.s, ".cer");
+ is_tal = endswith(path.s, ".tal");
+ if (is_cer && !check_ta_cer(rc, path.s))
+ break;
+ if (is_tal && !check_ta_tal(rc, path.s))
+ break;
+ if (!is_cer && !is_tal)
+ logmsg(rc, log_verbose, "Skipping non-trust-anchor %s", path.s);
}
if (dir != NULL)
closedir(dir);
- return ok;
+ return !d;;
}