2016-07-18 10 views
0

Ich habe ein Problem beim Erstellen einer Verknüpfung auf einem Server. Es wird immer eine Ausnahme ausgelöst:C#: ShortCut und Identitätswechsel

Zugriff verweigert. 0x80070005

Ich weiß wirklich nicht, ob das Problem auftritt, weil der Verknüpfungsort oder das Verknüpfungsziel.

Ich muss Identitätswechsel verwenden, um auf das Dateisystem zuzugreifen. Mit IO.File und IO.Directory kann ich Verzeichnisse erstellen, kopieren und entfernen, etc ... ohne Probleme. Wenn ich einen Remote-Desktop für das Dateirepository mit dem Benutzer impersonate öffne, kann ich die Verknüpfung mit allen Problemen erstellen.

Allerdings zum Erstellen einer Verknüpfung verwende ich WHSell, und es scheint, dass es einige Probleme mit Identitätswechsel hat. Irgendwelche Ideen?

Dies ist mein Code:

#region Impersonation 
     public const int LOGON32_LOGON_INTERACTIVE = 2; 
     public const int LOGON32_PROVIDER_DEFAULT = 0; 

     [DllImport("advapi32.dll")] 
     public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken); 

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

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern bool RevertToSelf(); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
     public static extern bool CloseHandle(IntPtr handle); 

     private void LogonAsUser(String userName, String domain, String password) 
     { 

      if (!LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle)) 
      { 
       int ret = Marshal.GetLastWin32Error(); 
       throw new System.ComponentModel.Win32Exception(ret); 
      } 
     } 

     private void LogonAsUserEnd(IntPtr token) 
     { 
      if (!IntPtr.Equals(token, IntPtr.Zero)) 
      { 
       CloseHandle(token); 
      } 

     } 

     public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid 
     { 
      private SafeTokenHandle() 
       : base(true) 
      { 
      } 

      [DllImport("kernel32.dll")] 
      [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
      [SuppressUnmanagedCodeSecurity] 
      [return: MarshalAs(UnmanagedType.Bool)] 
      private static extern bool CloseHandle(IntPtr handle); 

      protected override bool ReleaseHandle() 
      { 
       return CloseHandle(handle); 
      } 
     } 
     #endregion 

private void CreateShortCut(string shorcutPath, string shortcutTarget) 
     { 

      IWshRuntimeLibrary.WshShell wshShell = new IWshRuntimeLibrary.WshShell(); 
      IWshRuntimeLibrary.IWshShortcut shortcut; 
      shortcut = (IWshRuntimeLibrary.IWshShortcut)wshShell.CreateShortcut(shorcutPath); 

      shortcut.TargetPath = shortcutTarget; 
      shortcut.WorkingDirectory = shorcutPath; 
      shortcut.Description = "Presupuestos del servicio"; 
      shortcut.Save(); 
     } 

public void CreateServicioRepository(presupuestos p) 
     { 
      LogonAsUser(userName, domain, password); 
      using (safeTokenHandle) 
      { 
       using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle())) 
       { 
        using (WindowsImpersonationContext impersonatedUser = newId.Impersonate()) 
        { 
         try 
         { 
          if (Directory.Exists(serviceBasePath)) // serviceBasePath = "\\myserver\myfolder" 
          { 
           //Creamos el directorio para el servicio 
           string year = p.Fecha_alta.Year.ToString(); 
           string serviceFolderName = p.Codigo + "_" + p.productos.Siglas; 
           if (p.IdObra.HasValue) serviceFolderName += "_" + p.obras.TituloCorto; 
           serviceFolderName = formatePath(serviceFolderName); 

           string servicePaht = Path.Combine(serviceBasePath, year, serviceFolderName); 
           if (!Directory.Exists(servicePaht)) Directory.CreateDirectory(servicePaht); 

           //Comprobamos que existe la carpeta de backend de los informes 
           string presupuestosFolder = getPresupuestoReporthPath(p); //persupuestosFolder = "\\anotherServer\anotherfolder 

           if (!Directory.Exists(presupuestosFolder)) Directory.CreateDirectory(presupuestosFolder); 

           //Creamos el acceso directo a la carpeta de informes generados en presupuesto 
           if (!string.IsNullOrWhiteSpace(presupuestosFolder)) 
           { 
            string shortCutName = "001_" + p.Codigo + "_Presupuesto.lnk"; 
            string shortCutPath = Path.Combine(servicePaht, shortCutName); 

            if (!File.Exists(shortCutPath)) CreateShortCut(shortCutPath, presupuestosFolder); 
           } 

           //Comprobamos que existe la carpeta de backend de los informes 
           string pavoFolder = Path.Combine(System.Configuration.ConfigurationManager.AppSettings["pavoPath"], p.Codigo); 

           if (!Directory.Exists(pavoFolder)) Directory.CreateDirectory(pavoFolder); 

           //Creamos el acceso directo a la carpeta de PAVO 
           if (p.productos.IdModulo == (int)EnumsHelper.Modulos.Obras) 
           { 
            string pavoShortCutName = "002_" + p.Codigo + "_PVOD.lnk"; 
            string pavoShortCutPath = Path.Combine(servicePaht, pavoShortCutName); 

            if (!File.Exists(pavoShortCutPath)) CreateShortCut(pavoShortCutPath, pavoFolder); 
           } 

           //Copiamos las plantilla de la estructura de carpetas del servicio 
           if (Directory.Exists(directoryTemplate) && p.IdEstado == (int)EnumsHelper.EstadoPresupuesto.Aprobado) 
           { 
            foreach (string dirName in Directory.GetDirectories(directoryTemplate)) 
            { 
             if (dirName.Trim().ToLower().Contains(p.productos.Nombre.Trim().ToLower())) 
             { 
              string originalPath = Path.Combine(directoryTemplate, dirName); 
              CopyDirectory(originalPath, servicePaht, p.Codigo); 
              break; 
             } 
            } 
           } 

          } 
         } 
         catch (Exception ex) 
         { 
          LogHelper.Error(ex); 
          throw ex; 
         } 
        } 
       } 
      }      
     } 

