Click here to Skip to main content
15,886,137 members
Articles / Web Development / ASP.NET
Article

How to determine the owner of both local and remote files

Rate me:
Please Sign up or sign in to vote.
4.43/5 (11 votes)
30 Jun 2006CPOL2 min read 63.3K   1.1K   36   13
Code to determine the owner of both local and remote files.

Sample Image - fileowner.png

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> // For the 'Win32' API.
#include <shlwapi.h> // For the 'Path' API.
#include <winnetwk.h> // For the 'WNet' API.


// Function name   : GetOwner

// Description     : Determines the 'Owner' of a given file or folder.

// Return type     : UINT is S_OK if successful; A Win32 'ERROR_' value otherwise.

// Argument        : LPCWSTR szFileOrFolderPathName is the fully
//                   qualified path of the file or folder to examine.

// Argument        : LPWSTR pUserNameBuffer is a pointer to a buffer
//                   used to contain the resulting 'Owner' string.

// Argument        : int nSizeInBytes is the size of the buffer.

UINT GetOwner(LPCWSTR szFileOrFolderPathName, LPWSTR pUserNameBuffer, int nSizeInBytes) {
    // 1) Validate the path:

    // 1.1) Length should not be 0.

    // 1.2) Path must point to an existing file or folder.

    if(!lstrlen(szFileOrFolderPathName) || !PathFileExist(szFileOrFolderPathName))
        return ERROR_INVALID_PARAMETER;

    // 2) Validate the buffer:

    // 2.1) Size must not be 0.

    // 2.2) Pointer must not be NULL.

    if(nSizeInBytes<=0 || pUserNameBuffer==NULL)
        return ERROR_INVALID_PARAMETER;

    // 3) Convert the path to UNC if it is not already UNC
    //    so that we can extract a machine name from it:

    // 3.1) Use a big buffer... some OS's can have a path that is 32768 chars in length.

    WCHAR szUNCPathName[32767] = {0};
    // 3.2) If path is not UNC...

    if(!PathIsUNC(szFileOrFolderPathName)) {
        // 3.3) Mask the big buffer into a UNIVERSAL_NAME_INFO.

        DWORD dwUniSize = 32767*sizeof(WCHAR);
        UNIVERSAL_NAME_INFO* pUNI = (UNIVERSAL_NAME_INFO*)szUNCPathName;
        // 3.4) Attempt to get the UNC version of the path into the big buffer.

        if(!WNetGetUniversalName(szFileOrFolderPathName, 
            UNIVERSAL_NAME_INFO_LEVEL, pUNI, &dwUniSize)) {
            // 3.5) If successful, copy the UNC version into the buffer.

            lstrcpy(szUNCPathName, pUNI->lpUniversalName);
        } else {
            // 3.6) If not successful, copy the original path into the buffer.

            lstrcpy(szUNCPathName,szFileOrFolderPathName);
        }
    } else {
        // 3.7) Path is already UNC, copy the original path into the buffer.

        lstrcpy(szUNCPathName,szFileOrFolderPathName);
    }

    // 4) If path is UNC (will not be the case for local physical
    //    drive paths) we want to extract the machine name:

    // 4.1) Use a buffer bug enough to hold a machine name per Win32.

    WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH+1] = {0};
    // 4.2) If path is UNC...

    if(PathIsUNC(szUNCPathName)) {
        // 4.3) Use PathFindNextComponent() to skip past the double backslashes.

        LPWSTR lpMachineName = PathFindNextComponent(szUNCPathName);
        // 4.4) Walk the the rest of the path to find the end of the machine name.

        int nPos = 0;
        LPWSTR lpNextSlash = lpMachineName;
        while((lpNextSlash[0] != L'\\') && (lpNextSlash[0] != L'\0')) {
            nPos++;
            lpNextSlash++;
        }
        // 4.5) Copyt the machine name into the buffer.

        lstrcpyn(szMachineName, lpMachineName, nPos+1);
    }

    // 5) Derive the 'Owner' by getting the owner's Security ID from
    //    a Security Descriptor associated with the file or folder indicated in the path.

    // 5.1) Get a security descriptor for the file
    //      or folder that contains the Owner Security Information.

    // 5.1.1) Use GetFileSecurity() with some null params to get the required buffer size.

    // 5.1.2) We don't really care about the return value.

    // 5.1.3) The error code must be ERROR_INSUFFICIENT_BUFFER for us to continue.

    unsigned long   uSizeNeeded = 0;
    GetFileSecurity(szUNCPathName, OWNER_SECURITY_INFORMATION, 0, 0, &uSizeNeeded);
    UINT uRet = GetLastError();
    if(uRet==ERROR_INSUFFICIENT_BUFFER && uSizeNeeded) {
        uRet = S_OK; // Clear the ERROR_INSUFFICIENT_BUFFER


        // 5.2) Allocate the buffer for the Security Descriptor, check for out of memory

        LPBYTE lpSecurityBuffer = (LPBYTE) malloc(uSizeNeeded * sizeof(BYTE));
        if(!lpSecurityBuffer) {
            return ERROR_NOT_ENOUGH_MEMORY;
        }

        // 5.2) Get the Security Descriptor that contains
        // the Owner Security Information into the buffer, check for errors

        if(!GetFileSecurity(szUNCPathName, OWNER_SECURITY_INFORMATION, 
                            lpSecurityBuffer, uSizeNeeded, &uSizeNeeded)) {
            free(lpSecurityBuffer);
            return GetLastError();
        }

        // 5.3) Get the the owner's Security ID (SID)
        // from the Security Descriptor, check for errors

        PSID pSID = NULL;
        BOOL bOwnerDefaulted = FALSE;
        if(!GetSecurityDescriptorOwner(lpSecurityBuffer, &pSID, &bOwnerDefaulted)) {
            free(lpSecurityBuffer);
            return GetLastError();
        }
  
        // 5.4) Get the size of the buffers needed
        //      for the owner information (domain and name)

        // 5.4.1) Use LookupAccountSid() with buffer sizes
        //        set to zero to get the required buffer sizes.

        // 5.4.2) We don't really care about the return value.

        // 5.4.3) The error code must be ERROR_INSUFFICIENT_BUFFER for us to continue.

        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; // Clear the ERROR_INSUFFICIENT_BUFFER


            // 5.5) Allocate the required buffers, check for out of memory

            pName = (LPWSTR) malloc(uNameLen * sizeof(WCHAR));
            pDomain = (LPWSTR) malloc(uDomainLen * sizeof(WCHAR));
            if(!pName || !pDomain) {
                free(lpSecurityBuffer);
                return ERROR_NOT_ENOUGH_MEMORY;
            }

            // 5.6) Get domain and username

            if(!LookupAccountSid(szMachineName, pSID, pName, 
                      &uNameLen, pDomain, &uDomainLen, &sidNameUse)) {
                free(pName);
                free(pDomain);
                free(lpSecurityBuffer);
                return GetLastError();
            }

            // 5.7) Build the owner string from the domain and username

            if(nSizeBytes > ((uNameLen+uDomainLen+1)*sizeof(WCHAR))) {
                lstrcpy(pUserNameBuffer, pDomain);
                lstrcat(pUserNameBuffer, L"\\");
                lstrcat(pUserNameBuffer, pName);
            } else {
                uRet = ERROR_INSUFFICIENT_BUFFER;

            }

            // 5.8) Release memory
            free(pName);
            free(pDomain);
        }
        // 5.9) Release memory
        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!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
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.

