Introduction
I needed this code for a project I contributed to Blackball, Inc. I found all kinds of examples on the web, but they all fell short for various reasons. One problem was that most of the examples I found did not work on a remote location. Another issue was that many of the examples I found did not properly deal with 'UNC vs. Drive Letter' path issues... including drive letter paths that map to 'Physical Drives vs. Shares'. This code will also work on folders.
Demo Project
The demo project download is a quick way to take a look at how the code can be used.
If you just want to grab the code and start using it in your own project, you need to copy the file name getowner.cpp into your project folder and then add it to your project. The file is dependent on Win32 and RTL libraries.
Points of Interest
The code within the getowner.cpp file is really just a 'C' function and will work in a 'C' project if you move the variable declarations to the top of the function. The function is called GetOwner()
and is detailed in Figure 1. The GetOwner()
function takes three parameters: the path to the item in question, a pointer to a buffer to contain the result, and the size of the buffer in bytes. The numbered comments within the code spell out the intent of each step. Interesting APIs used are WNetGetUniversalName()
, GetFileSecurity()
, GetSecurityDescriptorOwner()
, and LookupAccountSid()
.
#include <windows.h>
#include <shlwapi.h>
#include <winnetwk.h>
UINT GetOwner(LPCWSTR szFileOrFolderPathName, LPWSTR pUserNameBuffer, int nSizeInBytes) {
if(!lstrlen(szFileOrFolderPathName) || !PathFileExist(szFileOrFolderPathName))
return ERROR_INVALID_PARAMETER;
if(nSizeInBytes<=0 || pUserNameBuffer==NULL)
return ERROR_INVALID_PARAMETER;
WCHAR szUNCPathName[32767] = {0};
if(!PathIsUNC(szFileOrFolderPathName)) {
DWORD dwUniSize = 32767*sizeof(WCHAR);
UNIVERSAL_NAME_INFO* pUNI = (UNIVERSAL_NAME_INFO*)szUNCPathName;
if(!WNetGetUniversalName(szFileOrFolderPathName,
UNIVERSAL_NAME_INFO_LEVEL, pUNI, &dwUniSize)) {
lstrcpy(szUNCPathName, pUNI->lpUniversalName);
} else {
lstrcpy(szUNCPathName,szFileOrFolderPathName);
}
} else {
lstrcpy(szUNCPathName,szFileOrFolderPathName);
}
WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH+1] = {0};
if(PathIsUNC(szUNCPathName)) {
LPWSTR lpMachineName = PathFindNextComponent(szUNCPathName);
int nPos = 0;
LPWSTR lpNextSlash = lpMachineName;
while((lpNextSlash[0] != L'\\') && (lpNextSlash[0] != L'\0')) {
nPos++;
lpNextSlash++;
}
lstrcpyn(szMachineName, lpMachineName, nPos+1);
}
unsigned long uSizeNeeded = 0;
GetFileSecurity(szUNCPathName, OWNER_SECURITY_INFORMATION, 0, 0, &uSizeNeeded);
UINT uRet = GetLastError();
if(uRet==ERROR_INSUFFICIENT_BUFFER && uSizeNeeded) {
uRet = S_OK;
LPBYTE lpSecurityBuffer = (LPBYTE) malloc(uSizeNeeded * sizeof(BYTE));
if(!lpSecurityBuffer) {
return ERROR_NOT_ENOUGH_MEMORY;
}
if(!GetFileSecurity(szUNCPathName, OWNER_SECURITY_INFORMATION,
lpSecurityBuffer, uSizeNeeded, &uSizeNeeded)) {
free(lpSecurityBuffer);
return GetLastError();
}
PSID pSID = NULL;
BOOL bOwnerDefaulted = FALSE;
if(!GetSecurityDescriptorOwner(lpSecurityBuffer, &pSID, &bOwnerDefaulted)) {
free(lpSecurityBuffer);
return GetLastError();
}
LPWSTR pName = NULL;
LPWSTR pDomain = NULL;
unsigned long uNameLen = 0;
unsigned long uDomainLen = 0;
SID_NAME_USE sidNameUse = SidTypeUser;
LookupAccountSid(szMachineName, pSID, pName, &uNameLen,
pDomain, &uDomainLen, &sidNameUse);
uRet = GetLastError();
if((uRet==ERROR_INSUFFICIENT_BUFFER) && uNameLen && uDomainLen) {
uRet = S_OK;
pName = (LPWSTR) malloc(uNameLen * sizeof(WCHAR));
pDomain = (LPWSTR) malloc(uDomainLen * sizeof(WCHAR));
if(!pName || !pDomain) {
free(lpSecurityBuffer);
return ERROR_NOT_ENOUGH_MEMORY;
}
if(!LookupAccountSid(szMachineName, pSID, pName,
&uNameLen, pDomain, &uDomainLen, &sidNameUse)) {
free(pName);
free(pDomain);
free(lpSecurityBuffer);
return GetLastError();
}
if(nSizeBytes > ((uNameLen+uDomainLen+1)*sizeof(WCHAR))) {
lstrcpy(pUserNameBuffer, pDomain);
lstrcat(pUserNameBuffer, L"\\");
lstrcat(pUserNameBuffer, pName);
} else {
uRet = ERROR_INSUFFICIENT_BUFFER;
}
free(pName);
free(pDomain);
}
free(lpSecurityBuffer);
}
return uRet;
}
(Figure 1)
If I left out any details you think should be mentioned in the article, please let me know.
If you could take one last second to rate this article or even leave a comment, it would be much appreciated.
Thanks for reading!
16yrs of GUI programming experience gained at: (most recent first) BlackBall, Veritas, Seagate Software, Arcada, Stac, Mountain, and Emerald Systems.
Languages/Scripting: C, C++, JAVA, BASIC, JAVASCRIPT, HTML, XML, PHP, and SQL
Tools: MS Visual Studio, MS Visual SourceSafe, CVS, PVCS, Bounds Checker, VMWare, ToDoList, InstallShield, and Office Applications
Libraries and API: RTL, STL, WIN32, MFC, ATL, .NET, ActiveX, DirectX, COM, DCOM, Shell Extensions, and Shell Namespaces
Strengths: Honest, communicative, keen eye for usability, good at estimating workload and completion dates, ready to take on grunt work, team player, experienced working with QA, localization, Tech Pubs, Sales, and Marketing teams.