1290001Sglebius/* 2290001Sglebius * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") 3290001Sglebius * Copyright (C) 2000-2002 Internet Software Consortium. 4290001Sglebius * 5290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any 6290001Sglebius * purpose with or without fee is hereby granted, provided that the above 7290001Sglebius * copyright notice and this permission notice appear in all copies. 8290001Sglebius * 9290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11290001Sglebius * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15290001Sglebius * PERFORMANCE OF THIS SOFTWARE. 16290001Sglebius */ 17290001Sglebius 18290001Sglebius/* $Id: fsaccess.c,v 1.15 2007/06/19 23:47:19 tbox Exp $ */ 19290001Sglebius 20290001Sglebius/* 21290001Sglebius * Note that Win32 does not have the concept of files having access 22290001Sglebius * and ownership bits. The FAT File system only has a readonly flag 23290001Sglebius * for everyone and that's all. NTFS uses ACL's which is a totally 24290001Sglebius * different concept of controlling access. 25290001Sglebius * 26290001Sglebius * This code needs to be revisited to set up proper access control for 27290001Sglebius * NTFS file systems. Nothing can be done for FAT file systems. 28290001Sglebius */ 29290001Sglebius 30290001Sglebius#include <config.h> 31290001Sglebius 32290001Sglebius#include <aclapi.h> 33290001Sglebius 34290001Sglebius#include <sys/types.h> 35290001Sglebius#include <sys/stat.h> 36290001Sglebius#include <io.h> 37290001Sglebius#include <errno.h> 38290001Sglebius 39290001Sglebius#include <isc/file.h> 40290001Sglebius#include <isc/stat.h> 41290001Sglebius 42290001Sglebius#include "errno2result.h" 43290001Sglebius 44290001Sglebius/* 45290001Sglebius * The OS-independent part of the API is in lib/isc. 46290001Sglebius */ 47290001Sglebius#include "../fsaccess.c" 48290001Sglebius 49290001Sglebius/* Store the user account name locally */ 50290001Sglebiusstatic char username[255] = "\0"; 51290001Sglebiusstatic DWORD namelen = 0; 52290001Sglebius 53290001Sglebius/* 54290001Sglebius * In order to set or retrieve access information, we need to obtain 55290001Sglebius * the File System type. These could be UNC-type shares. 56290001Sglebius */ 57290001Sglebius 58290001SglebiusBOOL 59290001Sglebiusis_ntfs(const char * file) { 60290001Sglebius 61290001Sglebius char drive[255]; 62290001Sglebius char FSType[20]; 63290001Sglebius char tmpbuf[256]; 64290001Sglebius char *machinename; 65290001Sglebius char *sharename; 66290001Sglebius char filename[1024]; 67290001Sglebius 68290001Sglebius REQUIRE(filename != NULL); 69290001Sglebius 70290001Sglebius if (isc_file_absolutepath(file, filename, 71290001Sglebius sizeof(filename)) != ISC_R_SUCCESS) { 72290001Sglebius return (FALSE); 73290001Sglebius } 74290001Sglebius 75290001Sglebius /* 76290001Sglebius * Look for c:\path\... style, c:/path/... or \\computer\shar\path... 77290001Sglebius * the UNC style file specs 78290001Sglebius */ 79290001Sglebius if (isalpha(filename[0]) && filename[1] == ':' && 80290001Sglebius (filename[2] == '\\' || filename[2] == '/')) { 81290001Sglebius strncpy(drive, filename, 3); 82290001Sglebius drive[3] = '\0'; 83290001Sglebius } 84290001Sglebius 85290001Sglebius else if ((filename[0] == '\\') && (filename[1] == '\\')) { 86290001Sglebius /* Find the machine and share name and rebuild the UNC */ 87290001Sglebius strcpy(tmpbuf, filename); 88290001Sglebius machinename = strtok(tmpbuf, "\\"); 89290001Sglebius sharename = strtok(NULL, "\\"); 90290001Sglebius strcpy(drive, "\\\\"); 91290001Sglebius strcat(drive, machinename); 92290001Sglebius strcat(drive, "\\"); 93290001Sglebius strcat(drive, sharename); 94290001Sglebius strcat(drive, "\\"); 95290001Sglebius 96290001Sglebius } 97290001Sglebius else /* Not determinable */ 98290001Sglebius return (FALSE); 99290001Sglebius 100290001Sglebius GetVolumeInformation(drive, NULL, 0, NULL, 0, NULL, FSType, 101290001Sglebius sizeof(FSType)); 102290001Sglebius if(strcmp(FSType,"NTFS") == 0) 103290001Sglebius return (TRUE); 104290001Sglebius else 105290001Sglebius return (FALSE); 106290001Sglebius} 107290001Sglebius 108290001Sglebius/* 109290001Sglebius * If it's not NTFS, we assume that it is FAT and proceed 110290001Sglebius * with almost nothing to do. Only the write flag can be set or 111290001Sglebius * cleared. 112290001Sglebius */ 113290001Sglebiusisc_result_t 114290001SglebiusFAT_fsaccess_set(const char *path, isc_fsaccess_t access) { 115290001Sglebius int mode; 116290001Sglebius isc_fsaccess_t bits; 117290001Sglebius 118290001Sglebius /* 119290001Sglebius * Done with checking bad bits. Set mode_t. 120290001Sglebius */ 121290001Sglebius mode = 0; 122290001Sglebius 123290001Sglebius#define SET_AND_CLEAR1(modebit) \ 124290001Sglebius if ((access & bits) != 0) { \ 125290001Sglebius mode |= modebit; \ 126290001Sglebius access &= ~bits; \ 127290001Sglebius } 128290001Sglebius#define SET_AND_CLEAR(user, group, other) \ 129290001Sglebius SET_AND_CLEAR1(user); \ 130290001Sglebius bits <<= STEP; \ 131290001Sglebius SET_AND_CLEAR1(group); \ 132290001Sglebius bits <<= STEP; \ 133290001Sglebius SET_AND_CLEAR1(other); 134290001Sglebius 135290001Sglebius bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY; 136290001Sglebius 137290001Sglebius SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH); 138290001Sglebius 139290001Sglebius bits = ISC_FSACCESS_WRITE | 140290001Sglebius ISC_FSACCESS_CREATECHILD | 141290001Sglebius ISC_FSACCESS_DELETECHILD; 142290001Sglebius 143290001Sglebius SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH); 144290001Sglebius 145290001Sglebius INSIST(access == 0); 146290001Sglebius 147290001Sglebius if (_chmod(path, mode) < 0) 148290001Sglebius return (isc__errno2result(errno)); 149290001Sglebius 150290001Sglebius return (ISC_R_SUCCESS); 151290001Sglebius} 152290001Sglebius 153290001Sglebiusisc_result_t 154290001SglebiusNTFS_Access_Control(const char *filename, const char *user, int access, 155290001Sglebius isc_boolean_t isdir) { 156290001Sglebius SECURITY_DESCRIPTOR sd; 157290001Sglebius BYTE aclBuffer[1024]; 158290001Sglebius PACL pacl=(PACL)&aclBuffer; 159290001Sglebius BYTE sidBuffer[100]; 160290001Sglebius PSID psid=(PSID) &sidBuffer; 161290001Sglebius DWORD sidBufferSize = sizeof(sidBuffer); 162290001Sglebius BYTE adminSidBuffer[100]; 163290001Sglebius PSID padminsid=(PSID) &adminSidBuffer; 164290001Sglebius DWORD adminSidBufferSize = sizeof(adminSidBuffer); 165290001Sglebius BYTE otherSidBuffer[100]; 166290001Sglebius PSID pothersid=(PSID) &otherSidBuffer; 167290001Sglebius DWORD otherSidBufferSize = sizeof(otherSidBuffer); 168290001Sglebius char domainBuffer[100]; 169290001Sglebius DWORD domainBufferSize = sizeof(domainBuffer); 170290001Sglebius SID_NAME_USE snu; 171290001Sglebius int errval; 172290001Sglebius DWORD NTFSbits; 173290001Sglebius int caccess; 174290001Sglebius 175290001Sglebius 176290001Sglebius /* Initialize an ACL */ 177290001Sglebius if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) 178290001Sglebius return (ISC_R_NOPERM); 179290001Sglebius if (!InitializeAcl(pacl, sizeof(aclBuffer), ACL_REVISION)) 180290001Sglebius return (ISC_R_NOPERM); 181290001Sglebius if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer, 182290001Sglebius &domainBufferSize, &snu)) 183290001Sglebius return (ISC_R_NOPERM); 184290001Sglebius domainBufferSize = sizeof(domainBuffer); 185290001Sglebius if (!LookupAccountName(0, "Administrators", padminsid, 186290001Sglebius &adminSidBufferSize, domainBuffer, &domainBufferSize, &snu)) { 187290001Sglebius errval = GetLastError(); 188290001Sglebius return (ISC_R_NOPERM); 189290001Sglebius } 190290001Sglebius domainBufferSize = sizeof(domainBuffer); 191290001Sglebius if (!LookupAccountName(0, "Everyone", pothersid, 192290001Sglebius &otherSidBufferSize, domainBuffer, &domainBufferSize, &snu)) { 193290001Sglebius errval = GetLastError(); 194290001Sglebius return (ISC_R_NOPERM); 195290001Sglebius } 196290001Sglebius 197290001Sglebius caccess = access; 198290001Sglebius /* Owner check */ 199290001Sglebius 200290001Sglebius NTFSbits = 0; 201290001Sglebius if (caccess & ISC_FSACCESS_READ) 202290001Sglebius NTFSbits |= FILE_GENERIC_READ; 203290001Sglebius if (caccess & ISC_FSACCESS_WRITE) 204290001Sglebius NTFSbits |= FILE_GENERIC_WRITE; 205290001Sglebius if (caccess & ISC_FSACCESS_EXECUTE) 206290001Sglebius NTFSbits |= FILE_GENERIC_EXECUTE; 207290001Sglebius 208290001Sglebius /* For directories check the directory-specific bits */ 209290001Sglebius if (isdir == ISC_TRUE) { 210290001Sglebius if (caccess & ISC_FSACCESS_CREATECHILD) 211290001Sglebius NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE; 212290001Sglebius if (caccess & ISC_FSACCESS_DELETECHILD) 213290001Sglebius NTFSbits |= FILE_DELETE_CHILD; 214290001Sglebius if (caccess & ISC_FSACCESS_LISTDIRECTORY) 215290001Sglebius NTFSbits |= FILE_LIST_DIRECTORY; 216290001Sglebius if (caccess & ISC_FSACCESS_ACCESSCHILD) 217290001Sglebius NTFSbits |= FILE_TRAVERSE; 218290001Sglebius } 219290001Sglebius 220290001Sglebius if (NTFSbits == (FILE_GENERIC_READ | FILE_GENERIC_WRITE 221290001Sglebius | FILE_GENERIC_EXECUTE)) 222290001Sglebius NTFSbits |= FILE_ALL_ACCESS; 223290001Sglebius /* 224290001Sglebius * Owner and Administrator also get STANDARD_RIGHTS_ALL 225290001Sglebius * to ensure that they have full control 226290001Sglebius */ 227290001Sglebius 228290001Sglebius NTFSbits |= STANDARD_RIGHTS_ALL; 229290001Sglebius 230290001Sglebius /* Add the ACE to the ACL */ 231290001Sglebius if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, psid)) 232290001Sglebius return (ISC_R_NOPERM); 233290001Sglebius if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, padminsid)) 234290001Sglebius return (ISC_R_NOPERM); 235290001Sglebius 236290001Sglebius /* 237290001Sglebius * Group is ignored since we can be in multiple groups or no group 238290001Sglebius * and its meaning is not clear on Win32 239290001Sglebius */ 240290001Sglebius 241290001Sglebius caccess = caccess >> STEP; 242290001Sglebius 243290001Sglebius /* 244290001Sglebius * Other check. We translate this to be the same as Everyone 245290001Sglebius */ 246290001Sglebius 247290001Sglebius caccess = caccess >> STEP; 248290001Sglebius 249290001Sglebius NTFSbits = 0; 250290001Sglebius if (caccess & ISC_FSACCESS_READ) 251290001Sglebius NTFSbits |= FILE_GENERIC_READ; 252290001Sglebius if (caccess & ISC_FSACCESS_WRITE) 253290001Sglebius NTFSbits |= FILE_GENERIC_WRITE; 254290001Sglebius if (caccess & ISC_FSACCESS_EXECUTE) 255290001Sglebius NTFSbits |= FILE_GENERIC_EXECUTE; 256290001Sglebius 257290001Sglebius /* For directories check the directory-specific bits */ 258290001Sglebius if (isdir == TRUE) { 259290001Sglebius if (caccess & ISC_FSACCESS_CREATECHILD) 260290001Sglebius NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE; 261290001Sglebius if (caccess & ISC_FSACCESS_DELETECHILD) 262290001Sglebius NTFSbits |= FILE_DELETE_CHILD; 263290001Sglebius if (caccess & ISC_FSACCESS_LISTDIRECTORY) 264290001Sglebius NTFSbits |= FILE_LIST_DIRECTORY; 265290001Sglebius if (caccess & ISC_FSACCESS_ACCESSCHILD) 266290001Sglebius NTFSbits |= FILE_TRAVERSE; 267290001Sglebius } 268290001Sglebius /* Add the ACE to the ACL */ 269290001Sglebius if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, 270290001Sglebius pothersid)) 271290001Sglebius return (ISC_R_NOPERM); 272290001Sglebius 273290001Sglebius if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) 274290001Sglebius return (ISC_R_NOPERM); 275290001Sglebius if (!SetFileSecurity(filename, DACL_SECURITY_INFORMATION, &sd)) { 276290001Sglebius return (ISC_R_NOPERM); 277290001Sglebius } 278290001Sglebius 279290001Sglebius return(ISC_R_SUCCESS); 280290001Sglebius} 281290001Sglebius 282290001Sglebiusisc_result_t 283290001SglebiusNTFS_fsaccess_set(const char *path, isc_fsaccess_t access, 284290001Sglebius isc_boolean_t isdir){ 285290001Sglebius 286290001Sglebius /* 287290001Sglebius * For NTFS we first need to get the name of the account under 288290001Sglebius * which BIND is running 289290001Sglebius */ 290290001Sglebius if (namelen <= 0) { 291290001Sglebius namelen = sizeof(username); 292290001Sglebius if (GetUserName(username, &namelen) == 0) 293290001Sglebius return (ISC_R_FAILURE); 294290001Sglebius } 295290001Sglebius return (NTFS_Access_Control(path, username, access, isdir)); 296290001Sglebius} 297290001Sglebius 298290001Sglebiusisc_result_t 299290001Sglebiusisc_fsaccess_set(const char *path, isc_fsaccess_t access) { 300290001Sglebius struct stat statb; 301290001Sglebius isc_boolean_t is_dir = ISC_FALSE; 302290001Sglebius isc_result_t result; 303290001Sglebius 304290001Sglebius if (stat(path, &statb) != 0) 305290001Sglebius return (isc__errno2result(errno)); 306290001Sglebius 307290001Sglebius if ((statb.st_mode & S_IFDIR) != 0) 308290001Sglebius is_dir = ISC_TRUE; 309290001Sglebius else if ((statb.st_mode & S_IFREG) == 0) 310290001Sglebius return (ISC_R_INVALIDFILE); 311290001Sglebius 312290001Sglebius result = check_bad_bits(access, is_dir); 313290001Sglebius if (result != ISC_R_SUCCESS) 314290001Sglebius return (result); 315290001Sglebius 316290001Sglebius /* 317290001Sglebius * Determine if this is a FAT or NTFS disk and 318290001Sglebius * call the appropriate function to set the permissions 319290001Sglebius */ 320290001Sglebius if (is_ntfs(path)) 321290001Sglebius return (NTFS_fsaccess_set(path, access, is_dir)); 322290001Sglebius else 323290001Sglebius return (FAT_fsaccess_set(path, access)); 324290001Sglebius} 325290001Sglebius 326290001Sglebiusisc_result_t 327290001Sglebiusisc_fsaccess_changeowner(const char *filename, const char *user) { 328290001Sglebius SECURITY_DESCRIPTOR psd; 329290001Sglebius BYTE sidBuffer[500]; 330290001Sglebius BYTE groupBuffer[500]; 331290001Sglebius PSID psid=(PSID) &sidBuffer; 332290001Sglebius DWORD sidBufferSize = sizeof(sidBuffer); 333290001Sglebius char domainBuffer[100]; 334290001Sglebius DWORD domainBufferSize = sizeof(domainBuffer); 335290001Sglebius SID_NAME_USE snu; 336290001Sglebius PSID pSidGroup = (PSID) &groupBuffer; 337290001Sglebius DWORD groupBufferSize = sizeof(groupBuffer); 338290001Sglebius 339290001Sglebius 340290001Sglebius /* 341290001Sglebius * Determine if this is a FAT or NTFS disk and 342290001Sglebius * call the appropriate function to set the ownership 343290001Sglebius * FAT disks do not have ownership attributes so it's 344290001Sglebius * a noop. 345290001Sglebius */ 346290001Sglebius if (is_ntfs(filename) == FALSE) 347290001Sglebius return (ISC_R_SUCCESS); 348290001Sglebius 349290001Sglebius if (!InitializeSecurityDescriptor(&psd, SECURITY_DESCRIPTOR_REVISION)) 350290001Sglebius return (ISC_R_NOPERM); 351290001Sglebius 352290001Sglebius if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer, 353290001Sglebius &domainBufferSize, &snu)) 354290001Sglebius return (ISC_R_NOPERM); 355290001Sglebius 356290001Sglebius /* Make sure administrators can get to it */ 357290001Sglebius domainBufferSize = sizeof(domainBuffer); 358290001Sglebius if (!LookupAccountName(0, "Administrators", pSidGroup, 359290001Sglebius &groupBufferSize, domainBuffer, &domainBufferSize, &snu)) 360290001Sglebius return (ISC_R_NOPERM); 361290001Sglebius 362290001Sglebius if (!SetSecurityDescriptorOwner(&psd, psid, FALSE)) 363290001Sglebius return (ISC_R_NOPERM); 364290001Sglebius 365290001Sglebius if (!SetSecurityDescriptorGroup(&psd, pSidGroup, FALSE)) 366290001Sglebius return (ISC_R_NOPERM); 367290001Sglebius 368290001Sglebius if (!SetFileSecurity(filename, 369290001Sglebius OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, 370290001Sglebius &psd)) 371290001Sglebius return (ISC_R_NOPERM); 372290001Sglebius 373290001Sglebius return (ISC_R_SUCCESS); 374290001Sglebius} 375290001Sglebius 376