1/* 2 * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000-2002 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: fsaccess.c,v 1.15 2007/06/19 23:47:19 tbox Exp $ */ 19 20/* 21 * Note that Win32 does not have the concept of files having access 22 * and ownership bits. The FAT File system only has a readonly flag 23 * for everyone and that's all. NTFS uses ACL's which is a totally 24 * different concept of controlling access. 25 * 26 * This code needs to be revisited to set up proper access control for 27 * NTFS file systems. Nothing can be done for FAT file systems. 28 */ 29 30#include <config.h> 31 32#include <aclapi.h> 33 34#include <sys/types.h> 35#include <sys/stat.h> 36#include <io.h> 37#include <errno.h> 38 39#include <isc/file.h> 40#include <isc/stat.h> 41 42#include "errno2result.h" 43 44/* 45 * The OS-independent part of the API is in lib/isc. 46 */ 47#include "../fsaccess.c" 48 49/* Store the user account name locally */ 50static char username[255] = "\0"; 51static DWORD namelen = 0; 52 53/* 54 * In order to set or retrieve access information, we need to obtain 55 * the File System type. These could be UNC-type shares. 56 */ 57 58BOOL 59is_ntfs(const char * file) { 60 61 char drive[255]; 62 char FSType[20]; 63 char tmpbuf[256]; 64 char *machinename; 65 char *sharename; 66 char filename[1024]; 67 68 REQUIRE(filename != NULL); 69 70 if (isc_file_absolutepath(file, filename, 71 sizeof(filename)) != ISC_R_SUCCESS) { 72 return (FALSE); 73 } 74 75 /* 76 * Look for c:\path\... style, c:/path/... or \\computer\shar\path... 77 * the UNC style file specs 78 */ 79 if (isalpha(filename[0]) && filename[1] == ':' && 80 (filename[2] == '\\' || filename[2] == '/')) { 81 strncpy(drive, filename, 3); 82 drive[3] = '\0'; 83 } 84 85 else if ((filename[0] == '\\') && (filename[1] == '\\')) { 86 /* Find the machine and share name and rebuild the UNC */ 87 strcpy(tmpbuf, filename); 88 machinename = strtok(tmpbuf, "\\"); 89 sharename = strtok(NULL, "\\"); 90 strcpy(drive, "\\\\"); 91 strcat(drive, machinename); 92 strcat(drive, "\\"); 93 strcat(drive, sharename); 94 strcat(drive, "\\"); 95 96 } 97 else /* Not determinable */ 98 return (FALSE); 99 100 GetVolumeInformation(drive, NULL, 0, NULL, 0, NULL, FSType, 101 sizeof(FSType)); 102 if(strcmp(FSType,"NTFS") == 0) 103 return (TRUE); 104 else 105 return (FALSE); 106} 107 108/* 109 * If it's not NTFS, we assume that it is FAT and proceed 110 * with almost nothing to do. Only the write flag can be set or 111 * cleared. 112 */ 113isc_result_t 114FAT_fsaccess_set(const char *path, isc_fsaccess_t access) { 115 int mode; 116 isc_fsaccess_t bits; 117 118 /* 119 * Done with checking bad bits. Set mode_t. 120 */ 121 mode = 0; 122 123#define SET_AND_CLEAR1(modebit) \ 124 if ((access & bits) != 0) { \ 125 mode |= modebit; \ 126 access &= ~bits; \ 127 } 128#define SET_AND_CLEAR(user, group, other) \ 129 SET_AND_CLEAR1(user); \ 130 bits <<= STEP; \ 131 SET_AND_CLEAR1(group); \ 132 bits <<= STEP; \ 133 SET_AND_CLEAR1(other); 134 135 bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY; 136 137 SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH); 138 139 bits = ISC_FSACCESS_WRITE | 140 ISC_FSACCESS_CREATECHILD | 141 ISC_FSACCESS_DELETECHILD; 142 143 SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH); 144 145 INSIST(access == 0); 146 147 if (_chmod(path, mode) < 0) 148 return (isc__errno2result(errno)); 149 150 return (ISC_R_SUCCESS); 151} 152 153isc_result_t 154NTFS_Access_Control(const char *filename, const char *user, int access, 155 isc_boolean_t isdir) { 156 SECURITY_DESCRIPTOR sd; 157 BYTE aclBuffer[1024]; 158 PACL pacl=(PACL)&aclBuffer; 159 BYTE sidBuffer[100]; 160 PSID psid=(PSID) &sidBuffer; 161 DWORD sidBufferSize = sizeof(sidBuffer); 162 BYTE adminSidBuffer[100]; 163 PSID padminsid=(PSID) &adminSidBuffer; 164 DWORD adminSidBufferSize = sizeof(adminSidBuffer); 165 BYTE otherSidBuffer[100]; 166 PSID pothersid=(PSID) &otherSidBuffer; 167 DWORD otherSidBufferSize = sizeof(otherSidBuffer); 168 char domainBuffer[100]; 169 DWORD domainBufferSize = sizeof(domainBuffer); 170 SID_NAME_USE snu; 171 int errval; 172 DWORD NTFSbits; 173 int caccess; 174 175 176 /* Initialize an ACL */ 177 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) 178 return (ISC_R_NOPERM); 179 if (!InitializeAcl(pacl, sizeof(aclBuffer), ACL_REVISION)) 180 return (ISC_R_NOPERM); 181 if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer, 182 &domainBufferSize, &snu)) 183 return (ISC_R_NOPERM); 184 domainBufferSize = sizeof(domainBuffer); 185 if (!LookupAccountName(0, "Administrators", padminsid, 186 &adminSidBufferSize, domainBuffer, &domainBufferSize, &snu)) { 187 errval = GetLastError(); 188 return (ISC_R_NOPERM); 189 } 190 domainBufferSize = sizeof(domainBuffer); 191 if (!LookupAccountName(0, "Everyone", pothersid, 192 &otherSidBufferSize, domainBuffer, &domainBufferSize, &snu)) { 193 errval = GetLastError(); 194 return (ISC_R_NOPERM); 195 } 196 197 caccess = access; 198 /* Owner check */ 199 200 NTFSbits = 0; 201 if (caccess & ISC_FSACCESS_READ) 202 NTFSbits |= FILE_GENERIC_READ; 203 if (caccess & ISC_FSACCESS_WRITE) 204 NTFSbits |= FILE_GENERIC_WRITE; 205 if (caccess & ISC_FSACCESS_EXECUTE) 206 NTFSbits |= FILE_GENERIC_EXECUTE; 207 208 /* For directories check the directory-specific bits */ 209 if (isdir == ISC_TRUE) { 210 if (caccess & ISC_FSACCESS_CREATECHILD) 211 NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE; 212 if (caccess & ISC_FSACCESS_DELETECHILD) 213 NTFSbits |= FILE_DELETE_CHILD; 214 if (caccess & ISC_FSACCESS_LISTDIRECTORY) 215 NTFSbits |= FILE_LIST_DIRECTORY; 216 if (caccess & ISC_FSACCESS_ACCESSCHILD) 217 NTFSbits |= FILE_TRAVERSE; 218 } 219 220 if (NTFSbits == (FILE_GENERIC_READ | FILE_GENERIC_WRITE 221 | FILE_GENERIC_EXECUTE)) 222 NTFSbits |= FILE_ALL_ACCESS; 223 /* 224 * Owner and Administrator also get STANDARD_RIGHTS_ALL 225 * to ensure that they have full control 226 */ 227 228 NTFSbits |= STANDARD_RIGHTS_ALL; 229 230 /* Add the ACE to the ACL */ 231 if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, psid)) 232 return (ISC_R_NOPERM); 233 if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, padminsid)) 234 return (ISC_R_NOPERM); 235 236 /* 237 * Group is ignored since we can be in multiple groups or no group 238 * and its meaning is not clear on Win32 239 */ 240 241 caccess = caccess >> STEP; 242 243 /* 244 * Other check. We translate this to be the same as Everyone 245 */ 246 247 caccess = caccess >> STEP; 248 249 NTFSbits = 0; 250 if (caccess & ISC_FSACCESS_READ) 251 NTFSbits |= FILE_GENERIC_READ; 252 if (caccess & ISC_FSACCESS_WRITE) 253 NTFSbits |= FILE_GENERIC_WRITE; 254 if (caccess & ISC_FSACCESS_EXECUTE) 255 NTFSbits |= FILE_GENERIC_EXECUTE; 256 257 /* For directories check the directory-specific bits */ 258 if (isdir == TRUE) { 259 if (caccess & ISC_FSACCESS_CREATECHILD) 260 NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE; 261 if (caccess & ISC_FSACCESS_DELETECHILD) 262 NTFSbits |= FILE_DELETE_CHILD; 263 if (caccess & ISC_FSACCESS_LISTDIRECTORY) 264 NTFSbits |= FILE_LIST_DIRECTORY; 265 if (caccess & ISC_FSACCESS_ACCESSCHILD) 266 NTFSbits |= FILE_TRAVERSE; 267 } 268 /* Add the ACE to the ACL */ 269 if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, 270 pothersid)) 271 return (ISC_R_NOPERM); 272 273 if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) 274 return (ISC_R_NOPERM); 275 if (!SetFileSecurity(filename, DACL_SECURITY_INFORMATION, &sd)) { 276 return (ISC_R_NOPERM); 277 } 278 279 return(ISC_R_SUCCESS); 280} 281 282isc_result_t 283NTFS_fsaccess_set(const char *path, isc_fsaccess_t access, 284 isc_boolean_t isdir){ 285 286 /* 287 * For NTFS we first need to get the name of the account under 288 * which BIND is running 289 */ 290 if (namelen <= 0) { 291 namelen = sizeof(username); 292 if (GetUserName(username, &namelen) == 0) 293 return (ISC_R_FAILURE); 294 } 295 return (NTFS_Access_Control(path, username, access, isdir)); 296} 297 298isc_result_t 299isc_fsaccess_set(const char *path, isc_fsaccess_t access) { 300 struct stat statb; 301 isc_boolean_t is_dir = ISC_FALSE; 302 isc_result_t result; 303 304 if (stat(path, &statb) != 0) 305 return (isc__errno2result(errno)); 306 307 if ((statb.st_mode & S_IFDIR) != 0) 308 is_dir = ISC_TRUE; 309 else if ((statb.st_mode & S_IFREG) == 0) 310 return (ISC_R_INVALIDFILE); 311 312 result = check_bad_bits(access, is_dir); 313 if (result != ISC_R_SUCCESS) 314 return (result); 315 316 /* 317 * Determine if this is a FAT or NTFS disk and 318 * call the appropriate function to set the permissions 319 */ 320 if (is_ntfs(path)) 321 return (NTFS_fsaccess_set(path, access, is_dir)); 322 else 323 return (FAT_fsaccess_set(path, access)); 324} 325 326isc_result_t 327isc_fsaccess_changeowner(const char *filename, const char *user) { 328 SECURITY_DESCRIPTOR psd; 329 BYTE sidBuffer[500]; 330 BYTE groupBuffer[500]; 331 PSID psid=(PSID) &sidBuffer; 332 DWORD sidBufferSize = sizeof(sidBuffer); 333 char domainBuffer[100]; 334 DWORD domainBufferSize = sizeof(domainBuffer); 335 SID_NAME_USE snu; 336 PSID pSidGroup = (PSID) &groupBuffer; 337 DWORD groupBufferSize = sizeof(groupBuffer); 338 339 340 /* 341 * Determine if this is a FAT or NTFS disk and 342 * call the appropriate function to set the ownership 343 * FAT disks do not have ownership attributes so it's 344 * a noop. 345 */ 346 if (is_ntfs(filename) == FALSE) 347 return (ISC_R_SUCCESS); 348 349 if (!InitializeSecurityDescriptor(&psd, SECURITY_DESCRIPTOR_REVISION)) 350 return (ISC_R_NOPERM); 351 352 if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer, 353 &domainBufferSize, &snu)) 354 return (ISC_R_NOPERM); 355 356 /* Make sure administrators can get to it */ 357 domainBufferSize = sizeof(domainBuffer); 358 if (!LookupAccountName(0, "Administrators", pSidGroup, 359 &groupBufferSize, domainBuffer, &domainBufferSize, &snu)) 360 return (ISC_R_NOPERM); 361 362 if (!SetSecurityDescriptorOwner(&psd, psid, FALSE)) 363 return (ISC_R_NOPERM); 364 365 if (!SetSecurityDescriptorGroup(&psd, pSidGroup, FALSE)) 366 return (ISC_R_NOPERM); 367 368 if (!SetFileSecurity(filename, 369 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, 370 &psd)) 371 return (ISC_R_NOPERM); 372 373 return (ISC_R_SUCCESS); 374} 375 376