views:

1195

answers:

3

I am trying to copy a file from sharepoint to a unc path. I am using the following code:

 var id = new WindowsIdentity("[email protected]");
 var p = new WindowsPrincipal(id);
 var wic = id.Impersonate();
 File.Move(oldName, newName);
 wic.Undo();

oldname is C:\test.txt newName is \\server\folder\test.txt

I am getting the error

A specified logon session does not exist. It may already have been terminated.

How do I go about removing this error OR copy a file from A to B(UNC path) using sharepoint.

+1  A: 

You are not actually getting a logon token to impersonate. You need to call the LogonUser API to get a valid logon token, which you can use to impersonate that user.

See this blog entry for example code in c# on impersonating a windows user. You can also see this KB article that also contains c# code (and a duplicatetoken call for issues with .net 1.0)

Philip Rieck
A: 

The following class will allow you to access SMB shares via a user-name and password. I use it all the time when copying files to network shares in both windows-to-windows and windows-to-unix environments. The benefit here is that you do not need to be authenticate as the user. In essence, you can use credentials that are local only to the target machine.

class WNetConnection : IDisposable
{
 public readonly string RemoteShare;

 public WNetConnection( string remoteHost, string remoteUser, string remotePassword )
 {
  Uri loc;
  if( !Uri.TryCreate( remoteHost, UriKind.Absolute, out loc ) || loc.IsUnc == false )
   throw new ApplicationException( "Not a valid UNC path: " + remoteHost );

  string auth = loc.Host;
  string[] segments = loc.Segments;

  // expected format is '\\machine\share'
  this.RemoteShare = String.Format( @"\\{0}\{1}", auth, segments[1].Trim( '\\', '/' ) );

  this.Connect( remoteUser, remotePassword );
 }

 ~WNetConnection()
 {
  Disconnect();
 }

 public void Dispose()
 {
  Disconnect();
  GC.SuppressFinalize( this );
 }

 #region Win32 API...

 [StructLayout( LayoutKind.Sequential )]
 internal struct NETRESOURCE
 {
  public int dwScope;
  public int dwType;
  public int dwDisplayType;
  public int dwUsage;
  [MarshalAs( UnmanagedType.LPWStr )]
  public string lpLocalName;
  [MarshalAs( UnmanagedType.LPWStr )]
  public string lpRemoteName;
  [MarshalAs( UnmanagedType.LPWStr )]
  public string lpComment;
  [MarshalAs( UnmanagedType.LPWStr )]
  public string lpProvider;
 }

 [DllImport( "mpr.dll", EntryPoint = "WNetAddConnection2W", CharSet = System.Runtime.InteropServices.CharSet.Unicode )]
 private static extern int WNetAddConnection2( ref NETRESOURCE lpNetResource, string lpPassword, string lpUsername, Int32 dwFlags );

 [DllImport( "mpr.dll", EntryPoint = "WNetCancelConnectionW", CharSet = System.Runtime.InteropServices.CharSet.Unicode )]
 private static extern int WNetCancelConnection( string lpRemoteName, bool bForce );

 private const int RESOURCETYPE_ANY = 0x00000000;
 private const int RESOURCETYPE_DISK = 0x00000001;
 private const int CONNECT_INTERACTIVE = 0x00000008;
 private const int CONNECT_PROMPT = 0x00000010;
 private const int NO_ERROR = 0;

 void Connect( string remoteUser, string remotePassword )
 {
  NETRESOURCE ConnInf = new NETRESOURCE();
  ConnInf.dwScope = 0;
  ConnInf.dwType = RESOURCETYPE_DISK;
  ConnInf.dwDisplayType = 0;
  ConnInf.dwUsage = 0;
  ConnInf.lpRemoteName = this.RemoteShare;
  ConnInf.lpLocalName = null;
  ConnInf.lpComment = null;
  ConnInf.lpProvider = null;

  // user must be qualified 'authority\user'
  if( remoteUser.IndexOf( '\\' ) < 0 )
   remoteUser = String.Format( @"{0}\{1}", new Uri(RemoteShare).Host, remoteUser );

  int dwResult = WNetAddConnection2( ref ConnInf, remotePassword, remoteUser, 0 );
  if( NO_ERROR != dwResult )
   throw new Win32Exception( dwResult );
 }

 void Disconnect()
 {
  int dwResult = WNetCancelConnection( this.RemoteShare, true );
  if( NO_ERROR != dwResult )
   throw new Win32Exception( dwResult );
 }

 #endregion
}
csharptest.net
A: 

Thank you for an excellent piece of code -- It worked at the first attempt!

Ulf Lunde