123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
- #include "winutils.h"
- //----------------------------------------------------------------------------
- // Function: ChangeFileOwnerBySid
- //
- // Description:
- // Change a file or directory ownership by giving new owner and group SIDs
- //
- // Returns:
- // ERROR_SUCCESS: on success
- // Error code: otherwise
- //
- // Notes:
- // This function is long path safe, i.e. the path will be converted to long
- // path format if not already converted. So the caller does not need to do
- // the converstion before calling the method.
- //
- static DWORD ChangeFileOwnerBySid(__in LPCWSTR path,
- __in_opt PSID pNewOwnerSid, __in_opt PSID pNewGroupSid)
- {
- LPWSTR longPathName = NULL;
- INT oldMode = 0;
- SECURITY_INFORMATION securityInformation = 0;
- DWORD dwRtnCode = ERROR_SUCCESS;
- // Convert the path the the long path
- //
- dwRtnCode = ConvertToLongPath(path, &longPathName);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto ChangeFileOwnerByNameEnd;
- }
- // Get a pointer to the existing owner information and DACL
- //
- dwRtnCode = FindFileOwnerAndPermission(longPathName, FALSE, NULL, NULL, &oldMode);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto ChangeFileOwnerByNameEnd;
- }
- // We need SeTakeOwnershipPrivilege to set the owner if the caller does not
- // have WRITE_OWNER access to the object; we need SeRestorePrivilege if the
- // SID is not contained in the caller's token, and have the SE_GROUP_OWNER
- // permission enabled.
- //
- if (!EnablePrivilege(L"SeTakeOwnershipPrivilege"))
- {
- fwprintf(stdout, L"INFO: The user does not have SeTakeOwnershipPrivilege.\n");
- }
- if (!EnablePrivilege(L"SeRestorePrivilege"))
- {
- fwprintf(stdout, L"INFO: The user does not have SeRestorePrivilege.\n");
- }
- assert(pNewOwnerSid != NULL || pNewGroupSid != NULL);
- // Set the owners of the file.
- //
- if (pNewOwnerSid != NULL) securityInformation |= OWNER_SECURITY_INFORMATION;
- if (pNewGroupSid != NULL) securityInformation |= GROUP_SECURITY_INFORMATION;
- dwRtnCode = SetNamedSecurityInfoW(
- longPathName,
- SE_FILE_OBJECT,
- securityInformation,
- pNewOwnerSid,
- pNewGroupSid,
- NULL,
- NULL);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto ChangeFileOwnerByNameEnd;
- }
- // Set the permission on the file for the new owner.
- //
- dwRtnCode = ChangeFileModeByMask(longPathName, oldMode);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- goto ChangeFileOwnerByNameEnd;
- }
- ChangeFileOwnerByNameEnd:
- LocalFree(longPathName);
- return dwRtnCode;
- }
- //----------------------------------------------------------------------------
- // Function: Chown
- //
- // Description:
- // The main method for chown command
- //
- // Returns:
- // 0: on success
- //
- // Notes:
- //
- //
- int Chown(__in int argc, __in_ecount(argc) wchar_t *argv[])
- {
- LPWSTR pathName = NULL;
- LPWSTR ownerInfo = NULL;
- WCHAR const * colonPos = NULL;
- LPWSTR userName = NULL;
- size_t userNameLen = 0;
- LPWSTR groupName = NULL;
- size_t groupNameLen = 0;
- PSID pNewOwnerSid = NULL;
- PSID pNewGroupSid = NULL;
- DWORD dwRtnCode = 0;
- int ret = EXIT_FAILURE;
- if (argc >= 3)
- {
- ownerInfo = argv[1];
- pathName = argv[2];
- }
- else
- {
- fwprintf(stderr, L"Incorrect command line arguments.\n\n");
- ChownUsage(argv[0]);
- return ret;
- }
- // Parsing the owner name
- //
- if ((colonPos = wcschr(ownerInfo, L':')) != NULL)
- {
- if (colonPos - ownerInfo != 0)
- {
- // Length includes NULL terminator
- userNameLen = colonPos - ownerInfo + 1;
- userName = (LPTSTR)LocalAlloc(LPTR, userNameLen * sizeof(WCHAR));
- if (userName == NULL)
- {
- ReportErrorCode(L"LocalAlloc", GetLastError());
- goto ChownEnd;
- }
- if (FAILED(StringCchCopyNW(userName, userNameLen,
- ownerInfo, userNameLen - 1)))
- goto ChownEnd;
- }
- if (*(colonPos + 1) != 0)
- {
- // Length includes NULL terminator
- groupNameLen = wcslen(ownerInfo) - (colonPos - ownerInfo) + 1;
- groupName = (LPTSTR)LocalAlloc(LPTR, groupNameLen * sizeof(WCHAR));
- if (groupName == NULL)
- {
- ReportErrorCode(L"LocalAlloc", GetLastError());
- goto ChownEnd;
- }
- if (FAILED(StringCchCopyNW(groupName, groupNameLen,
- colonPos + 1, groupNameLen)))
- goto ChownEnd;
- }
- }
- else
- {
- // Length includes NULL terminator
- userNameLen = wcslen(ownerInfo) + 1;
- userName = (LPWSTR)LocalAlloc(LPTR, userNameLen * sizeof(WCHAR));
- if (userName == NULL)
- {
- ReportErrorCode(L"LocalAlloc", GetLastError());
- goto ChownEnd;
- }
- if (FAILED(StringCchCopyNW(userName, userNameLen, ownerInfo, userNameLen)))
- goto ChownEnd;
- }
- // Not allow zero length user name or group name in the parsing results.
- //
- assert(userName == NULL || wcslen(userName) > 0);
- assert(groupName == NULL || wcslen(groupName) > 0);
- // Nothing to change if both names are empty
- //
- if ((userName == NULL) && (groupName == NULL))
- {
- ret = EXIT_SUCCESS;
- goto ChownEnd;
- }
- if (userName != NULL)
- {
- dwRtnCode = GetSidFromAcctNameW(userName, &pNewOwnerSid);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- ReportErrorCode(L"GetSidFromAcctName", dwRtnCode);
- fwprintf(stderr, L"Invalid user name: %s\n", userName);
- goto ChownEnd;
- }
- }
- if (groupName != NULL)
- {
- dwRtnCode = GetSidFromAcctNameW(groupName, &pNewGroupSid);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- ReportErrorCode(L"GetSidFromAcctName", dwRtnCode);
- fwprintf(stderr, L"Invalid group name: %s\n", groupName);
- goto ChownEnd;
- }
- }
- if (wcslen(pathName) == 0 || wcsspn(pathName, L"/?|><:*\"") != 0)
- {
- fwprintf(stderr, L"Incorrect file name format: %s\n", pathName);
- goto ChownEnd;
- }
- dwRtnCode = ChangeFileOwnerBySid(pathName, pNewOwnerSid, pNewGroupSid);
- if (dwRtnCode != ERROR_SUCCESS)
- {
- ReportErrorCode(L"ChangeFileOwnerBySid", dwRtnCode);
- goto ChownEnd;
- }
- ret = EXIT_SUCCESS;
- ChownEnd:
- LocalFree(userName);
- LocalFree(groupName);
- LocalFree(pNewOwnerSid);
- LocalFree(pNewGroupSid);
- return ret;
- }
- void ChownUsage(LPCWSTR program)
- {
- fwprintf(stdout, L"\
- Usage: %s [OWNER][:[GROUP]] [FILE]\n\
- Change the owner and/or group of the FILE to OWNER and/or GROUP.\n\
- \n\
- Note:\n\
- On Linux, if a colon but no group name follows the user name, the group of\n\
- the files is changed to that user\'s login group. Windows has no concept of\n\
- a user's login group. So we do not change the group owner in this case.\n",
- program);
- }
|