2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 06:25:31 +00:00

Merge branch '3982-remove-isc_fsaccess-API' into 'main'

Replace isc_fsaccess API with more secure file creation

Closes #3982

See merge request isc-projects/bind9!7766
This commit is contained in:
Ondřej Surý
2023-03-31 12:53:22 +00:00
13 changed files with 180 additions and 456 deletions

View File

@@ -1,3 +1,7 @@
6136. [cleanup] Remove the isc_fsaccess API in favor of creating
temporary file first and atomically replace the key
with non-truncated content. [GL #3982]
6135. [cleanup] Change isc_stdtime_get(&t) to t = isc_stdtime_now().
[GL !7757]

View File

@@ -29,18 +29,21 @@
/*! \file */
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <isc/buffer.h>
#include <isc/dir.h>
#include <isc/file.h>
#include <isc/fsaccess.h>
#include <isc/lex.h>
#include <isc/mem.h>
#include <isc/once.h>
#include <isc/os.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <isc/safe.h>
@@ -893,6 +896,66 @@ out:
return (result);
}
FILE *
dst_key_open(char *tmpname, mode_t mode) {
/* Create public key file. */
int fd = mkstemp(tmpname);
if (fd == -1) {
return (NULL);
}
if (fchmod(fd, mode & ~isc_os_umask()) != 0) {
goto error;
}
FILE *fp = fdopen(fd, "w");
if (fp == NULL) {
goto error;
}
return (fp);
error:
(void)close(fd);
(void)unlink(tmpname);
return (NULL);
}
isc_result_t
dst_key_close(char *tmpname, FILE *fp, char *filename) {
if ((fflush(fp) != 0) || (ferror(fp) != 0)) {
return (dst_key_cleanup(tmpname, fp));
}
if (rename(tmpname, filename) != 0) {
return (dst_key_cleanup(tmpname, fp));
}
if (fclose(fp) != 0) {
/*
* This is in fact error, but we don't care at this point,
* as the file has been already flushed to disk.
*/
}
return (ISC_R_SUCCESS);
}
isc_result_t
dst_key_cleanup(char *tmpname, FILE *fp) {
if (ftruncate(fileno(fp), 0) != 0) {
/*
* ftruncate() result can't be ignored, but we don't care, as
* any sensitive data are protected by the permissions, and
* unlinked in the next step, this is just a good practice.
*/
}
(void)unlink(tmpname);
(void)fclose(fp);
return (DST_R_WRITEERROR);
}
isc_result_t
dst_key_buildinternal(const dns_name_t *name, unsigned int alg,
unsigned int bits, unsigned int flags,
@@ -1368,7 +1431,8 @@ dst_key_buildfilename(const dst_key_t *key, int type, const char *directory,
isc_buffer_t *out) {
REQUIRE(VALID_KEY(key));
REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
type == DST_TYPE_STATE || type == 0);
type == DST_TYPE_STATE || type == DST_TYPE_TEMPLATE ||
type == 0);
return (buildfilename(key->key_name, key->key_id, key->key_alg, type,
directory, out));
@@ -1988,9 +2052,10 @@ static isc_result_t
write_key_state(const dst_key_t *key, int type, const char *directory) {
FILE *fp;
isc_buffer_t fileb;
isc_buffer_t tmpb;
char filename[NAME_MAX];
isc_result_t ret;
isc_fsaccess_t access;
char tmpname[NAME_MAX];
isc_result_t result;
REQUIRE(VALID_KEY(key));
@@ -1998,33 +2063,33 @@ write_key_state(const dst_key_t *key, int type, const char *directory) {
* Make the filename.
*/
isc_buffer_init(&fileb, filename, sizeof(filename));
ret = dst_key_buildfilename(key, DST_TYPE_STATE, directory, &fileb);
if (ret != ISC_R_SUCCESS) {
return (ret);
result = dst_key_buildfilename(key, DST_TYPE_STATE, directory, &fileb);
if (result != ISC_R_SUCCESS) {
return (result);
}
/*
* Create public key file.
*/
if ((fp = fopen(filename, "w")) == NULL) {
isc_buffer_init(&tmpb, tmpname, sizeof(tmpname));
result = dst_key_buildfilename(key, DST_TYPE_TEMPLATE, directory,
&tmpb);
if (result != ISC_R_SUCCESS) {
return (result);
}
mode_t mode = issymmetric(key) ? S_IRUSR | S_IWUSR
: S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
/* Create temporary public key file. */
fp = dst_key_open(tmpname, mode);
if (fp == NULL) {
return (DST_R_WRITEERROR);
}
if (issymmetric(key)) {
access = 0;
isc_fsaccess_add(ISC_FSACCESS_OWNER,
ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
&access);
(void)isc_fsaccess_set(filename, access);
}
/* Write key state */
if ((type & DST_TYPE_KEY) == 0) {
fprintf(fp, "; This is the state of key %d, for ", key->key_id);
ret = dns_name_print(key->key_name, fp);
if (ret != ISC_R_SUCCESS) {
fclose(fp);
return (ret);
result = dns_name_print(key->key_name, fp);
if (result != ISC_R_SUCCESS) {
return (dst_key_cleanup(tmpname, fp));
}
fputc('\n', fp);
@@ -2064,13 +2129,11 @@ write_key_state(const dst_key_t *key, int type, const char *directory) {
printstate(key, DST_KEY_GOAL, "GoalState", fp);
}
fflush(fp);
if (ferror(fp)) {
ret = DST_R_WRITEERROR;
if (result != ISC_R_SUCCESS) {
return (dst_key_cleanup(tmpname, fp));
}
fclose(fp);
return (ret);
return (dst_key_close(tmpname, fp, filename));
}
/*%
@@ -2079,15 +2142,15 @@ write_key_state(const dst_key_t *key, int type, const char *directory) {
static isc_result_t
write_public_key(const dst_key_t *key, int type, const char *directory) {
FILE *fp;
isc_buffer_t keyb, textb, fileb, classb;
isc_buffer_t keyb, tmpb, textb, fileb, classb;
isc_region_t r;
char tmpname[NAME_MAX];
char filename[NAME_MAX];
unsigned char key_array[DST_KEY_MAXSIZE];
char text_array[DST_KEY_MAXTEXTSIZE];
char class_array[10];
isc_result_t ret;
dns_rdata_t rdata = DNS_RDATA_INIT;
isc_fsaccess_t access;
REQUIRE(VALID_KEY(key));
@@ -2122,19 +2185,19 @@ write_public_key(const dst_key_t *key, int type, const char *directory) {
return (ret);
}
/*
* Create public key file.
*/
if ((fp = fopen(filename, "w")) == NULL) {
return (DST_R_WRITEERROR);
isc_buffer_init(&tmpb, tmpname, sizeof(tmpname));
ret = dst_key_buildfilename(key, DST_TYPE_TEMPLATE, directory, &tmpb);
if (ret != ISC_R_SUCCESS) {
return (ret);
}
if (issymmetric(key)) {
access = 0;
isc_fsaccess_add(ISC_FSACCESS_OWNER,
ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
&access);
(void)isc_fsaccess_set(filename, access);
/* Create temporary public key file. */
mode_t mode = issymmetric(key) ? S_IRUSR | S_IWUSR
: S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
fp = dst_key_open(tmpname, mode);
if (fp == NULL) {
return (DST_R_WRITEERROR);
}
/* Write key information in comments */
@@ -2164,6 +2227,9 @@ write_public_key(const dst_key_t *key, int type, const char *directory) {
/* Now print the actual key */
ret = dns_name_print(key->key_name, fp);
if (ret != ISC_R_SUCCESS) {
return (dst_key_cleanup(tmpname, fp));
}
fprintf(fp, " ");
if (key->key_ttl != 0) {
@@ -2172,7 +2238,7 @@ write_public_key(const dst_key_t *key, int type, const char *directory) {
isc_buffer_usedregion(&classb, &r);
if ((unsigned int)fwrite(r.base, 1, r.length, fp) != r.length) {
ret = DST_R_WRITEERROR;
return (dst_key_cleanup(tmpname, fp));
}
if ((type & DST_TYPE_KEY) != 0) {
@@ -2183,17 +2249,16 @@ write_public_key(const dst_key_t *key, int type, const char *directory) {
isc_buffer_usedregion(&textb, &r);
if ((unsigned int)fwrite(r.base, 1, r.length, fp) != r.length) {
ret = DST_R_WRITEERROR;
return (dst_key_cleanup(tmpname, fp));
}
fputc('\n', fp);
fflush(fp);
if (ferror(fp)) {
ret = DST_R_WRITEERROR;
}
fclose(fp);
return (ret);
if (ret != ISC_R_SUCCESS) {
return (dst_key_cleanup(tmpname, fp));
}
return (dst_key_close(tmpname, fp, filename));
}
static isc_result_t
@@ -2203,12 +2268,15 @@ buildfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg,
isc_result_t result;
REQUIRE(out != NULL);
if ((type & DST_TYPE_PRIVATE) != 0) {
suffix = ".private";
} else if ((type & DST_TYPE_PUBLIC) != 0) {
suffix = ".key";
} else if ((type & DST_TYPE_STATE) != 0) {
suffix = ".state";
} else if ((type & DST_TYPE_TEMPLATE) != 0) {
suffix = ".XXXXXX";
}
if (directory != NULL) {

View File

@@ -238,6 +238,16 @@ dst__mem_free(void *ptr);
void *
dst__mem_realloc(void *ptr, size_t size);
/*%
* Secure private file handling
*/
FILE *
dst_key_open(char *tmpname, mode_t mode);
isc_result_t
dst_key_close(char *tmpname, FILE *fp, char *filename);
isc_result_t
dst_key_cleanup(char *tmpname, FILE *fp);
ISC_LANG_ENDDECLS
/*! \file */

View File

@@ -30,11 +30,11 @@
#include "dst_parse.h"
#include <inttypes.h>
#include <stdbool.h>
#include <unistd.h>
#include <isc/base64.h>
#include <isc/dir.h>
#include <isc/file.h>
#include <isc/fsaccess.h>
#include <isc/lex.h>
#include <isc/mem.h>
#include <isc/stdtime.h>
@@ -593,11 +593,13 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
FILE *fp;
isc_result_t result;
char filename[NAME_MAX];
char tmpname[NAME_MAX];
char buffer[MAXFIELDSIZE * 2];
isc_fsaccess_t access;
isc_stdtime_t when;
uint32_t value;
isc_buffer_t b;
isc_buffer_t fileb;
isc_buffer_t tmpb;
isc_region_t r;
int major, minor;
mode_t mode;
@@ -612,14 +614,15 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
return (ret);
}
isc_buffer_init(&b, filename, sizeof(filename));
result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &b);
isc_buffer_init(&fileb, filename, sizeof(filename));
result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory,
&fileb);
if (result != ISC_R_SUCCESS) {
return (result);
}
result = isc_file_mode(filename, &mode);
if (result == ISC_R_SUCCESS && mode != 0600) {
if (result == ISC_R_SUCCESS && mode != (S_IRUSR | S_IWUSR)) {
/* File exists; warn that we are changing its permissions */
int level;
@@ -632,14 +635,17 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
filename, (unsigned int)mode);
}
if ((fp = fopen(filename, "w")) == NULL) {
return (DST_R_WRITEERROR);
isc_buffer_init(&tmpb, tmpname, sizeof(tmpname));
result = dst_key_buildfilename(key, DST_TYPE_TEMPLATE, directory,
&tmpb);
if (result != ISC_R_SUCCESS) {
return (result);
}
access = 0;
isc_fsaccess_add(ISC_FSACCESS_OWNER,
ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, &access);
(void)isc_fsaccess_set(filename, access);
fp = dst_key_open(tmpname, S_IRUSR | S_IWUSR);
if (fp == NULL) {
return (DST_R_WRITEERROR);
}
dst_key_getprivateformat(key, &major, &minor);
if (major == 0 && minor == 0) {
@@ -710,8 +716,7 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
isc_buffer_init(&b, buffer, sizeof(buffer));
result = isc_base64_totext(&r, sizeof(buffer), "", &b);
if (result != ISC_R_SUCCESS) {
fclose(fp);
return (DST_R_INVALIDPRIVATEKEY);
return (dst_key_cleanup(tmpname, fp));
}
isc_buffer_usedregion(&b, &r);
@@ -742,8 +747,7 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
isc_buffer_init(&b, buffer, sizeof(buffer));
result = dns_time32_totext(when, &b);
if (result != ISC_R_SUCCESS) {
fclose(fp);
return (DST_R_INVALIDPRIVATEKEY);
return (dst_key_cleanup(tmpname, fp));
}
isc_buffer_usedregion(&b, &r);
@@ -755,9 +759,7 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
}
}
fflush(fp);
result = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS;
fclose(fp);
result = dst_key_close(tmpname, fp, filename);
return (result);
}

View File

@@ -119,10 +119,11 @@ typedef enum dst_algorithm {
#define DST_KEY_MAXTEXTSIZE 2048
/*% 'Type' for dst_read_key() */
#define DST_TYPE_KEY 0x1000000 /* KEY key */
#define DST_TYPE_PRIVATE 0x2000000
#define DST_TYPE_PUBLIC 0x4000000
#define DST_TYPE_STATE 0x8000000
#define DST_TYPE_KEY 0x1000000 /* KEY key */
#define DST_TYPE_PRIVATE 0x2000000
#define DST_TYPE_PUBLIC 0x4000000
#define DST_TYPE_STATE 0x8000000
#define DST_TYPE_TEMPLATE 0x10000000
/* Key timing metadata definitions */
#define DST_TIME_CREATED 0
@@ -772,11 +773,13 @@ dst_key_buildfilename(const dst_key_t *key, int type, const char *directory,
/*%<
* Generates the filename used by dst to store the specified key.
* If directory is NULL, the current directory is assumed.
* If tmp is not NULL, generates a template for mkstemp().
*
* Requires:
*\li "key" is a valid key
*\li "type" is either DST_TYPE_PUBLIC, DST_TYPE_PRIVATE, or 0 for no suffix.
*\li "out" is a valid buffer
*\li "tmp" is a valid buffer or NULL
*
* Ensures:
*\li the file name will be written to "out", and the used pointer will

View File

@@ -29,7 +29,6 @@ libisc_la_HEADERS = \
include/isc/error.h \
include/isc/file.h \
include/isc/formatcheck.h \
include/isc/fsaccess.h \
include/isc/fuzz.h \
include/isc/getaddresses.h \
include/isc/hash.h \
@@ -130,9 +129,6 @@ libisc_la_SOURCES = \
errno2result.h \
error.c \
file.c \
fsaccess.c \
fsaccess_common.c \
fsaccess_common_p.h \
getaddresses.c \
hash.c \
hashmap.c \

View File

@@ -1,86 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#include <errno.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <isc/fsaccess.h>
#include <isc/result.h>
#include <isc/types.h>
#include <isc/util.h>
#include "../fsaccess_common_p.h"
#include "errno2result.h"
isc_result_t
isc_fsaccess_set(const char *path, isc_fsaccess_t access) {
struct stat statb;
mode_t mode;
bool is_dir = false;
isc_fsaccess_t bits;
isc_result_t result;
if (stat(path, &statb) != 0) {
return (isc__errno2result(errno));
}
if ((statb.st_mode & S_IFDIR) != 0) {
is_dir = true;
} else if ((statb.st_mode & S_IFREG) == 0) {
return (ISC_R_INVALIDFILE);
}
result = isc__fsaccess_check_bad_bits(access, is_dir);
if (result != ISC_R_SUCCESS) {
return (result);
}
/*
* Done with checking bad bits. Set mode_t.
*/
mode = 0;
#define SET_AND_CLEAR1(modebit) \
if ((access & bits) != 0) { \
mode |= modebit; \
access &= ~bits; \
}
#define SET_AND_CLEAR(user, group, other) \
SET_AND_CLEAR1(user); \
bits <<= STEP; \
SET_AND_CLEAR1(group); \
bits <<= STEP; \
SET_AND_CLEAR1(other);
bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY;
SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH);
bits = ISC_FSACCESS_WRITE | ISC_FSACCESS_CREATECHILD |
ISC_FSACCESS_DELETECHILD;
SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH);
bits = ISC_FSACCESS_EXECUTE | ISC_FSACCESS_ACCESSCHILD;
SET_AND_CLEAR(S_IXUSR, S_IXGRP, S_IXOTH);
INSIST(access == 0);
if (chmod(path, mode) < 0) {
return (isc__errno2result(errno));
}
return (ISC_R_SUCCESS);
}

View File

@@ -1,96 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*! \file
* \brief
* This file contains the OS-independent functionality of the API.
*/
#include <stdbool.h>
#include <isc/fsaccess.h>
#include <isc/result.h>
#include <isc/types.h>
#include <isc/util.h>
#include "fsaccess_common_p.h"
void
isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access) {
REQUIRE(trustee <= 0x7);
REQUIRE(permission <= 0xFF);
if ((trustee & ISC_FSACCESS_OWNER) != 0) {
*access |= permission;
}
if ((trustee & ISC_FSACCESS_GROUP) != 0) {
*access |= (permission << GROUP);
}
if ((trustee & ISC_FSACCESS_OTHER) != 0) {
*access |= (permission << OTHER);
}
}
void
isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access) {
REQUIRE(trustee <= 0x7);
REQUIRE(permission <= 0xFF);
if ((trustee & ISC_FSACCESS_OWNER) != 0) {
*access &= ~permission;
}
if ((trustee & ISC_FSACCESS_GROUP) != 0) {
*access &= ~(permission << GROUP);
}
if ((trustee & ISC_FSACCESS_OTHER) != 0) {
*access &= ~(permission << OTHER);
}
}
isc_result_t
isc__fsaccess_check_bad_bits(isc_fsaccess_t access, bool is_dir) {
isc_fsaccess_t bits;
/*
* Check for disallowed user bits.
*/
if (is_dir) {
bits = ISC_FSACCESS_READ | ISC_FSACCESS_WRITE |
ISC_FSACCESS_EXECUTE;
} else {
bits = ISC_FSACCESS_CREATECHILD | ISC_FSACCESS_ACCESSCHILD |
ISC_FSACCESS_DELETECHILD | ISC_FSACCESS_LISTDIRECTORY;
}
/*
* Set group bad bits.
*/
bits |= bits << STEP;
/*
* Set other bad bits.
*/
bits |= bits << STEP;
if ((access & bits) != 0) {
if (is_dir) {
return (ISC_R_NOTFILE);
} else {
return (ISC_R_NOTDIRECTORY);
}
}
return (ISC_R_SUCCESS);
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#pragma once
/*!
* Shorthand. Maybe ISC__FSACCESS_PERMISSIONBITS should not even be in
* <isc/fsaccess.h>. Could check consistency with sizeof(isc_fsaccess_t)
* and the number of bits in each function.
*/
#define STEP (ISC__FSACCESS_PERMISSIONBITS)
#define GROUP (STEP)
#define OTHER (STEP * 2)
isc_result_t
isc__fsaccess_check_bad_bits(isc_fsaccess_t access, bool is_dir);

View File

@@ -1,171 +0,0 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#pragma once
/*! \file isc/fsaccess.h
* \brief The ISC filesystem access module encapsulates the setting of file
* and directory access permissions into one API that is meant to be
* portable to multiple operating systems.
*
* The two primary operating system flavors that are initially accommodated
* are POSIX and Windows NT 4.0 and later. The Windows NT access model is
* considerable more flexible than POSIX's model (as much as I am loathe to
* admit it), and so the ISC API has a higher degree of complexity than would
* be needed to simply address POSIX's needs.
*
* The full breadth of NT's flexibility is not available either, for the
* present time. Much of it is to provide compatibility with what Unix
* programmers are expecting. This is also due to not yet really needing all
* of the functionality of an NT system (or, for that matter, a POSIX system)
* in BIND9, and so resolving how to handle the various incompatibilities has
* been a purely theoretical exercise with no operational experience to
* indicate how flawed the thinking may be.
*
* Some of the more notable dumbing down of NT for this API includes:
*
*\li Each of FILE_READ_DATA and FILE_READ_EA are set with #ISC_FSACCESS_READ.
*
* \li All of FILE_WRITE_DATA, FILE_WRITE_EA and FILE_APPEND_DATA are
* set with #ISC_FSACCESS_WRITE. FILE_WRITE_ATTRIBUTES is not set
* so as to be consistent with Unix, where only the owner of the file
* or the superuser can change the attributes/mode of a file.
*
* \li Both of FILE_ADD_FILE and FILE_ADD_SUBDIRECTORY are set with
* #ISC_FSACCESS_CREATECHILD. This is similar to setting the WRITE
* permission on a Unix directory.
*
* \li SYNCHRONIZE is always set for files and directories, unless someone
* can give me a reason why this is a bad idea.
*
* \li READ_CONTROL and FILE_READ_ATTRIBUTES are always set; this is
* consistent with Unix, where any file or directory can be stat()'d
* unless the directory path disallows complete access somewhere along
* the way.
*
* \li WRITE_DAC is only set for the owner. This too is consistent with
* Unix, and is tighter security than allowing anyone else to be
* able to set permissions.
*
* \li DELETE is only set for the owner. On Unix the ability to delete
* a file is controlled by the directory permissions, but it isn't
* currently clear to me what happens on NT if the directory has
* FILE_DELETE_CHILD set but a file within it does not have DELETE
* set. Always setting DELETE on the file/directory for the owner
* gives maximum flexibility to the owner without exposing the
* file to deletion by others.
*
* \li WRITE_OWNER is never set. This too is consistent with Unix,
* and is also tighter security than allowing anyone to change the
* ownership of the file apart from the superu..ahem, Administrator.
*
* \li Inheritance is set to NO_INHERITANCE.
*
* Unix's dumbing down includes:
*
* \li The sticky bit cannot be set.
*
* \li setuid and setgid cannot be set.
*
* \li Only regular files and directories can be set.
*
* The rest of this comment discusses a few of the incompatibilities
* between the two systems that need more thought if this API is to
* be extended to accommodate them.
*
* The Windows standard access right "DELETE" doesn't have a direct
* equivalent in the Unix world, so it isn't clear what should be done
* with it.
*
* The Unix sticky bit is not supported. While NT does have a concept
* of allowing users to create files in a directory but not delete or
* rename them, it does not have a concept of allowing them to be deleted
* if they are owned by the user trying to delete/rename. While it is
* probable that something could be cobbled together in NT 5 with inheritance,
* it can't really be done in NT 4 as a single property that you could
* set on a directory. You'd need to coordinate something with file creation
* so that every file created had DELETE set for the owner but no one else.
*
* On Unix systems, setting #ISC_FSACCESS_LISTDIRECTORY sets READ.
* ... setting either #ISC_FSACCESS_CREATECHILD or #ISC_FSACCESS_DELETECHILD
* sets WRITE.
* ... setting #ISC_FSACCESS_ACCESSCHILD sets EXECUTE.
*
* On NT systems, setting #ISC_FSACCESS_LISTDIRECTORY sets FILE_LIST_DIRECTORY.
* ... setting #ISC_FSACCESS_CREATECHILD sets FILE_CREATE_CHILD independently.
* ... setting #ISC_FSACCESS_DELETECHILD sets FILE_DELETE_CHILD independently.
* ... setting #ISC_FSACCESS_ACCESSCHILD sets FILE_TRAVERSE.
*
* Unresolved: XXXDCL
* \li What NT access right controls the ability to rename a file?
* \li How does DELETE work? If a directory has FILE_DELETE_CHILD but a
* file or directory within it does not have DELETE, is that file
* or directory deletable?
* \li To implement isc_fsaccess_get(), mapping an existing Unix permission
* mode_t back to an isc_fsaccess_t is pretty trivial; however, mapping
* an NT DACL could be impossible to do in a responsible way.
* \li Similarly, trying to implement the functionality of being able to
* say "add group writability to whatever permissions already exist"
* could be tricky on NT because of the order-of-entry issue combined
* with possibly having one or more matching ACEs already explicitly
* granting or denying access. Because this functionality is
* not yet needed by the ISC, no code has been written to try to
* solve this problem.
*/
#include <inttypes.h>
#include <isc/lang.h>
#include <isc/types.h>
/*
* Trustees.
*/
#define ISC_FSACCESS_OWNER 0x1 /*%< User account. */
#define ISC_FSACCESS_GROUP 0x2 /*%< Primary group owner. */
#define ISC_FSACCESS_OTHER 0x4 /*%< Not the owner or the group owner. */
#define ISC_FSACCESS_WORLD 0x7 /*%< User, Group, Other. */
/*
* Types of permission.
*/
#define ISC_FSACCESS_READ 0x00000001 /*%< File only. */
#define ISC_FSACCESS_WRITE 0x00000002 /*%< File only. */
#define ISC_FSACCESS_EXECUTE 0x00000004 /*%< File only. */
#define ISC_FSACCESS_CREATECHILD 0x00000008 /*%< Dir only. */
#define ISC_FSACCESS_DELETECHILD 0x00000010 /*%< Dir only. */
#define ISC_FSACCESS_LISTDIRECTORY 0x00000020 /*%< Dir only. */
#define ISC_FSACCESS_ACCESSCHILD 0x00000040 /*%< Dir only. */
/*%
* Adding any permission bits beyond 0x200 would mean typedef'ing
* isc_fsaccess_t as uint64_t, and redefining this value to
* reflect the new range of permission types, Probably to 21 for
* maximum flexibility. The number of bits has to accommodate all of
* the permission types, and three full sets of them have to fit
* within an isc_fsaccess_t.
*/
#define ISC__FSACCESS_PERMISSIONBITS 10
ISC_LANG_BEGINDECLS
void
isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access);
void
isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access);
isc_result_t
isc_fsaccess_set(const char *path, isc_fsaccess_t access);
ISC_LANG_ENDDECLS

View File

@@ -14,6 +14,7 @@
#pragma once
/*! \file isc/os.h */
#include <sys/stat.h>
#include <isc/lang.h>
#include <isc/types.h>
@@ -37,9 +38,15 @@ isc_os_ncpus(void);
unsigned long
isc_os_cacheline(void);
/*%<
* Return L1 caheline size of the CPU.
* Return L1 cacheline size of the CPU.
* If L1 cache is greater than ISC_OS_CACHELINE_SIZE, ensure it is used
* instead of constant. Is common on ppc64le architecture.
*/
mode_t
isc_os_umask(void);
/*%<
* Return umask of the current process as initialized at the program start
*/
ISC_LANG_ENDDECLS

View File

@@ -38,7 +38,6 @@ typedef struct isc_constregion isc_constregion_t; /*%< Const region */
typedef struct isc_consttextregion isc_consttextregion_t; /*%< Const Text Region
*/
typedef struct isc_counter isc_counter_t; /*%< Counter */
typedef uint32_t isc_fsaccess_t; /*%< FS Access */
typedef struct isc_hash isc_hash_t; /*%< Hash */
typedef struct isc_httpd isc_httpd_t; /*%< HTTP client */
typedef void(isc_httpdfree_t)(isc_buffer_t *, void *); /*%< HTTP free function

View File

@@ -12,6 +12,7 @@
*/
#include <inttypes.h>
#include <sys/stat.h>
#include <isc/os.h>
#include <isc/types.h>
@@ -21,6 +22,7 @@
static unsigned int isc__os_ncpus = 0;
static unsigned long isc__os_cacheline = ISC_OS_CACHELINE_SIZE;
static mode_t isc__os_umask = 0;
#ifdef HAVE_SYSCONF
@@ -72,6 +74,12 @@ ncpus_initialize(void) {
}
}
static void
umask_initialize(void) {
isc__os_umask = umask(0);
(void)umask(isc__os_umask);
}
unsigned int
isc_os_ncpus(void) {
return (isc__os_ncpus);
@@ -82,8 +90,14 @@ isc_os_cacheline(void) {
return (isc__os_cacheline);
}
mode_t
isc_os_umask(void) {
return (isc__os_umask);
}
void
isc__os_initialize(void) {
umask_initialize();
ncpus_initialize();
#if defined(HAVE_SYSCONF) && defined(_SC_LEVEL1_DCACHE_LINESIZE)
long s = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);