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