Frage

Ich habe eine Website bekommen, die Windows-Authentifizierung auf es ermöglichen hat. Von einer Seite in der Website haben die Nutzer die Möglichkeit, einen Dienst zu starten, ein paar Sachen mit der Datenbank der Fall ist.

Es funktioniert gut für mich, den Dienst zu starten, weil ich einen lokalen Administrator auf dem Server bin. Aber ich hatte nur ein Benutzer testen und sie kann den Dienst nicht gestartet bekommen.

Meine Frage ist:


Kennt jemand eine Möglichkeit, eine Liste der Dienste auf einem bestimmten Computer nach dem Namen zu bekommen eine anderen Fenster-Konto verwendet, als die, die sie zur Zeit angemeldet sind mit?


Ich möchte wirklich nicht alle Benutzer hinzufügen, die den Dienst in einer Windows-Gruppe starten müssen und sie alle zu einem lokalen Administrator auf meinem IIS-Server .....

Hier einige der Code, den ich habe:

public static ServiceControllerStatus FindService()
        {
            ServiceControllerStatus status = ServiceControllerStatus.Stopped;

            try
            {
                string machineName = ConfigurationManager.AppSettings["ServiceMachineName"];
                ServiceController[] services = ServiceController.GetServices(machineName);
                string serviceName = ConfigurationManager.AppSettings["ServiceName"].ToLower();

                foreach (ServiceController service in services)
                {
                    if (service.ServiceName.ToLower() == serviceName)
                    {
                        status = service.Status;
                        break;
                    }
                }
            }
            catch(Exception ex)
            {
                status = ServiceControllerStatus.Stopped;
                SaveError(ex, "Utilities - FindService()");
            }

            return status;
        }

Meine Ausnahme stammt aus der zweiten Zeile im try-Block. Hier ist der Fehler:

  

System.InvalidOperationException:   Kann nicht Service Control Manager öffnen auf   Computer 'server.domain.com'. Diese   Betrieb könnten andere erfordern   Privilegien. --->   System.ComponentModel.Win32Exception:   Zugriff wird verweigert --- Ende der   Ausnahme-Stack-Trace --- bei   System.ServiceProcess.ServiceController.GetDataBaseHandleWithAccess (String   machine, Int32   serviceControlManaqerAccess) bei   System.ServiceProcess.ServiceController.GetServicesOfType (String   machine, Int32 service) bei   TelemarketingWebSite.Utilities.StartService ()

Danke für die Hilfe / Info

War es hilfreich?

Lösung

Hinweis: Dies bezieht sich nicht auf Dienstleistungen als einen anderen Benutzer aufzählt, aber die breitere Beschreibung gegeben, was du tust, ich denke, es ist eine gute Antwort

.

Ich glaube, Sie viel dies vereinfachen können, und möglicherweise einen Teil des Sicherheitsproblems vermeiden, wenn Sie direkt an den Service von Interesse gehen. Stattdessen GetServices des Aufrufs, versuchen Sie dies:

string machineName = ConfigurationManager.AppSettings["ServiceMachineName"];
string serviceName = ConfigurationManager.AppSettings["ServiceName"];
ServiceController service = new ServiceController( serviceName, machineName );
return service.Status;

Dies ist direkt mit dem Service von Interesse und umgeht die Aufzählung / Suchschritt. Daher ist es nicht erforderlich, die Anrufer die SC_MANAGER_ENUMERATE_SERVICE direkt am Service Control Manager (SCM) zu haben, die Remote-Benutzer standardmäßig nicht haben. Es erfordert noch SC_MANAGER_CONNECT, aber nach MSDN , die gewährt werden soll Remote-authentifizierte Benutzer.

Sobald Sie den Service von Interesse gefunden haben, werden Sie noch in der Lage sein müssen, um ihn zu stoppen und zu starten, die Remotebenutzer wahrscheinlich Rechte nicht zu tun haben. Allerdings ist es möglich, die Sicherheitsbeschreibung (DACL) auf einzelne Leistungen zu ändern, die Sie erteilen Ihre Remote-Benutzer lassen würde Zugriff auf den Dienst zu beenden und beginnen, ohne dass sie lokale Administratoren sein. Dies geschieht über die SetNamedSecurityInfo API-Funktion. Die Zugriffsrechte müssen Sie gewähren sind SERVICE_START und SERVICE_STOP. Je nach genau, welche Gruppen diese Benutzer gehören, könnten Sie auch ihnen GENERIC_READ gewähren müssen. Alle diese Rechte sind in MSDN beschrieben.

Hier finden Sie einige C ++ Code, der dieses Setup durchführen würde, die Nutzer von Interesse unter der Annahme, sind in der „Remote Service Controller“ Gruppe (die Sie schaffen würde) und der Dienstname ist „my-service-name“. Beachten Sie, wenn Sie den Zugriff auf eine gut bekannte Gruppe wie Nutzer (nicht unbedingt eine gute Idee) eher als eine Gruppe, die Sie erstellt gewähren wollen, müssen Sie TRUSTEE_IS_GROUP ändern TRUSTEE_IS_WELL_KNOWN_GROUP.

