Switch from readdir_r back to readdir.

readdir and readdir_r have a sad history:
https://www.gnu.org/software/libc/manual/html_node/Reading_002fClosing-Directory.html
https://womble.decadent.org.uk/readdir_r-advisory.html
http://austingroupbugs.net/view.php?id=696

Martin Thomson reports that newer glibcs warn that readdir_r is
deprecated. Especially since this has been banished to libdecrepit
anyway, go ahead and honor that warning. OpenSSL also uses readdir, so
we're no worse than they are.

While I'm here, rewrite this to remove a useless layer of abstraction,
now that we've punted on supporting most platforms here. Also remove the
redundant documentation comment (there's one in the header already).

Change-Id: I5350c55417a7f5c4c4725f97dd63f960aeb96801
Reviewed-on: https://boringssl-review.googlesource.com/11220
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
David Benjamin 2016-09-22 10:59:11 -04:00 committed by CQ bot account: commit-bot@chromium.org
parent f3fbadeae0
commit a78e6a5ab5

View File

@ -114,111 +114,51 @@
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/mem.h> #include <openssl/mem.h>
typedef struct { int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
DIR *dir; const char *path) {
struct dirent dirent; DIR *dir = opendir(path);
} OPENSSL_DIR_CTX; if (dir == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
static const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, ERR_add_error_data(3, "opendir('", dir, "')");
const char *directory) {
struct dirent *dirent;
if (ctx == NULL || directory == NULL) {
errno = EINVAL;
return NULL;
}
errno = 0;
if (*ctx == NULL) {
*ctx = malloc(sizeof(OPENSSL_DIR_CTX));
if (*ctx == NULL) {
errno = ENOMEM;
return 0;
}
memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX));
(*ctx)->dir = opendir(directory);
if ((*ctx)->dir == NULL) {
int save_errno = errno; /* Probably not needed, but I'm paranoid */
free(*ctx);
*ctx = NULL;
errno = save_errno;
return 0;
}
}
if (readdir_r((*ctx)->dir, &(*ctx)->dirent, &dirent) != 0 ||
dirent == NULL) {
return 0; return 0;
} }
return (*ctx)->dirent.d_name;
}
static int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) {
if (ctx != NULL && *ctx != NULL) {
int r = closedir((*ctx)->dir);
free(*ctx);
*ctx = NULL;
return r == 0;
}
errno = EINVAL;
return 0;
}
/* Add a directory of certs to a stack.
*
* \param stack the stack to append to.
* \param dir the directory to append from. All files in this directory will be
* examined as potential certs. Any that are acceptable to
* SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will
* be included.
* \return 1 for success, 0 for failure. Note that in the case of failure some
* certs may have been added to \c stack. */
int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
const char *dir) {
OPENSSL_DIR_CTX *d = NULL;
const char *filename;
int ret = 0; int ret = 0;
for (;;) {
/* |readdir| may fail with or without setting |errno|. */
errno = 0;
struct dirent *dirent = readdir(dir);
if (dirent == NULL) {
if (errno) {
OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
ERR_add_error_data(3, "readdir('", path, "')");
} else {
ret = 1;
}
break;
}
/* Note that a side effect is that the CAs will be sorted by name */
while ((filename = OPENSSL_DIR_read(&d, dir))) {
char buf[1024]; char buf[1024];
int r; if (strlen(path) + strlen(dirent->d_name) + 2 > sizeof(buf)) {
if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PATH_TOO_LONG); OPENSSL_PUT_ERROR(SSL, SSL_R_PATH_TOO_LONG);
goto err; break;
} }
r = BIO_snprintf(buf, sizeof buf, "%s/%s", dir, filename); int r = BIO_snprintf(buf, sizeof(buf), "%s/%s", path, dirent->d_name);
if (r <= 0 || r >= (int)sizeof(buf) || if (r <= 0 ||
r >= (int)sizeof(buf) ||
!SSL_add_file_cert_subjects_to_stack(stack, buf)) { !SSL_add_file_cert_subjects_to_stack(stack, buf)) {
goto err; break;
} }
} }
if (errno) { closedir(dir);
OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB);
ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')");
goto err;
}
ret = 1;
err:
if (d) {
OPENSSL_DIR_end(&d);
}
return ret; return ret;
} }