From 5c4e92b9736b36b760109bf57487d3bb5eee84c5 Mon Sep 17 00:00:00 2001 From: Danny Mayer Date: Tue, 13 Nov 2001 05:07:57 +0000 Subject: [PATCH] Added support for NTFS disks --- lib/isc/win32/fsaccess.c | 267 +++++++++++++++++++++++++++++++++++---- 1 file changed, 240 insertions(+), 27 deletions(-) diff --git a/lib/isc/win32/fsaccess.c b/lib/isc/win32/fsaccess.c index ea8755eedb..5aa47dc221 100644 --- a/lib/isc/win32/fsaccess.c +++ b/lib/isc/win32/fsaccess.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: fsaccess.c,v 1.9 2001/07/09 21:06:07 gson Exp $ */ +/* $Id: fsaccess.c,v 1.10 2001/11/13 05:07:57 mayer Exp $ */ /* * Note that Win32 does not have the concept of files having access @@ -34,6 +34,7 @@ #include #include +#include #include #include "errno2result.h" @@ -43,25 +44,74 @@ */ #include "../fsaccess.c" +/* Store the user account name locally */ +static char username[255] = "\0"; +static DWORD namelen = 0; + +/* + * In order to set or retrieve access information, we need to obtain + * the File System type. These could be UNC-type shares. + */ + +BOOL +is_ntfs(const char * file) { + + char drive[255]; + char FSType[20]; + char tmpbuf[256]; + char *machinename; + char *sharename; + char filename[1024]; + + REQUIRE(filename != NULL); + + if (isc_file_absolutepath(file, filename, + sizeof(filename)) != ISC_R_SUCCESS) { + return (FALSE); + } + + /* + * Look for c:\path\... style, c:/path/... or \\computer\shar\path... + * the UNC style file specs + */ + if (isalpha(filename[0]) && filename[1] == ':' && + (filename[2] == '\\' || filename[2] == '/')) { + strncpy(drive, filename, 3); + drive[3] = '\0'; + } + + else if ((filename[0] == '\\') && (filename[1] == '\\')) { + /* Find the machine and share name and rebuild the UNC */ + strcpy(tmpbuf, filename); + machinename = strtok(tmpbuf, "\\"); + sharename = strtok(NULL, "\\"); + strcpy(drive, "\\\\"); + strcat(drive, machinename); + strcat(drive, "\\"); + strcat(drive, sharename); + strcat(drive, "\\"); + + } + else /* Not determinable */ + return (FALSE); + + GetVolumeInformation(drive, NULL, 0, NULL, 0, NULL, FSType, + sizeof(FSType)); + if(strcmp(FSType,"NTFS") == 0) + return (TRUE); + else + return (FALSE); +} + +/* + * If it's not NTFS, we assume that it is FAT and proceed + * with almost nothing to do. Only the write flag can be set or + * cleared. + */ isc_result_t -isc_fsaccess_set(const char *path, isc_fsaccess_t access) { - struct stat statb; +FAT_fsaccess_set(const char *path, isc_fsaccess_t access) { int mode; - isc_boolean_t is_dir = ISC_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 = ISC_TRUE; - else if ((statb.st_mode & S_IFREG) == 0) - return (ISC_R_INVALIDFILE); - - result = check_bad_bits(access, is_dir); - if (result != ISC_R_SUCCESS) - return (result); /* * Done with checking bad bits. Set mode_t. @@ -90,16 +140,6 @@ isc_fsaccess_set(const char *path, isc_fsaccess_t access) { SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH); -#ifdef notyet - /* - * WIN32 doesn't have the concept of execute bits. We leave this here - * for when we review this module. - */ - bits = ISC_FSACCESS_EXECUTE | - ISC_FSACCESS_ACCESSCHILD; - - SET_AND_CLEAR(S_IXUSR, S_IXGRP, S_IXOTH); -#endif INSIST(access == 0); if (_chmod(path, mode) < 0) @@ -107,3 +147,176 @@ isc_fsaccess_set(const char *path, isc_fsaccess_t access) { return (ISC_R_SUCCESS); } + +isc_result_t +NTFS_Access_Control(const char *filename, const char *user, int access, + isc_boolean_t isdir) { + SECURITY_DESCRIPTOR sd; + BYTE aclBuffer[1024]; + PACL pacl=(PACL)&aclBuffer; + BYTE sidBuffer[100]; + PSID psid=(PSID) &sidBuffer; + DWORD sidBufferSize = sizeof(sidBuffer); + BYTE adminSidBuffer[100]; + PSID padminsid=(PSID) &adminSidBuffer; + DWORD adminSidBufferSize = sizeof(adminSidBuffer); + BYTE otherSidBuffer[100]; + PSID pothersid=(PSID) &otherSidBuffer; + DWORD otherSidBufferSize = sizeof(otherSidBuffer); + char domainBuffer[100]; + DWORD domainBufferSize = sizeof(domainBuffer); + SID_NAME_USE snu; + int errval; + DWORD NTFSbits; + int caccess; + + + /* Initialize an ACL */ + if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) + return (ISC_R_NOPERM); + if (!InitializeAcl(pacl, sizeof(aclBuffer), ACL_REVISION)) + return (ISC_R_NOPERM); + if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer, + &domainBufferSize, &snu)) + return (ISC_R_NOPERM); + domainBufferSize = sizeof(domainBuffer); + if (!LookupAccountName(0, "Administrators", padminsid, + &adminSidBufferSize, domainBuffer, &domainBufferSize, &snu)) { + errval = GetLastError(); + return (ISC_R_NOPERM); + } + domainBufferSize = sizeof(domainBuffer); + if (!LookupAccountName(0, "Everyone", pothersid, + &otherSidBufferSize, domainBuffer, &domainBufferSize, &snu)) { + errval = GetLastError(); + return (ISC_R_NOPERM); + } + + caccess = access; + /* Owner check */ + + NTFSbits = 0; + if (caccess & ISC_FSACCESS_READ) + NTFSbits |= FILE_GENERIC_READ; + if (caccess & ISC_FSACCESS_WRITE) + NTFSbits |= FILE_GENERIC_WRITE; + if (caccess & ISC_FSACCESS_EXECUTE) + NTFSbits |= FILE_GENERIC_EXECUTE; + + /* For directories check the directory-specific bits */ + if(isdir == ISC_TRUE) { + if (caccess & ISC_FSACCESS_CREATECHILD) + NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE; + if (caccess & ISC_FSACCESS_DELETECHILD) + NTFSbits |= FILE_DELETE_CHILD; + if (caccess & ISC_FSACCESS_LISTDIRECTORY) + NTFSbits |= FILE_LIST_DIRECTORY; + if (caccess & ISC_FSACCESS_ACCESSCHILD) + NTFSbits |= FILE_TRAVERSE; + } + + if(NTFSbits == (FILE_GENERIC_READ | FILE_GENERIC_WRITE + | FILE_GENERIC_EXECUTE)) + NTFSbits |= FILE_ALL_ACCESS; + /* + * Owner and Administrator also get STANDARD_RIGHTS_ALL + * to ensure that they have full control + */ + + NTFSbits |= STANDARD_RIGHTS_ALL; + + /* Add the ACE to the ACL */ + if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, psid)) + return (ISC_R_NOPERM); + if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, padminsid)) + return (ISC_R_NOPERM); + + /* + * Group is ignored since we can be in multiple groups or no group + * and its meaning is not clear on Win32 + */ + + caccess = caccess >> STEP; + + /* + * Other check. We translate this to be the same as Everyone + */ + + caccess = caccess >> STEP; + + NTFSbits = 0; + if (caccess & ISC_FSACCESS_READ) + NTFSbits |= FILE_GENERIC_READ; + if (caccess & ISC_FSACCESS_WRITE) + NTFSbits |= FILE_GENERIC_WRITE; + if (caccess & ISC_FSACCESS_EXECUTE) + NTFSbits |= FILE_GENERIC_EXECUTE; + + /* For directories check the directory-specific bits */ + if(isdir == TRUE) { + if (caccess & ISC_FSACCESS_CREATECHILD) + NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE; + if (caccess & ISC_FSACCESS_DELETECHILD) + NTFSbits |= FILE_DELETE_CHILD; + if (caccess & ISC_FSACCESS_LISTDIRECTORY) + NTFSbits |= FILE_LIST_DIRECTORY; + if (caccess & ISC_FSACCESS_ACCESSCHILD) + NTFSbits |= FILE_TRAVERSE; + } + /* Add the ACE to the ACL */ + if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, + pothersid)) + return (ISC_R_NOPERM); + + if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) + return (ISC_R_NOPERM); + if(!SetFileSecurity(filename, DACL_SECURITY_INFORMATION, &sd)) { + return (ISC_R_NOPERM); + } + + return(ISC_R_SUCCESS); +} + +isc_result_t +NTFS_fsaccess_set(const char *path, isc_fsaccess_t access, + isc_boolean_t isdir){ + + /* + * For NTFS we first need to get the name of the account under + * which BIND is running + */ + if (namelen <= 0) { + namelen = sizeof(username); + if (GetUserName(username, &namelen) == 0) + return (ISC_R_FAILURE); + } + return (NTFS_Access_Control(path, username, access, isdir)); +} + +isc_result_t +isc_fsaccess_set(const char *path, isc_fsaccess_t access) { + struct stat statb; + isc_boolean_t is_dir = ISC_FALSE; + isc_result_t result; + + if (stat(path, &statb) != 0) + return (isc__errno2result(errno)); + + if ((statb.st_mode & S_IFDIR) != 0) + is_dir = ISC_TRUE; + else if ((statb.st_mode & S_IFREG) == 0) + return (ISC_R_INVALIDFILE); + + result = check_bad_bits(access, is_dir); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Determine if this is a FAT or NTFS disk and + * call the appropriate function to set the permissions + */ + if (is_ntfs(path)) + return (NTFS_fsaccess_set(path, access, is_dir)); + else + return (FAT_fsaccess_set(path, access)); +}