2013-04-02 9 views
5

Wie kann ich einem bestimmten Benutzer (wahrscheinlich dem NET SERVICE-Benutzer) erlauben, einen bestimmten Dienst zu starten und zu stoppen, nur mit C# -Code.Wie man einem Benutzer die Erlaubnis gibt, einen bestimmten Dienst mit C# -Code zu starten und zu stoppen

ich den resultierenden Code müssen auf alles von Windows XP auf Windows 8.

[Bearbeiten] ich bereits einen Dienst zu arbeiten, die, und eine Installationsroutine, die Ordnerberechtigungen setzt, installiert den Dienst funktioniert, startet es usw.

Der Dienst überprüft eine URL, um zu sehen, ob es ein Update gibt, und wenn dies der Fall ist, lädt es das Programm herunter und startet ein Aktualisierungsprogramm, um den Dienst zu aktualisieren (und beendet sich).

Das Aktualisierungsprogramm aktualisiert den Dienst exe (und andere benötigte Dateien) und muss den Dienst neu starten.

Ich weiß aus der Forschung, dass es möglich ist, dem Dienstbenutzer (NETZWERKDIENST in diesem Fall) die Erlaubnis zu geben, einen einzelnen Dienst zu starten und zu beenden, aber ich kenne die API nicht, um es in Code zu tun.

+3

gut Sie konnte kein Dienstkonto für diesen Benutzer erstellen? Was hast du zur Zeit? Denk daran: "SO ist keine Code Factory", du musst etwas auf eigene Faust versuchen und dann zurückmelden, welche Probleme du hast und andere werden mehr als glücklich sein, dir zu helfen, andere nicht zu erwarten Mach dein "Arbeit für dich" – MethodMan

+0

Ich brauche nur ein paar Hinweise. Was ist ein Dienstkonto? –

+0

Habe gerade nachgeschaut. Nicht sicher, ob es relevant ist, denn die Frage lautet dann: "Wie gebe ich meinem Dienstkonto die Erlaubnis, einen Dienst zu starten und zu beenden". Oder fehlt mir etwas? –

Antwort

6

bekam ich ein paar Hinweise aus anderen Ländern, und schaffte es herauszufinden:

[StructLayoutAttribute(LayoutKind.Sequential)] 
struct SECURITY_DESCRIPTOR { 
    public byte revision; 
    public byte size; 
    public short control; 
    public IntPtr owner; 
    public IntPtr group; 
    public IntPtr sacl; 
    public IntPtr dacl; 
} 

[DllImport("advapi32.dll", SetLastError = true)] 
static extern bool QueryServiceObjectSecurity(IntPtr serviceHandle, 
    System.Security.AccessControl.SecurityInfos secInfo, 
    ref SECURITY_DESCRIPTOR lpSecDesrBuf, 
    uint bufSize, 
    out uint bufSizeNeeded); 

[DllImport("advapi32.dll", SetLastError = true)] 
static extern bool QueryServiceObjectSecurity(SafeHandle serviceHandle, 
    System.Security.AccessControl.SecurityInfos secInfo, 
    byte[] lpSecDesrBuf, 
    uint bufSize, 
    out uint bufSizeNeeded); 

[DllImport("advapi32.dll", SetLastError = true)] 
static extern bool SetServiceObjectSecurity(SafeHandle serviceHandle, 
    System.Security.AccessControl.SecurityInfos secInfos, 
    byte[] lpSecDesrBuf); 

public void SetServicePermissions(string service, string username) { 
    System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController(service, "."); 
    ServiceControllerStatus status = sc.Status; 
    byte[] psd = new byte[0]; 
    uint bufSizeNeeded; 
    bool ok = QueryServiceObjectSecurity(sc.ServiceHandle, SecurityInfos.DiscretionaryAcl, psd, 0, out bufSizeNeeded); 
    if (!ok) { 
     int err = Marshal.GetLastWin32Error(); 
     if (err == 122 || err == 0) { // ERROR_INSUFFICIENT_BUFFER 
      // expected; now we know bufsize 
      psd = new byte[bufSizeNeeded]; 
      ok = QueryServiceObjectSecurity(sc.ServiceHandle, SecurityInfos.DiscretionaryAcl, psd, bufSizeNeeded, out bufSizeNeeded); 
     } else { 
      throw new ApplicationException("error calling QueryServiceObjectSecurity() to get DACL for " + _name + ": error code=" + err); 
     } 
    } 
    if (!ok) 
     throw new ApplicationException("error calling QueryServiceObjectSecurity(2) to get DACL for " + _name + ": error code=" + Marshal.GetLastWin32Error()); 

    // get security descriptor via raw into DACL form so ACE 
    // ordering checks are done for us. 
    RawSecurityDescriptor rsd = new RawSecurityDescriptor(psd, 0); 
    RawAcl racl = rsd.DiscretionaryAcl; 
    DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, racl); 

    // Add start/stop/read access 
    NTAccount acct = new NTAccount(username); 
    SecurityIdentifier sid = (SecurityIdentifier) acct.Translate(typeof(SecurityIdentifier)); 
    // 0xf7 is SERVICE_QUERY_CONFIG|SERVICE_CHANGE_CONFIG|SERVICE_QUERY_STATUS| 
    // SERVICE_START|SERVICE_STOP|SERVICE_PAUSE_CONTINUE|SERVICE_INTERROGATE 
    dacl.AddAccess(AccessControlType.Allow, sid, 0xf7, InheritanceFlags.None, PropagationFlags.None); 

    // convert discretionary ACL back to raw form; looks like via byte[] is only way 
    byte[] rawdacl = new byte[dacl.BinaryLength]; 
    dacl.GetBinaryForm(rawdacl, 0); 
    rsd.DiscretionaryAcl = new RawAcl(rawdacl, 0); 

    // set raw security descriptor on service again 
    byte[] rawsd = new byte[rsd.BinaryLength]; 
    rsd.GetBinaryForm(rawsd, 0); 
    ok = SetServiceObjectSecurity(sc.ServiceHandle, SecurityInfos.DiscretionaryAcl, rawsd); 
    if (!ok) { 
     throw new ApplicationException("error calling SetServiceObjectSecurity(); error code=" + Marshal.GetLastWin32Error()); 
    } 
} 
+0

"Ändern der DACL für einen Dienst" https://msdn.microsoft.com/en-us/library/windows/desktop/ms684215(v=vs.85).aspx – Liviu

Verwandte Themen