return result;
}
+static isc_result_t
+file_lstats(const char *file, struct stat *stats) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(file != NULL);
+ REQUIRE(stats != NULL);
+
+ if (lstat(file, stats) != 0) {
+ result = isc__errno2result(errno);
+ }
+
+ return result;
+}
+
static isc_result_t
fd_stats(int fd, struct stat *stats) {
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(filename != NULL);
REQUIRE(fp != NULL && *fp == NULL);
- result = file_stats(filename, &sb);
+ result = file_lstats(filename, &sb);
if (result == ISC_R_SUCCESS) {
- if ((sb.st_mode & S_IFREG) == 0) {
+ if (!S_ISREG(sb.st_mode)) {
return ISC_R_INVALIDFILE;
}
- flags = O_WRONLY | O_TRUNC;
+ flags = O_WRONLY | O_TRUNC | O_NOFOLLOW;
} else if (result == ISC_R_FILENOTFOUND) {
- flags = O_WRONLY | O_CREAT | O_EXCL;
+ flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
} else {
return result;
}
isc_result_t
isc_file_safecreate(const char *filename, FILE **fp);
/*%<
- * Open 'filename' for writing, truncating if necessary. Ensure that
- * if it existed it was a normal file. If creating the file, ensure
+ * Open 'filename' for writing, truncating if necessary. If 'filename'
+ * exists it must be a regular file; symbolic links (and any other
+ * non-regular file types) are rejected. If creating the file, ensure
* that only the owner can read/write it.
*/
unlink(F(SHA));
}
+/* test that isc_file_safecreate refuses to follow symlinks */
+ISC_RUN_TEST_IMPL(isc_file_safecreate_symlink) {
+ char target[] = "safecreate_target.XXXXXX";
+ char link[] = "safecreate_link.XXXXXX";
+ int fd;
+ FILE *fp = NULL;
+ isc_result_t result;
+
+ UNUSED(state);
+
+ fd = mkstemp(target);
+ assert_int_not_equal(fd, -1);
+ close(fd);
+
+ fd = mkstemp(link);
+ assert_int_not_equal(fd, -1);
+ close(fd);
+ unlink(link);
+ assert_return_code(symlink(target, link), 0);
+
+ result = isc_file_safecreate(link, &fp);
+ assert_int_equal(result, ISC_R_INVALIDFILE);
+ assert_null(fp);
+
+ unlink(link);
+ unlink(target);
+}
+
/* test filename templates */
ISC_RUN_TEST_IMPL(isc_file_template) {
isc_result_t result;
ISC_TEST_LIST_START
ISC_TEST_ENTRY(isc_file_sanitize)
+ISC_TEST_ENTRY(isc_file_safecreate_symlink)
ISC_TEST_ENTRY(isc_file_template)
ISC_TEST_LIST_END