"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/isc/win32/fsaccess.c" (4 Sep 2020, 10202 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fsaccess.c" see the Fossies "Dox" file reference documentation.

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