1 /* $NetBSD: fsaccess.c,v 1.5 2014/12/10 04:38:01 christos Exp $ */
4 * Copyright (C) 2004, 2007, 2013 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
);
177 /* Initialize an ACL */
178 if (!InitializeSecurityDescriptor(&sd
, SECURITY_DESCRIPTOR_REVISION
))
179 return (ISC_R_NOPERM
);
180 if (!InitializeAcl(pacl
, sizeof(aclBuffer
), ACL_REVISION
))
181 return (ISC_R_NOPERM
);
182 if (!LookupAccountName(0, user
, psid
, &sidBufferSize
, domainBuffer
,
183 &domainBufferSize
, &snu
))
184 return (ISC_R_NOPERM
);
185 domainBufferSize
= sizeof(domainBuffer
);
186 if (!LookupAccountName(0, "Administrators", padminsid
,
187 &adminSidBufferSize
, domainBuffer
, &domainBufferSize
, &snu
)) {
188 (void)GetLastError();
189 return (ISC_R_NOPERM
);
191 domainBufferSize
= sizeof(domainBuffer
);
192 if (!LookupAccountName(0, "Everyone", pothersid
,
193 &otherSidBufferSize
, domainBuffer
, &domainBufferSize
, &snu
)) {
194 (void)GetLastError();
195 return (ISC_R_NOPERM
);
202 if (caccess
& ISC_FSACCESS_READ
)
203 NTFSbits
|= FILE_GENERIC_READ
;
204 if (caccess
& ISC_FSACCESS_WRITE
)
205 NTFSbits
|= FILE_GENERIC_WRITE
;
206 if (caccess
& ISC_FSACCESS_EXECUTE
)
207 NTFSbits
|= FILE_GENERIC_EXECUTE
;
209 /* For directories check the directory-specific bits */
210 if (isdir
== ISC_TRUE
) {
211 if (caccess
& ISC_FSACCESS_CREATECHILD
)
212 NTFSbits
|= FILE_ADD_SUBDIRECTORY
| FILE_ADD_FILE
;
213 if (caccess
& ISC_FSACCESS_DELETECHILD
)
214 NTFSbits
|= FILE_DELETE_CHILD
;
215 if (caccess
& ISC_FSACCESS_LISTDIRECTORY
)
216 NTFSbits
|= FILE_LIST_DIRECTORY
;
217 if (caccess
& ISC_FSACCESS_ACCESSCHILD
)
218 NTFSbits
|= FILE_TRAVERSE
;
221 if (NTFSbits
== (FILE_GENERIC_READ
| FILE_GENERIC_WRITE
222 | FILE_GENERIC_EXECUTE
))
223 NTFSbits
|= FILE_ALL_ACCESS
;
225 * Owner and Administrator also get STANDARD_RIGHTS_ALL
226 * to ensure that they have full control
229 NTFSbits
|= STANDARD_RIGHTS_ALL
;
231 /* Add the ACE to the ACL */
232 if (!AddAccessAllowedAce(pacl
, ACL_REVISION
, NTFSbits
, psid
))
233 return (ISC_R_NOPERM
);
234 if (!AddAccessAllowedAce(pacl
, ACL_REVISION
, NTFSbits
, padminsid
))
235 return (ISC_R_NOPERM
);
238 * Group is ignored since we can be in multiple groups or no group
239 * and its meaning is not clear on Win32
242 caccess
= caccess
>> STEP
;
245 * Other check. We translate this to be the same as Everyone
248 caccess
= caccess
>> STEP
;
251 if (caccess
& ISC_FSACCESS_READ
)
252 NTFSbits
|= FILE_GENERIC_READ
;
253 if (caccess
& ISC_FSACCESS_WRITE
)
254 NTFSbits
|= FILE_GENERIC_WRITE
;
255 if (caccess
& ISC_FSACCESS_EXECUTE
)
256 NTFSbits
|= FILE_GENERIC_EXECUTE
;
258 /* For directories check the directory-specific bits */
260 if (caccess
& ISC_FSACCESS_CREATECHILD
)
261 NTFSbits
|= FILE_ADD_SUBDIRECTORY
| FILE_ADD_FILE
;
262 if (caccess
& ISC_FSACCESS_DELETECHILD
)
263 NTFSbits
|= FILE_DELETE_CHILD
;
264 if (caccess
& ISC_FSACCESS_LISTDIRECTORY
)
265 NTFSbits
|= FILE_LIST_DIRECTORY
;
266 if (caccess
& ISC_FSACCESS_ACCESSCHILD
)
267 NTFSbits
|= FILE_TRAVERSE
;
269 /* Add the ACE to the ACL */
270 if (!AddAccessAllowedAce(pacl
, ACL_REVISION
, NTFSbits
,
272 return (ISC_R_NOPERM
);
274 if (!SetSecurityDescriptorDacl(&sd
, TRUE
, pacl
, FALSE
))
275 return (ISC_R_NOPERM
);
276 if (!SetFileSecurity(filename
, DACL_SECURITY_INFORMATION
, &sd
)) {
277 return (ISC_R_NOPERM
);
280 return(ISC_R_SUCCESS
);
284 NTFS_fsaccess_set(const char *path
, isc_fsaccess_t access
,
285 isc_boolean_t isdir
){
288 * For NTFS we first need to get the name of the account under
289 * which BIND is running
292 namelen
= sizeof(username
);
293 if (GetUserName(username
, &namelen
) == 0)
294 return (ISC_R_FAILURE
);
296 return (NTFS_Access_Control(path
, username
, access
, isdir
));
300 isc_fsaccess_set(const char *path
, isc_fsaccess_t access
) {
302 isc_boolean_t is_dir
= ISC_FALSE
;
305 if (stat(path
, &statb
) != 0)
306 return (isc__errno2result(errno
));
308 if ((statb
.st_mode
& S_IFDIR
) != 0)
310 else if ((statb
.st_mode
& S_IFREG
) == 0)
311 return (ISC_R_INVALIDFILE
);
313 result
= check_bad_bits(access
, is_dir
);
314 if (result
!= ISC_R_SUCCESS
)
318 * Determine if this is a FAT or NTFS disk and
319 * call the appropriate function to set the permissions
322 return (NTFS_fsaccess_set(path
, access
, is_dir
));
324 return (FAT_fsaccess_set(path
, access
));
328 isc_fsaccess_changeowner(const char *filename
, const char *user
) {
329 SECURITY_DESCRIPTOR psd
;
331 BYTE groupBuffer
[500];
332 PSID psid
=(PSID
) &sidBuffer
;
333 DWORD sidBufferSize
= sizeof(sidBuffer
);
334 char domainBuffer
[100];
335 DWORD domainBufferSize
= sizeof(domainBuffer
);
337 PSID pSidGroup
= (PSID
) &groupBuffer
;
338 DWORD groupBufferSize
= sizeof(groupBuffer
);
342 * Determine if this is a FAT or NTFS disk and
343 * call the appropriate function to set the ownership
344 * FAT disks do not have ownership attributes so it's
347 if (is_ntfs(filename
) == FALSE
)
348 return (ISC_R_SUCCESS
);
350 if (!InitializeSecurityDescriptor(&psd
, SECURITY_DESCRIPTOR_REVISION
))
351 return (ISC_R_NOPERM
);
353 if (!LookupAccountName(0, user
, psid
, &sidBufferSize
, domainBuffer
,
354 &domainBufferSize
, &snu
))
355 return (ISC_R_NOPERM
);
357 /* Make sure administrators can get to it */
358 domainBufferSize
= sizeof(domainBuffer
);
359 if (!LookupAccountName(0, "Administrators", pSidGroup
,
360 &groupBufferSize
, domainBuffer
, &domainBufferSize
, &snu
))
361 return (ISC_R_NOPERM
);
363 if (!SetSecurityDescriptorOwner(&psd
, psid
, FALSE
))
364 return (ISC_R_NOPERM
);
366 if (!SetSecurityDescriptorGroup(&psd
, pSidGroup
, FALSE
))
367 return (ISC_R_NOPERM
);
369 if (!SetFileSecurity(filename
,
370 OWNER_SECURITY_INFORMATION
| GROUP_SECURITY_INFORMATION
,
372 return (ISC_R_NOPERM
);
374 return (ISC_R_SUCCESS
);