webForumDet fria alternativet

Namespace för Windows konton ?

.NET

14 svar · 728 visningar · startad av erka

Medlem sedan dec. 19996 522 inlägg
Frågan#1

Jag undrar om någon vet i vilket namespace jag hittar klasser för att hantera windows konton, tex om jag vill ändra lösenordet till en viss använder lokalt på servern.

Medlem sedan dec. 19996 522 inlägg
#2

Har nu letat i 2 dagar efter hur man ändrar NLTM lösenord via .net, men inte hittat något. Det borde ju gå. Ingen som har någon annan idé ;) Börjar bli smått desperat

Medlem sedan aug. 2001458 inlägg
#3

Använd NetUserChangePassword med interop

Medlem sedan dec. 19996 522 inlägg
#4

developer, förklara gärna lite mer :) tack

Medlem sedan aug. 2001458 inlägg
#5

Normalt används funktionen NetUserChangePassword för att programmatiskt byta lösenord. Dock finns inte den exponerad i .Nets klassbibliotek. Man använder då "interop" (interoperability) eller mer specifikt P/Invoke för att komma åt den som en vanlig C-funktioner från en dll.

NetUserChangePassword finns i Netapi32.dll, och du måste då i din klass berätta att du vill komma åt den. Såhär:

[DllImport("Netapi32.dll", EntryPoint="NetUserChangePassword", SetLastError=false, CharSet=CharSet.Unicode, ExactSpelling=true)]
private static extern NET_API_STATUS NetUserChangePassword(String domainname, String username, String oldpassword, String newpassword);

Nu vet .Net runtimen att den ska använda den NetUserChangePassword som finns i NetApi32.dll från din C# kod. Dock finns inte NET_API_STATUS i .Nets klassbibliotek, men från <LMCons.h> ser man att det är en DWORD, vilket i C# motsvarar en uint.

Det är smidigt att lägga in returvärdena i en enum. Dessutom tycker jag det är trevligare att wrappa all funktionalitet i en klass så att användaren av klassen inte ser vad som ligger bakom. Klassen har statiska publika metoder för att byta lösenord och kastar exception om något går fel. All kod är *givetvis* helt otestad.

using System;
using System.Runtime.InteropServices;

public sealed class NetApi 
{
	#region P/Invoke
	private const uint NERR_BASE = 2100; // från <LMErr.h>
	private enum NET_API_STATUS : uint 
	{
		NERR_Success            = 0,
		ERROR_ACCESS_DENIED     = 5,
		ERROR_INVALID_PASSWORD  = 86,
		NERR_InvalidComputer    = NERR_BASE+251,
		NERR_NotPrimary         = NERR_BASE+126,
		NERR_UserNotFound       = NERR_BASE+121,
		NERR_PasswordTooShort   = NERR_BASE+145,
	}
	[DllImport("Netapi32.dll", EntryPoint="NetUserChangePassword", SetLastError=false, CharSet=CharSet.Unicode, ExactSpelling=true)]
	private static extern NET_API_STATUS NetUserChangePassword(String domainname, String username, String oldpassword, String newpassword);
	#endregion

	// Den här klassen vill vi inte skapa instanser av. En privat konstruktor
	// stoppar det.
	private NetApi() {}

	#region Exceptions

	// Just nu har vi bara password-funktionalitet, men senare kanske du
	// vill lägga till mer från NetApi. Därför har vi ett bas-exception
	// för framtida bruk.
	public class NetApiException : Exception
	{
	}

	// Detta kastas om password-bytet gått fel
	public sealed class PasswordException : NetApiException 
	{
		public enum ExceptionReason 
		{
			OldPasswordRejected,
			NewPasswordRejected,
			InvalidUserName,
			DomainNotFound,
			NotPrimary,
			UnknownError,
		};

		ExceptionReason m_Reason;
		ExceptionReason Reason { get { return m_Reason; } }
		public PasswordException(ExceptionReason reason) 
		{
			m_Reason = reason;
		}
		public override string ToString()
		{
			return "Failed to change password: " + Reason.ToString();
		}
	}
	#endregion

	/// <summary>
	/// Byter lösenord för angiven användare
	/// </summary>
	public static void ChangePassword(String domainname, String username, String oldpassword, String newpassword) 
	{
		if (oldpassword == null) throw new ArgumentNullException("oldpassword");
		if (newpassword == null) throw new ArgumentNullException("newpassword");

		switch (NetUserChangePassword(domainname, username, oldpassword, newpassword)) 
		{
			case NET_API_STATUS.NERR_Success:
				break;

			case NET_API_STATUS.NERR_UserNotFound:
				throw new PasswordException(PasswordException.ExceptionReason.InvalidUserName);
			case NET_API_STATUS.ERROR_INVALID_PASSWORD:
				throw new PasswordException(PasswordException.ExceptionReason.OldPasswordRejected);
			case NET_API_STATUS.NERR_PasswordTooShort:
				throw new PasswordException(PasswordException.ExceptionReason.NewPasswordRejected);
			case NET_API_STATUS.NERR_InvalidComputer:
				throw new PasswordException(PasswordException.ExceptionReason.DomainNotFound);
			case NET_API_STATUS.NERR_NotPrimary:
				throw new PasswordException(PasswordException.ExceptionReason.NotPrimary);

			default:
				throw new PasswordException(PasswordException.ExceptionReason.UnknownError);
		}
	}