Comments and Discussions

 
QuestionIn c# Pin
L4NGERS19-Dec-11 3:21
L4NGERS19-Dec-11 3:21 
AnswerRe: In c# Pin
Shaun Harrington19-Dec-11 3:33
Shaun Harrington19-Dec-11 3:33 
GeneralThanks! Pin
alan.wagoner9-Oct-08 8:05
alan.wagoner9-Oct-08 8:05 
GeneralHelp, plz Pin
thangnvhl20-Aug-06 15:55
thangnvhl20-Aug-06 15:55 
GeneralRe: Help, plz Pin
Shaun Harrington21-Aug-06 3:34
Shaun Harrington21-Aug-06 3:34 
GeneralSpendid! Pin
Kdiggins6-Jul-06 13:54
Kdiggins6-Jul-06 13:54 
GeneralRe: Spendid! Pin
Shaun Harrington6-Jul-06 15:18
Shaun Harrington6-Jul-06 15:18 
Generalfileowner_demo.zip Pin
avnersimon25-Jun-06 23:50
avnersimon25-Jun-06 23:50 
GeneralRe: fileowner_demo.zip [modified] Pin
Shaun Harrington26-Jun-06 1:56
Shaun Harrington26-Jun-06 1:56 
Generalfileowner_demo.zip Pin
avnersimon25-Jun-06 23:48
avnersimon25-Jun-06 23:48 
GeneralIn a nutshell... Pin
Vasudevan Deepak Kumar21-Jun-06 23:19
Vasudevan Deepak Kumar21-Jun-06 23:19 
GeneralRe: In a nutshell... Pin
Shaun Harrington22-Jun-06 4:26
Shaun Harrington22-Jun-06 4:26 
GeneralRe: In a nutshell... Pin
Shaun Harrington22-Jun-06 10:07
Shaun Harrington22-Jun-06 10:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.