From 263d232c792914b36af3c7e9b9f894b9af9eafb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Thu, 30 Mar 2023 18:00:17 +0200 Subject: [PATCH] Replace isc_fsaccess API with more secure file creation The isc_fsaccess API was created to hide the implementation details between POSIX and Windows APIs. As we are not supporting the Windows APIs anymore, it's better to drop this API used in the DST part. Moreover, the isc_fsaccess was setting the permissions in an insecure manner - it operated on the filename, and not on the file descriptor which can lead to all kind of attacks if unpriviledged user has read (or even worse write) access to key directory. Replace the code that operates on the private keys with code that uses mkstemp(), fchmod() and atomic rename() at the end, so at no time the private key files have insecure permissions. --- lib/dns/dst_api.c | 166 ++++++++++++++++++++++---------- lib/dns/dst_internal.h | 10 ++ lib/dns/dst_parse.c | 38 ++++---- lib/dns/include/dst/dst.h | 11 ++- lib/isc/Makefile.am | 4 - lib/isc/fsaccess.c | 86 ----------------- lib/isc/fsaccess_common.c | 96 ------------------ lib/isc/fsaccess_common_p.h | 26 ----- lib/isc/include/isc/fsaccess.h | 171 --------------------------------- lib/isc/include/isc/types.h | 1 - 10 files changed, 154 insertions(+), 455 deletions(-) delete mode 100644 lib/isc/fsaccess.c delete mode 100644 lib/isc/fsaccess_common.c delete mode 100644 lib/isc/fsaccess_common_p.h delete mode 100644 lib/isc/include/isc/fsaccess.h diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 5ea70796f6..66c911b025 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -29,18 +29,21 @@ /*! \file */ +#include +#include #include #include #include #include +#include #include #include #include -#include #include #include #include +#include #include #include #include @@ -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) { diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index aa8fda3d7e..40b54dd029 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -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 */ diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c index 6f6d7b2871..375c1bcf8f 100644 --- a/lib/dns/dst_parse.c +++ b/lib/dns/dst_parse.c @@ -30,11 +30,11 @@ #include "dst_parse.h" #include #include +#include #include #include #include -#include #include #include #include @@ -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); } diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index e127aedd19..4f5cf76286 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -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 diff --git a/lib/isc/Makefile.am b/lib/isc/Makefile.am index 9963c8cc60..fb2faba58c 100644 --- a/lib/isc/Makefile.am +++ b/lib/isc/Makefile.am @@ -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 \ diff --git a/lib/isc/fsaccess.c b/lib/isc/fsaccess.c deleted file mode 100644 index 0e5fe650b5..0000000000 --- a/lib/isc/fsaccess.c +++ /dev/null @@ -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 -#include -#include - -#include -#include -#include -#include - -#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); -} diff --git a/lib/isc/fsaccess_common.c b/lib/isc/fsaccess_common.c deleted file mode 100644 index ca497e9758..0000000000 --- a/lib/isc/fsaccess_common.c +++ /dev/null @@ -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 - -#include -#include -#include -#include - -#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); -} diff --git a/lib/isc/fsaccess_common_p.h b/lib/isc/fsaccess_common_p.h deleted file mode 100644 index e4ee01f233..0000000000 --- a/lib/isc/fsaccess_common_p.h +++ /dev/null @@ -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 - * . 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); diff --git a/lib/isc/include/isc/fsaccess.h b/lib/isc/include/isc/fsaccess.h deleted file mode 100644 index e06903037e..0000000000 --- a/lib/isc/include/isc/fsaccess.h +++ /dev/null @@ -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 - -#include -#include - -/* - * 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 diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index 0c0b609bc1..09c5527b33 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -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