Pregunta

Tengo una aplicación C # que escanea un directorio y recopila información. Me gustaría mostrar el nombre de la cuenta para cada archivo. Puedo hacer esto en el sistema local obteniendo el SID para el objeto FileInfo y luego haciendo:

string GetNameFromSID( SecurityIdentifier sid )
{
    NTAccount ntAccount = (NTAccount)sid.Translate( typeof( NTAccount ) );
    return ntAccount.ToString();
}

Sin embargo, esto no funciona para archivos en una red, presumiblemente porque la función Traducir () solo funciona con cuentas de usuario locales. Pensé que tal vez podría hacer una búsqueda LDAP en el SID, así que intenté lo siguiente:

string GetNameFromSID( SecurityIdentifier sid )
{
    string str = "LDAP://<SID=" + sid.Value + ">";
    DirectoryEntry dirEntry = new DirectoryEntry( str );
    return dirEntry.Name;
}

Parece que funcionará, ya que el acceso a " dirEntry.Name " se cuelga durante unos segundos, como si se apagara y consultara la red, pero luego arroja una excepción System.Runtime.InteropServices.COMException

¿Alguien sabe cómo puedo obtener el nombre de cuenta de un archivo arbitrario o SID? No sé mucho sobre redes o LDAP ni nada. Hay una clase llamada DirectorySearcher que tal vez se supone que debo usar, pero quiere un nombre de dominio y tampoco sé cómo obtenerlo; todo lo que tengo es la ruta al directorio que estoy escaneando.

Gracias de antemano.

¿Fue útil?

Solución

El método Traducir del objeto SecurityReference funciona en SID no locales, pero solo para cuentas de dominio. Para las cuentas locales de otra máquina o en una configuración que no sea de dominio, necesitará PInvocar la función LookupAccountSid que especifica el nombre específico de la máquina en la que se debe realizar la búsqueda.

Otros consejos

Vea aquí para una buena respuesta:

¿La mejor manera de resolver mostrar el nombre de usuario por SID?

La esencia de esto es este bit:

string sid="S-1-5-21-789336058-507921405-854245398-9938";
string account = new System.Security.Principal.SecurityIdentifier(sid).Translate(typeof(System.Security.Principal.NTAccount)).ToString();

Este enfoque funciona para mí para los SID no locales sobre el directorio activo.

System.DirectoryServices.AccountManagement.UserPrincipal class (msdn link) has a static function FindByIdentity to convert an SID to a User object. It should be able to work both against the local machine or an LDAP/Active Directory server. I have only used it against active directory.

Here is an example that I have used in IIS:

// Set the search context to a specific domain in active directory
var searchContext = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=SomeOU,DC=YourCompany,DC=com");
// get the currently logged in user from IIS
MembershipUser aspUser = Membership.GetUser();
// get the SID of the user (stored in the SecurityIdentifier class)
var sid = aspUser.ProviderUserKey as System.Security.Principal.SecurityIdentifier;
// get the ActiveDirectory user object using the SID (sid.Value returns the SID in string form)
var adUser = UserPrincipal.FindByIdentity(searchContext, IdentityType.Sid, sid.Value);
// do stuff to user, look up group membership, etc.

In C#, get the user SID and assign it to a string variable through:

string strUser = System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString();

You will need to use string because the ability to resolve to the UserName supports string. In other words, using var varUser will result in a namespace error.

string strUserName = new System.Security.Principal.SecurityIdentifier(strUser).Translate(typeof(System.Security.Principal.NTAccount)).ToString();

Ooh, then it's possible that the LDAP call is not working because you might not be in an Active Directory environment. If this is the case, then each of your machines is responsible for its own identity store. And your first code sample is not working across the network because the machine on which you are executing your code does not know how to resolve the SID that only makes sense on the remote machine.

You really should check if your machines are a part of an Active Directory. You would know this during the logon process. Or you can check by right clicking on "My Computer", select "Properties", the "Computer Name" tab, then see if your computer is part of a domain.

Great. I cribbed some LookupAccountSid() code from here:

http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid

And that worked, though I had to provide the host name myself. In the case of a UNC path I can just take the first component of it. When it's a mapped drive, I use this code to convert the path to a UNC one:

http://www.wiredprairie.us/blog/index.php/archives/22

It seems to work, so that's how I'll do it, unless someone comes up with a situation in which the first component of a UNC path isn't the host name...

Thank you all for your help.

You can also get account name of special accounts like "Everyone" with code like this that will work regardless of user's language settings:

   SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
   string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString();

This one is a stumper. You are in an Active Directory environment right? Just checking:)

Anyhow, instead of binding with sid.Value,

string str = "LDAP://<SID=" + sid.Value + ">";

I would try converting the SID's byte array to an Octet String and bind with that instead.

There is a sweet example here on page 78. This will get you closer. To be honest, I've not tried binding with a SID before. But I've had success binding with a user's GUID though :)

Good luck and let me know how it goes.

Get the current domain:

System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain();

Get a directory entry from ldap and the domain name:

DirectoryEntry de = new DirectoryEntry(string.Format("LDAP://{0}", domain));

Get the sid from an ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:

ActiveDirectoryMembershipUser user = (ActiveDirectoryMembershipUser)Membership.GetUser();
var sid = (SecurityIdentifier)user.ProviderUserKey;

Get the username from the SecurityIdentifier:

(NTAccount)sid.Translate(typeof(NTAccount));

Get directory search done on an activedirectory with the domain directory entry and username:

DirectorySearcher search = new DirectorySearcher(entry);
        search.Filter = string.Format("(SAMAccountName={0})", username);
        search.PropertiesToLoad.Add("Name");
        search.PropertiesToLoad.Add("displayName");
        search.PropertiesToLoad.Add("company");
        search.PropertiesToLoad.Add("homePhone");
        search.PropertiesToLoad.Add("mail");
        search.PropertiesToLoad.Add("givenName");
        search.PropertiesToLoad.Add("lastLogon");
        search.PropertiesToLoad.Add("userPrincipalName");
        search.PropertiesToLoad.Add("st");
        search.PropertiesToLoad.Add("sn");
        search.PropertiesToLoad.Add("telephoneNumber");
        search.PropertiesToLoad.Add("postalCode");
        SearchResult result = search.FindOne();
        if (result != null)
        {
            foreach (string key in result.Properties.PropertyNames)
            {
                // Each property contains a collection of its own
                // that may contain multiple values
                foreach (Object propValue in result.Properties[key])
                {
                    outputString += key + " = " + propValue + ".<br/>";
                }
            }
        }

Depending on the data in your active directory, you will get a varied response in the output.

Here is a site that has all the user properties I needed:

I am quite sure you will be able to use the accepted answer from here: Determine the LocalSystem account name using C#

Basically, you can translate an instance of the SecurityIdentifier class to type NTAccount, from which you can get the user name. In code:

using System.Security.Principal;

SecurityIdentifier sid = new SecurityIdentifier("S-1-5-18");
NTAccount acct = (NTAccount)sid.Translate(typeof(NTAccount));
Console.WriteLine(acct.Value);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top