Antwort

0

Als Abhilfe können Sie Identitätswechsel deaktivieren und dann den Shell verwenden, um die Verknüpfungsdatei in einem temporären Verzeichnis zu erstellen. Sie können diese Datei dann als Bytearray an den imitierten Code übergeben, wo sie im richtigen Pfad gespeichert werden kann.

public void CreateShortCut(string shorcutPath, string shortcutTarget) 
{ 
    byte[] bytes = null; 

    // Disable impersonation 
    using (System.Security.Principal.WindowsImpersonationContext ctx = System.Security.Principal.WindowsIdentity.Impersonate(IntPtr.Zero)) 
    { 
     // Get a temp file name (the shell commands won't work without .lnk extension) 
     var path = Path.GetTempPath(); 
     string temp = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".lnk"); 
     try 
     { 
      WshShell shell = new WshShell(); 
      IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(temp); 
      shortcut.TargetPath = shortcutTarget; 
      shortcut.Save(); 
      bytes = System.IO.File.ReadAllBytes(temp); 
     } 
     finally 
     { 
      if (System.IO.File.Exists(temp)) System.IO.File.Delete(temp); 
     } 
    } 

    // Impersonation resumed 
    System.IO.File.WriteAllBytes(shorcutPath, bytes); 
} 
+0

Dies gilt nicht für meine Situation. Wenn Sie 'shortcut.Save()' in Ihrem Code verwenden, müssen Sie angeben, dass der Benutzer Zugriff auf den Zielspeicherort hat. Ich kann den Identitätswechsel nicht deaktivieren, weil der IIS_IUSER (der standardmäßig verwendete Benutzer) nicht auf das Zielverzeichnis zugreifen kann, und ich kann keinen Zugriff darauf gewähren. Also diese Zeile löst eine Ausnahme – Rumpelstinsk

+0

Dies sollte funktionieren, solange es ein Verzeichnis gibt, in dem der "Standard" -Benutzer (die Identität, die angenommen wird, wenn der Identitätswechsel deaktiviert ist) Schreibzugriff hat. In meinem Snippet ist dieses "staging" -Verzeichnis das temporäre Verzeichnis, das von 'Path.GetTempPath()' bereitgestellt wird, da es für die Identität meines IIS-Anwendungspools funktioniert hat. – nedmund

Verwandte Themen