1 /* $NetBSD: fsaccess.c,v 1.5 2014/12/10 04:38:01 christos Exp $ */
2
3 /*
4 * Copyright (C) 2004, 2007, 2013 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 */
52 static char username[255] = "\0";
53 static 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
60 BOOL
is_ntfs(const char * file)61 is_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 */
115 isc_result_t
FAT_fsaccess_set(const char * path,isc_fsaccess_t access)116 FAT_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
155 isc_result_t
NTFS_Access_Control(const char * filename,const char * user,int access,isc_boolean_t isdir)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;
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 DWORD NTFSbits;
174 int caccess;
175
176
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);
190 }
191 domainBufferSize = sizeof(domainBuffer);
192 if (!LookupAccountName(0, "Everyone", pothersid,
193 &otherSidBufferSize, domainBuffer, &domainBufferSize, &snu)) {
194 (void)GetLastError();
195 return (ISC_R_NOPERM);
196 }
197
198 caccess = access;
199 /* Owner check */
200
201 NTFSbits = 0;
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;
208
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;
219 }
220
221 if (NTFSbits == (FILE_GENERIC_READ | FILE_GENERIC_WRITE
222 | FILE_GENERIC_EXECUTE))
223 NTFSbits |= FILE_ALL_ACCESS;
224 /*
225 * Owner and Administrator also get STANDARD_RIGHTS_ALL
226 * to ensure that they have full control
227 */
228
229 NTFSbits |= STANDARD_RIGHTS_ALL;
230
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);
236
237 /*
238 * Group is ignored since we can be in multiple groups or no group
239 * and its meaning is not clear on Win32
240 */
241
242 caccess = caccess >> STEP;
243
244 /*
245 * Other check. We translate this to be the same as Everyone
246 */
247
248 caccess = caccess >> STEP;
249
250 NTFSbits = 0;
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;
257
258 /* For directories check the directory-specific bits */
259 if (isdir == TRUE) {
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;
268 }
269 /* Add the ACE to the ACL */
270 if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits,
271 pothersid))
272 return (ISC_R_NOPERM);
273
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);
278 }
279
280 return(ISC_R_SUCCESS);
281 }
282
283 isc_result_t
NTFS_fsaccess_set(const char * path,isc_fsaccess_t access,isc_boolean_t isdir)284 NTFS_fsaccess_set(const char *path, isc_fsaccess_t access,
285 isc_boolean_t isdir){
286
287 /*
288 * For NTFS we first need to get the name of the account under
289 * which BIND is running
290 */
291 if (namelen == 0) {
292 namelen = sizeof(username);
293 if (GetUserName(username, &namelen) == 0)
294 return (ISC_R_FAILURE);
295 }
296 return (NTFS_Access_Control(path, username, access, isdir));
297 }
298
299 isc_result_t
isc_fsaccess_set(const char * path,isc_fsaccess_t access)300 isc_fsaccess_set(const char *path, isc_fsaccess_t access) {
301 struct stat statb;
302 isc_boolean_t is_dir = ISC_FALSE;
303 isc_result_t result;
304
305 if (stat(path, &statb) != 0)
306 return (isc__errno2result(errno));
307
308 if ((statb.st_mode & S_IFDIR) != 0)
309 is_dir = ISC_TRUE;
310 else if ((statb.st_mode & S_IFREG) == 0)
311 return (ISC_R_INVALIDFILE);
312
313 result = check_bad_bits(access, is_dir);
314 if (result != ISC_R_SUCCESS)
315 return (result);
316
317 /*
318 * Determine if this is a FAT or NTFS disk and
319 * call the appropriate function to set the permissions
320 */
321 if (is_ntfs(path))
322 return (NTFS_fsaccess_set(path, access, is_dir));
323 else
324 return (FAT_fsaccess_set(path, access));
325 }
326
327 isc_result_t
isc_fsaccess_changeowner(const char * filename,const char * user)328 isc_fsaccess_changeowner(const char *filename, const char *user) {
329 SECURITY_DESCRIPTOR psd;
330 BYTE sidBuffer[500];
331 BYTE groupBuffer[500];
332 PSID psid=(PSID) &sidBuffer;
333 DWORD sidBufferSize = sizeof(sidBuffer);
334 char domainBuffer[100];
335 DWORD domainBufferSize = sizeof(domainBuffer);
336 SID_NAME_USE snu;
337 PSID pSidGroup = (PSID) &groupBuffer;
338 DWORD groupBufferSize = sizeof(groupBuffer);
339
340
341 /*
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
345 * a noop.
346 */
347 if (is_ntfs(filename) == FALSE)
348 return (ISC_R_SUCCESS);
349
350 if (!InitializeSecurityDescriptor(&psd, SECURITY_DESCRIPTOR_REVISION))
351 return (ISC_R_NOPERM);
352
353 if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer,
354 &domainBufferSize, &snu))
355 return (ISC_R_NOPERM);
356
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);
362
363 if (!SetSecurityDescriptorOwner(&psd, psid, FALSE))
364 return (ISC_R_NOPERM);
365
366 if (!SetSecurityDescriptorGroup(&psd, pSidGroup, FALSE))
367 return (ISC_R_NOPERM);
368
369 if (!SetFileSecurity(filename,
370 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION,
371 &psd))
372 return (ISC_R_NOPERM);
373
374 return (ISC_R_SUCCESS);
375 }
376
377