tags:

views:

400

answers:

2

I need to get machine SID (not computer account's SID) in C#. Computer is specified be host name, it is't necessarily local computer and it can be domain computer or workgroup computer. I using this helper class to call LookupAccountName API function:

    private static class Helper
    {
        internal enum SID_NAME_USE
        {
            SidTypeUser = 1,
            SidTypeGroup,
            SidTypeDomain,
            SidTypeAlias,
            SidTypeWellKnownGroup,
            SidTypeDeletedAccount,
            SidTypeInvalid,
            SidTypeUnknown,
            SidTypeComputer
        }

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool LookupAccountName(
            string systemName,
            string accountName,
            byte[] sid,
            ref int sidLen,
            System.Text.StringBuilder domainName,
            ref int domainNameLen,
            out SID_NAME_USE peUse);

        public static SecurityIdentifier LookupAccountName(
            string systemName,
            string accountName,
            out string strDomainName,
            out SID_NAME_USE accountType)
        {
            const int ERROR_INSUFFICIENT_BUFFER = 122;

            int lSidSize = 0;
            int lDomainNameSize = 0;

            //First get the required buffer sizes for SID and domain name.
            LookupAccountName(systemName,
                              accountName,
                              null,
                              ref lSidSize,
                              null,
                              ref lDomainNameSize,
                              out accountType);

            if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
            {
                //Allocate the buffers with actual sizes that are required
                //for SID and domain name.
                byte[] sid = new byte[lSidSize];
                var sbDomainName = new System.Text.StringBuilder(lDomainNameSize);

                if (LookupAccountName(systemName,
                                      accountName,
                                      sid,
                                      ref lSidSize,
                                      sbDomainName,
                                      ref lDomainNameSize,
                                      out accountType))
                {
                    strDomainName = sbDomainName.ToString();
                    return new SecurityIdentifier(sid, 0);
                }
            }

            throw new Win32Exception();
        }
    }

and using it like this:

Helper.SID_NAME_USE accountType;
string refDomain;
SecurityIdentifier sid = Helper.LookupAccountName("falcon.mydomain.local", "falcon", out refDomain, out accountType);  //Domain computer

SecurityIdentifier sid = Helper.LookupAccountName("rat", "rat", out refDomain, out accountType);  //Workgroup computer

My only problem is, that this is not working if computer is primary domain controller (i need to obtain domain SID in that case).