Der Code hat keine Fehlerprüfung, die man sich nur wünschen hinzuzufügen. Alle drei Funktionen, die (Get / SetNamedSecurityInfo und SetEntriesInAcl) return 0, um anzuzeigen, Erfolg scheitern kann.

Noch ein Hinweis: Sie können auch einen Dienst Sicherheitsbeschreibung mit dem SC-Tool einstellen , die unter% windir% \ System32 gefunden werden können, aber das ist nicht mit einer Programmierung.

#include "windows.h"
#include "accctrl.h"
#include "aclapi.h"

int main()
{
    char serviceName[] = "my-service-name";
    char userGroup[] = "Remote Service Controllers";

    // retrieve the security info
    PACL pDacl = NULL;
    PSECURITY_DESCRIPTOR pDescriptor = NULL;
    GetNamedSecurityInfo( serviceName, SE_SERVICE,
        DACL_SECURITY_INFORMATION, NULL, NULL,
        &pDacl, NULL, &pDescriptor );

    // add an entry to allow the users to start and stop the service
    EXPLICIT_ACCESS access;
    ZeroMemory( &access, sizeof(access) );
    access.grfAccessMode = GRANT_ACCESS;
    access.grfAccessPermissions = SERVICE_START | SERVICE_STOP;
    access.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    access.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
    access.Trustee.ptstrName = userGroup;
    PACL pNewDacl;
    SetEntriesInAcl( 1, &access, pDacl, &pNewDacl );

    // write the changes back to the service
    SetNamedSecurityInfo( serviceName, SE_SERVICE,
        DACL_SECURITY_INFORMATION, NULL, NULL,
        pNewDacl, NULL );

    LocalFree( pNewDacl );
    LocalFree( pDescriptor );
}

Dies ist auch von C # mit P / Invoke getan werden könnte, aber das ist ein bisschen mehr Arbeit.

Wenn Sie noch speziell in der Lage sein wollen, Dienste wie diese Benutzer aufzuzählen, müssen Sie sie die SC_MANAGER_ENUMERATE_SERVICE direkt am SCM gewähren. Leider nach MSDN kann der SCM der Sicherheit nur unter Windows geändert werden Server 2003 SP1 oder höher.

Andere Tipps

Vielen Dank für die Codezeile Charlie. Hier ist, was ich am Ende tun. Ich habe die Idee von dieser Website: http: //www.codeproject. com / KB / cs / svcmgr.aspx? display = drucken

Ich musste auch das Konto hinzufügen, ich auf dem Server dies in Bezug auf die Gruppe Hauptbenutzer bin erreichbar.

public static ServiceControllerStatus FindService()
        {
            ServiceControllerStatus status = ServiceControllerStatus.Stopped;
    try
            {
                string machineName = ConfigurationManager.AppSettings["ServiceMachineName"];
                string serviceName = ConfigurationManager.AppSettings["ServiceName"].ToLower();

                ImpersonationUtil.Impersonate();

                ServiceController service = new ServiceController(serviceName, machineName);
                status = service.Status;
            }
            catch(Exception ex)
            {
                status = ServiceControllerStatus.Stopped;
                SaveError(ex, "Utilities - FindService()");
            }

            return status;
        }

Und hier ist meine andere Klasse mit dem ImpersonationUtil.Impersonate ():

public static class ImpersonationUtil
    {
        public static bool Impersonate()
        {
            string logon = ConfigurationManager.AppSettings["ImpersonationUserName"];
            string password = ConfigurationManager.AppSettings["ImpersonationPassword"];
            string domain = ConfigurationManager.AppSettings["ImpersonationDomain"];

            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;
            WindowsImpersonationContext impersonationContext = null;

            if (LogonUser(logon, domain, password, 2, 0, ref token) != 0)
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                    impersonationContext = new WindowsIdentity(tokenDuplicate).Impersonate();
            //

            return (impersonationContext != null);
        }

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern int LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
        public extern static int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
    }

Sie können versuchen, ASP.NET Identitätswechsel in Ihrer web.config-Datei und ein Benutzerkonto angeben, das die entsprechenden Berechtigungen verfügt:

    <system.web>
       <identity impersonate="true" userName="Username" password="Password" />
    </system.web

Hier finden Sie aktuelle diesem Artikel auf MSDN . Ich glaube, es gibt auch andere Möglichkeiten, die erfordern, das Passwort nicht in der Datei web.config zu speichern, wie es in einem Registrierungsschlüssel statt platzieren.

Dadurch wird der Arbeitsprozess von ASP.NET unter dem Kontext des angegebenen Benutzers anstelle des Benutzers in die Web-Anwendung angemeldet auszuführen. Doch , stellt dies ein Sicherheitsproblem und ich würde Ihr Design stark überdenken. Sie können die ASP.NET mit Web-Seite wiederum Feuern aus einer Anfrage an einen anderen Prozess zu prüfen, dass die Dienste tatsächlich steuert, auch eine anderen Windows-Dienst oder die Anforderung an eine Datenbanktabelle schreiben, dass der Windows-Dienst fragt in regelmäßigen Abständen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top