xref: /minix/external/bsd/bind/dist/lib/isc/win32/fsaccess.c (revision 00b67f09)
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