	/// <summary>
	/// Byter lösenord för användaren som kör detta.
	/// </summary>
	public static void ChangePassword(String oldpassword, String newpassword) 
	{
		ChangePassword(null, null, oldpassword, newpassword);
	}
}

Mer information om interop finns bland annat här:

Medlem sedan dec. 19996 522 inlägg
#6

Stort tack developer, lär återkomma med fler frågor snart ;)

Medlem sedan dec. 19996 522 inlägg
#7

Håller nu på och pillar, din kod verkar fungera hyffsat med små modifieringar. Den spottar ut felmeddelanden om jag skickar in fel användarnamn etc. Men om jag skickar in rätt lösenord och användare ger den mig

throw new PasswordException(PasswordException.ExceptionReason.UnknownError);

Min c# är ju inget vidare, är det något rättighetsproblem kanske ?

Medlem sedan aug. 2001458 inlägg
#8

Kolla så NET_API_STATUS-konstanterna stämmer, du får söka i .h filerna för att hitta dem. Alternativt göra ett c-program som skriver ut de numeriska värdena. Sedan såg jag att jag glömt ERROR_ACCESS_DENIED i switchen.

Vad blir det numeriska returvärdet?

NET_API_STATUS status = NetUserChangePassword(...);

Medlem sedan dec. 19996 522 inlägg
#9

Tack developer får nu

throw new PasswordException(PasswordException.ExceptionReason.AccessDenied)

men om jag ger asp.net kontot rättigheter till Netapi32.dll fungerar det ändå inte. Är det något annat kanske. Hajjar inte riktigt hur jag ska få ut det numeriska returvärdet, kör det på en aspx sida där jag än så länge bara har klassen i ett script block, på sidan finns textfält för gamalt lösenord samt nytt, och en submittknapp som triggar en sub som i sin tur kör ChangeUsrPassword med värdena från textboxarna.

tacksam

Medlem sedan aug. 2001458 inlägg
#10

Det är inte själva dll:en du inte ha access till. Du lyckas ju exekvera funktionen och den returnerar en felkod. Problemet måste vara att användaren inte har rätt att exekvera NetUserChangePassword.

Vad händer om du kör från en vanlig windows form applikation eller en console-applikation med samma parametrar?

Vilket OS? Vilken användare blir det som kör funktionen under IIS:en? Läs hjälpen för NetUserChangePassword under "Remarks" om ERROR_ACCESS_DENIED.

Medlem sedan dec. 19996 522 inlägg
#11

det är win2000, användaren som kör funktionen är den som är inloggad, om jag loggar in som "Erka" med lösenordet "querty" så är det ju det lösenordet jag försöker ändra. Ska kolla hjälpen, tack för hjälpen hitills :)

Medlem sedan dec. 19996 522 inlägg
#12

Har lyckats lösa det nu genom att köra en "impersonation" som serveradmin innan jag försöker byta lösenord, sedan byter jag tillbaks till inloggad användare. Bara ett problem då jag inte är en c# kille.

Hur får jag felmeddelanden som fångas i tex

throw new PasswordException(PasswordException.ExceptionReason.InvalidUserName);

att skrivas ut med en förklarande text istället som nu skrivas ut rakt på sidan

Exception of type PasswordException was thrown.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Har en label på sidan som heter LblErrorMsg

tacksam

Medlem sedan dec. 19996 522 inlägg
#13

Vad jag undrar över är alltså hur jag i c# ska skriva för att få felmeddelandet (om något genereras) i ditt exempel att skrivas ut i en label på aspx sidan om ett fel uppstår.

tacksam

Medlem sedan aug. 2001458 inlägg
#14

Läs om try/catch: http://msdn.microsoft.com/library/en-us/csref/html/vclrfTheTrycatchStatement.asp

try
{
    NetApi.ChangePassword("", "");
}
catch (PasswordException passwordException)
{
    string err = "";
    switch (passwordException.Reason)
    {
        case NetApi.PasswordException.OldPasswordRejected: s = "invalid password"; break;
        case NetApi.PasswordException.NewPasswordRejected: s = "New password incorrect (rejected by policy, too short etc.)"; break;
        default: s = passwordException.Reason.ToString(); break;
    }
    Console.WriteLine("Failed to change password: {0}", s);
}
Medlem sedan dec. 19996 522 inlägg
#15

Stort tack developer, härligt med folk som hjälper till andra som inte vet lika mycket :) Trode inte att try catch fanns i c#

259 ms totalt · 4 externa anrop · v20260731065814-full.1dc6f849
121 ms — deklarationer (db)
0 ms — hämta statistik (cache)
135 ms — hämta tråd, inlägg och bilagor (db)
121 ms — ändringar (db)