4 * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2002 Internet Software Consortium.
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.
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.
20 /* Id: fsaccess.c,v 1.15 2007/06/19 23:47:19 tbox Exp */
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.
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.
36 #include <sys/types.h>
44 #include "errno2result.h"
47 * The OS-independent part of the API is in lib/isc.
49 #include "../fsaccess.c"
51 /* Store the user account name locally */
52 static char username
[255] = "\0";
53 static DWORD namelen
= 0;
56 * In order to set or retrieve access information, we need to obtain
57 * the File System type. These could be UNC-type shares.
61 is_ntfs(const char * file
) {
70 REQUIRE(filename
!= NULL
);
72 if (isc_file_absolutepath(file
, filename
,
73 sizeof(filename
)) != ISC_R_SUCCESS
) {
78 * Look for c:\path\... style, c:/path/... or \\computer\shar\path...
79 * the UNC style file specs
81 if (isalpha(filename
[0]) && filename
[1] == ':' &&
82 (filename
[2] == '\\' || filename
[2] == '/')) {
83 strncpy(drive
, filename
, 3);
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
);
95 strcat(drive
, sharename
);
99 else /* Not determinable */
102 GetVolumeInformation(drive
, NULL
, 0, NULL
, 0, NULL
, FSType
,
104 if(strcmp(FSType
,"NTFS") == 0)
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
116 FAT_fsaccess_set(const char *path
, isc_fsaccess_t access
) {
121 * Done with checking bad bits. Set mode_t.
125 #define SET_AND_CLEAR1(modebit) \
126 if ((access & bits) != 0) { \
130 #define SET_AND_CLEAR(user, group, other) \
131 SET_AND_CLEAR1(user); \
133 SET_AND_CLEAR1(group); \
135 SET_AND_CLEAR1(other);
137 bits
= ISC_FSACCESS_READ
| ISC_FSACCESS_LISTDIRECTORY
;
139 SET_AND_CLEAR(S_IRUSR
, S_IRGRP
, S_IROTH
);
141 bits
= ISC_FSACCESS_WRITE
|
142 ISC_FSACCESS_CREATECHILD
|
143 ISC_FSACCESS_DELETECHILD
;
145 SET_AND_CLEAR(S_IWUSR
, S_IWGRP
, S_IWOTH
);
149 if (_chmod(path
, mode
) < 0)
150 return (isc__errno2result(errno
));
152 return (ISC_R_SUCCESS
);
156 NTFS_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
;
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
);
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
);
192 domainBufferSize
= sizeof(domainBuffer
);
193 if (!LookupAccountName(0, "Everyone", pothersid
,
194 &otherSidBufferSize
, domainBuffer
, &domainBufferSize
, &snu
)) {
195 errval
= GetLastError();
196 return (ISC_R_NOPERM
);
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
;
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
;
222 if (NTFSbits
== (FILE_GENERIC_READ
| FILE_GENERIC_WRITE
223 | FILE_GENERIC_EXECUTE
))
224 NTFSbits
|= FILE_ALL_ACCESS
;
226 * Owner and Administrator also get STANDARD_RIGHTS_ALL
227 * to ensure that they have full control
230 NTFSbits
|= STANDARD_RIGHTS_ALL
;
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
);
239 * Group is ignored since we can be in multiple groups or no group
240 * and its meaning is not clear on Win32
243 caccess
= caccess
>> STEP
;
246 * Other check. We translate this to be the same as Everyone
249 caccess
= caccess
>> STEP
;
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
;
259 /* For directories check the directory-specific bits */
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
;
270 /* Add the ACE to the ACL */
271 if (!AddAccessAllowedAce(pacl
, ACL_REVISION
, NTFSbits
,
273 return (ISC_R_NOPERM
);
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
);
281 return(ISC_R_SUCCESS
);
285 NTFS_fsaccess_set(const char *path
, isc_fsaccess_t access
,
286 isc_boolean_t isdir
){
289 * For NTFS we first need to get the name of the account under
290 * which BIND is running
293 namelen
= sizeof(username
);
294 if (GetUserName(username
, &namelen
) == 0)
295 return (ISC_R_FAILURE
);
297 return (NTFS_Access_Control(path
, username
, access
, isdir
));
301 isc_fsaccess_set(const char *path
, isc_fsaccess_t access
) {
303 isc_boolean_t is_dir
= ISC_FALSE
;
306 if (stat(path
, &statb
) != 0)
307 return (isc__errno2result(errno
));
309 if ((statb
.st_mode
& S_IFDIR
) != 0)
311 else if ((statb
.st_mode
& S_IFREG
) == 0)
312 return (ISC_R_INVALIDFILE
);
314 result
= check_bad_bits(access
, is_dir
);
315 if (result
!= ISC_R_SUCCESS
)
319 * Determine if this is a FAT or NTFS disk and
320 * call the appropriate function to set the permissions
323 return (NTFS_fsaccess_set(path
, access
, is_dir
));
325 return (FAT_fsaccess_set(path
, access
));
329 isc_fsaccess_changeowner(const char *filename
, const char *user
) {
330 SECURITY_DESCRIPTOR psd
;
332 BYTE groupBuffer
[500];
333 PSID psid
=(PSID
) &sidBuffer
;
334 DWORD sidBufferSize
= sizeof(sidBuffer
);
335 char domainBuffer
[100];
336 DWORD domainBufferSize
= sizeof(domainBuffer
);
338 PSID pSidGroup
= (PSID
) &groupBuffer
;
339 DWORD groupBufferSize
= sizeof(groupBuffer
);
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
348 if (is_ntfs(filename
) == FALSE
)
349 return (ISC_R_SUCCESS
);
351 if (!InitializeSecurityDescriptor(&psd
, SECURITY_DESCRIPTOR_REVISION
))
352 return (ISC_R_NOPERM
);
354 if (!LookupAccountName(0, user
, psid
, &sidBufferSize
, domainBuffer
,
355 &domainBufferSize
, &snu
))
356 return (ISC_R_NOPERM
);
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
);
364 if (!SetSecurityDescriptorOwner(&psd
, psid
, FALSE
))
365 return (ISC_R_NOPERM
);
367 if (!SetSecurityDescriptorGroup(&psd
, pSidGroup
, FALSE
))
368 return (ISC_R_NOPERM
);
370 if (!SetFileSecurity(filename
,
371 OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
,
373 return (ISC_R_NOPERM
);
375 return (ISC_R_SUCCESS
);