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