I am writing a piece of code that queries the existing logon sessions on a windows machine. For network logons, I am trying to find the IP address and/or name of the machine from which the logon was done.
I got the list of logon sessions so far by using LsaEnumerateLogonSessions/LsaGetLogonSessionData, but the IP is nowhere to be found in the returned SECURITY_LOGON_SESSION_DATA structure.
How do I get the IP address/machine name of a network logon session?
DateTime systime = new DateTime(1601, 1, 1, 0, 0, 0, 0);
UInt64 sessionCount;
IntPtr luidPtr;
LsaEnumerateLogonSessions(out sessionCount, out luidPtr);
IntPtr iter = luidPtr;
for (ulong i = 0; i < sessionCount; i++)
{
IntPtr sessionData;
LsaGetLogonSessionData(iter, out sessionData);
var data =
(SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(sessionData, typeof(SECURITY_LOGON_SESSION_DATA));
if (data.PSiD != IntPtr.Zero)
{
System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(data.PSiD);
SECURITY_LOGON_TYPE secType = (SECURITY_LOGON_TYPE)data.LogonType;
DateTime logonTime = systime.AddTicks((long)data.LoginTime);
string authpackage = Marshal.PtrToStringUni(data.AuthenticationPackage.buffer);
string domain = Marshal.PtrToStringUni(data.LoginDomain.buffer);
string username = Marshal.PtrToStringUni(data.Username.buffer);
string dnsDomainName = Marshal.PtrToStringUni(data.DnsDomainName.buffer);
string logonServer = Marshal.PtrToStringUni(data.LogonServer.buffer);
string upn = Marshal.PtrToStringUni(data.Upn.buffer);
Console.WriteLine("SID "+sid+" Type: " + secType + "\t" + domain + "\\" + username + "\tTime: " + logonTime);
if (secType == SECURITY_LOGON_TYPE.Network)
{
// TODO get IP/machine name
}
}
iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(LUID)));
LsaFreeReturnBuffer(sessionData);
}
LsaFreeReturnBuffer(luidPtr);
SECURITY_LOGON_SESSION_DATA has a DnsDomainName field:
An LSA_UNICODE_STRING structure that contains the DNS name for the owner of the logon session.
If you need the IP address, do a reverse DNS lookup on that name using gethostbyname() or getaddrinfo().
Alternatively, SECURITY_LOGON_SESSION_DATA also has a Session field. If it is not 0, you can pass it to WTSQuerySessionInformation(), setting the WTSInfoClass parameter to WTSClientAddress and the ppBuffer parameter to the address of a WTS_CLIENT_ADDRESS* pointer variable.
Related
"System.UnauthorizedAccessException" - I've seen this message on my screen for 2 days and just couldn't figured out why.
I've checked all the possible reasons in my knowledge to make it work but fail. Here is the summary of what I have checked:
The file in the shared drive (mapped drive in the local network) is not ready only and the full access permissions are granted to everyone. The folders in the file path are also been set to grant full access permissions to everyone.
I can delete the file manually
the file was created by the same user (me) and I need to delete it when there is a revision. (delete the old one and put the new one in)
when I change the destination folder to local drive (c:..), everything works well. No problems to delete files. But it won't work (System.UnauthorizedAccessException) when I change it to the shared drive (H: drive).
Here are the codes related to the exception:
fdname = inipath + Convert.ToString(ynum);
if (! Directory.Exists(fdname))
System.IO.Directory.CreateDirectory(fdname);
fdname = inipath + Convert.ToString(ynum) + "\\" + Convert.ToString(fpathnum);
if (!Directory.Exists(fdname))
System.IO.Directory.CreateDirectory(fdname);
fdname = inipath + Convert.ToString(ynum) + "\\" + Convert.ToString(fpathnum) + "\\" + Convert.ToString(salodrnum);
if (!Directory.Exists(fdname))
{
System.IO.Directory.CreateDirectory(fdname);
File.SetAttributes(fdname, FileAttributes.Normal);
// File.SetAttributes(fdname, File.GetAttributes(fdname) & ~FileAttributes.ReadOnly); //remove read ony
}
if (File.Exists(fdname + #"\PS" + salodrnum + ".pdf"))
{
File.SetAttributes(fdname + #"\PS" + salodrnum + ".pdf", FileAttributes.Normal);
File.Delete(fdname + #"\PS" + salodrnum + ".pdf");
}
doc.ExportToDisk(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat, fdname + #"\PS" + salodrnum + ".pdf");
File.SetAttributes(fdname + #"\PS" + salodrnum + ".pdf", FileAttributes.Normal);
procForm.Close();
It is a permission issue but I just couldn't figure out where the problem is. Here is the debugging details:
System.UnauthorizedAccessException
HResult=0x80070005
Message=Access to the path 'H:\OrderFiles\21\21003\2100337\PS2100337.pdf' is denied.
Source=mscorlib
StackTrace:
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.File.InternalDelete(String path, Boolean checkHost)
at System.IO.File.Delete(String path)
at OpenOrder.PSForm.crystalReportViewer1_Load(Object sender, EventArgs
e) in C:\SG100sys\Source Codes\OpenOrder\OpenOrder\PSForm.cs:line 188
This exception was originally thrown at this call stack:
[External Code]
OpenOrder.PSForm.crystalReportViewer1_Load(object, System.EventArgs) in PSForm.cs
Probably off-topic, but in case it helps.
I remember having that headache a while ago while trying to replace files on a mapped drive in a machine that had to interact with that and other network locations, often with different credentials. I ended up using a custom impersonation context and passing the domain and credentials each time. I have this method in my FileUtil lib:
public static void InteractWithNetworkFolder(Action MethodThatInteractsWithTheFolder, string Domain, string Username, string Password)
{
var ImpersonationContext = new WrappedImpersonationContext(Domain, Username, Password);
ImpersonationContext.Enter();
MethodThatInteractsWithTheFolder.Invoke();
ImpersonationContext.Leave();
}
In your case, you'd use it like this:
FileUtil.InteractWithNetworkFolder(() => File.Delete(PathToYourFile), Domain, Username, Password)
And the impersonation context (credit to it's creator) looks like this:
public sealed class WrappedImpersonationContext
{
public enum LogonType : int
{
Interactive = 2,
Network = 3,
Batch = 4,
Service = 5,
Unlock = 7,
NetworkClearText = 8,
NewCredentials = 9
}
public enum LogonProvider : int
{
Default = 0, // LOGON32_PROVIDER_DEFAULT
WinNT35 = 1,
WinNT40 = 2, // Use the NTLM logon provider.
WinNT50 = 3 // Use the negotiate logon provider.
}
[DllImport("advapi32.dll", EntryPoint = "LogonUserW", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain,
String lpszPassword, LogonType dwLogonType, LogonProvider dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll")]
public extern static bool CloseHandle(IntPtr handle);
private string _domain, _password, _username;
private IntPtr _token;
private WindowsImpersonationContext _context;
private bool IsInContext
{
get { return _context != null; }
}
public WrappedImpersonationContext(string domain, string username, string password)
{
_domain = String.IsNullOrEmpty(domain) ? "." : domain;
_username = username;
_password = password;
}
// Changes the Windows identity of this thread. Make sure to always call Leave() at the end.
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public void Enter()
{
if (IsInContext)
return;
_token = IntPtr.Zero;
bool logonSuccessfull = LogonUser(_username, _domain, _password, LogonType.NewCredentials, LogonProvider.WinNT50, ref _token);
if (!logonSuccessfull)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
WindowsIdentity identity = new WindowsIdentity(_token);
_context = identity.Impersonate();
Debug.WriteLine(WindowsIdentity.GetCurrent().Name);
}
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public void Leave()
{
if (!IsInContext)
return;
_context.Undo();
if (_token != IntPtr.Zero)
{
CloseHandle(_token);
}
_context = null;
}
}
Please try to check for less convoluted solutions before jumping into this one.
I am using the following code to get and set environment variables.
public static string Get( string name, bool ExpandVariables=true ) {
if ( ExpandVariables ) {
return System.Environment.GetEnvironmentVariable( name );
} else {
return (string)Microsoft.Win32.Registry.LocalMachine.OpenSubKey( #"SYSTEM\CurrentControlSet\Control\Session Manager\Environment\" ).GetValue( name, "", Microsoft.Win32.RegistryValueOptions.DoNotExpandEnvironmentNames );
}
}
public static void Set( string name, string value ) {
System.Environment.SetEnvironmentVariable( name, value );
}
The problem I face, is even when the program is running as administrator, the environment variable lasts only as long as the program is running. I have confirmed this by running a Get on the variable I set in a previous instance.
Example usage of above
Set("OPENSSL_CONF", #"c:\openssl\openssl.cfg");
And to retrieve
MessageBox.Show( Get("OPENSSL_CONF") );
While the program is running, after using Set, the value is returned using Get without any issue. The problem is the environment variable isn't permanent (being set on the system).
It also never shows up under advanced properties.
Thanks in advance.
While the program is running, after using Set, the value is returned
using Get without any issue. The problem is the environment variable
isn't permanent (being set on the system).
Thats because the overload of SetEnvironmentVariable that you're using stores in the process variables. From the docs:
Calling this method is equivalent to calling the
SetEnvironmentVariable(String, String, EnvironmentVariableTarget)
overload with a value of EnvironmentVariableTarget.Process for the
target argument.
You need to use the overload specifying EnvironmentVariableTarget.Machine instead:
public static void Set(string name, string value)
{
Environment.SetEnvironmentVariable(name, value, EnvironmentVariableTarget.Machine);
}
According to MSDN the method you are using is just modifying the variable for the runtime of the process.
Try the overload described here: https://msdn.microsoft.com/library/96xafkes%28v=vs.110%29.aspx
This kind of question has already been asked multiple times, check the following links for more information:
Set Env Variable - 1
Set Env Variable - 2
Set Env Variable - Tutorial
Here's an example that permanently updates the User PATH variable by programmatically editing the registry:
// Admin Permission not-required:
// HKCU\Environment\Path
// Admin Permission required:
// HKLM\SYSTEM\CurrentControlSet\Control
// \Session Manager\Environment\Path
public static void UserPathAppend(string path, int verbose=1) {
string oldpath = UserPathGet();
List<string> newpathlist = oldpath.Split(';').ToList();
newpathlist.Add(path);
string newpath = String.Join(";", newpathlist.ToArray());
UserPathSet(newpath);
UpdateEnvPath();
if (verbose!=0) {
System.Windows.MessageBox.Show(
"PATH APPEND:\n\n"
+ path + "\n\n"
+ "OLD HKCU PATH:\n\n"
+ oldpath + "\n\n"
+ "NEW HKCU PATH:\n\n"
+ newpath + "\n\n"
+ "REGISTRY KEY MODIFIED:\n\n"
+ "HKCU\\Environment\\Path\n\n"
+ "NOTE:\n\n"
+ "'Command Path' is a concat of 'HKLM Path' & 'HKCU Path'.\n",
"Updated Current User Path Environment Variable"
);
}
}
public static void UserPathPrepend(string path, int verbose=1) {
string oldpath = UserPathGet();
List<string> newpathlist = oldpath.Split(';').ToList();
newpathlist.Insert(0, path);
string newpath = String.Join(";", newpathlist.ToArray());
UserPathSet(newpath);
UpdateEnvPath();
if (verbose != 0) {
System.Windows.MessageBox.Show(
"PATH PREPEND:\n\n"
+ path + "\n\n"
+ "OLD HKCU PATH:\n\n"
+ oldpath + "\n\n"
+ "NEW HKCU PATH:\n\n"
+ newpath + "\n\n"
+ "REGISTRY KEY MODIFIED:\n\n"
+ "HKCU\\Environment\\Path\n\n"
+ "NOTE:\n\n"
+ "'Command Path' is a concat of 'HKLM Path' & 'HKCU Path'.\n",
"Updated Current User Path Environment Variable"
);
}
}
public static string UserPathGet()
{
// Reads Registry Path "HKCU\Environment\Path"
string subKey = "Environment";
Microsoft.Win32.RegistryKey sk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(subKey);
if (sk == null)
return null;
else
return sk.GetValue("Path").ToString();
}
public static void UserPathSet(string newpath)
{
// Writes Registry Path "HKCU\Environment\Path"
string subKey = "Environment";
Microsoft.Win32.RegistryKey sk1 = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(subKey);
sk1.SetValue("Path", newpath);
}
//===========================================================
// Private: This part required if you don't want to logout
// and login again to see Path Variable update
//===========================================================
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr SendMessageTimeout(IntPtr hWnd,
uint Msg, UIntPtr wParam, string lParam,
SendMessageTimeoutFlags fuFlags,
uint uTimeout, out UIntPtr lpdwResult);
private enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0, SMTO_BLOCK = 0x1,
SMTO_ABORTIFHUNG = 0x2, SMTO_NOTIMEOUTIFNOTHUNG = 0x8
}
private static void UpdateEnvPath() {
// SEE: https://support.microsoft.com/en-us/help/104011/how-to-propagate-environment-variables-to-the-system
// Need to send WM_SETTINGCHANGE Message to
// propagage changes to Path env from registry
IntPtr HWND_BROADCAST = (IntPtr)0xffff;
const UInt32 WM_SETTINGCHANGE = 0x001A;
UIntPtr result;
IntPtr settingResult
= SendMessageTimeout(HWND_BROADCAST,
WM_SETTINGCHANGE, (UIntPtr)0,
"Environment",
SendMessageTimeoutFlags.SMTO_ABORTIFHUNG,
5000, out result);
}
This question already has answers here:
C# accessing active directory with different user credentials
(4 answers)
Closed 9 years ago.
Just a quick question here. Does anyone how can I set the access a difference server folder with username and password in c# .net?
I have have the following code to upload a file into a folder in the other server. Somehow I need to use the username and password then I can be only able to access into this folder. Does anyone know the code to set the access username and password for the folder?
private void uploadFile()
{
DateTime dateTime = DateTime.Now;
string sDate = dateTime.ToString("yyyyMMdd") + "_" + dateTime.ToString("fffffff");
string fn = System.IO.Path.GetFileName(File1.PostedFile.FileName);
string SaveLocation = Server.MapPath("document") + "\\" + sDate + "_" + fn;
supportFileName = sDate + "_" + fn;
try
{
File1.PostedFile.SaveAs(SaveLocation);
}
catch (Exception ex)
{
err.Text = "Error: " + ex.Message;
}
}
for access the different server , and upload file into it.
first, you need to give correct rights to this user account, and impersonation this account.
The term "Impersonation" in a programming context refers to a technique that executes the code under another user context than the user who originally started an application, i.e. the user context is temporarily changed once or multiple times during the execution of an application.
here are two article, hope can help you, with the sample codes:
http://www.codeproject.com/Articles/4051/Windows-Impersonation-using-C
http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User
using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
...
<code that executes under the new context>
...
}
public WindowsImpersonationContext
ImpersonateUser(string sUsername, string sDomain, string sPassword)
{
// initialize tokens
IntPtr pExistingTokenHandle = new IntPtr(0);
IntPtr pDuplicateTokenHandle = new IntPtr(0);
pExistingTokenHandle = IntPtr.Zero;
pDuplicateTokenHandle = IntPtr.Zero;
// if domain name was blank, assume local machine
if (sDomain == "")
sDomain = System.Environment.MachineName;
try
{
string sResult = null;
const int LOGON32_PROVIDER_DEFAULT = 0;
// create token
const int LOGON32_LOGON_INTERACTIVE = 2;
//const int SecurityImpersonation = 2;
// get handle to token
bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref pExistingTokenHandle);
// did impersonation fail?
if (false == bImpersonated)
{
int nErrorCode = Marshal.GetLastWin32Error();
sResult = "LogonUser() failed with error code: " +
nErrorCode + "\r\n";
// show the reason why LogonUser failed
MessageBox.Show(this, sResult, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
// Get identity before impersonation
sResult += "Before impersonation: " +
WindowsIdentity.GetCurrent().Name + "\r\n";
bool bRetVal = DuplicateToken(pExistingTokenHandle,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
ref pDuplicateTokenHandle);
// did DuplicateToken fail?
if (false == bRetVal)
{
int nErrorCode = Marshal.GetLastWin32Error();
// close existing handle
CloseHandle(pExistingTokenHandle);
sResult += "DuplicateToken() failed with error code: "
+ nErrorCode + "\r\n";
// show the reason why DuplicateToken failed
MessageBox.Show(this, sResult, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
else
{
// create new identity using new primary token
WindowsIdentity newId = new WindowsIdentity
(pDuplicateTokenHandle);
WindowsImpersonationContext impersonatedUser =
newId.Impersonate();
// check the identity after impersonation
sResult += "After impersonation: " +
WindowsIdentity.GetCurrent().Name + "\r\n";
MessageBox.Show(this, sResult, "Success",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return impersonatedUser;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
// close handle(s)
if (pExistingTokenHandle != IntPtr.Zero)
CloseHandle(pExistingTokenHandle);
if (pDuplicateTokenHandle != IntPtr.Zero)
CloseHandle(pDuplicateTokenHandle);
}
}
Runnnig this code getting this error, could any one help figure out what is going on here?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace LSATest
{
class Program
{
public static List<string> listBox1 = new List<string>();
static void Main(string[] args)
{
DateTime systime = new DateTime(1601, 1, 1, 0, 0, 0, 0); //win32 systemdate
UInt64 count;
IntPtr luidPtr = IntPtr.Zero;
LSAClass.LsaEnumerateLogonSessions(out count, out luidPtr); //gets an array of pointers to LUIDs
IntPtr iter = luidPtr; //set the pointer to the start of the array
for (ulong i = 0; i < count; i++) //for each pointer in the array
{
IntPtr sessionData;
LSAClass.LsaGetLogonSessionData(iter, out sessionData);
LSAClass.SECURITY_LOGON_SESSION_DATA data = (LSAClass.SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(sessionData, typeof(LSAClass.SECURITY_LOGON_SESSION_DATA));
//if we have a valid logon
if (data.PSiD != IntPtr.Zero)
{
//get the security identifier for further use
System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(data.PSiD);
//extract some useful information from the session data struct
string username = Marshal.PtrToStringUni(data.Username.buffer).Trim(); //get the account username
string domain = Marshal.PtrToStringUni(data.LoginDomain.buffer).Trim(); //domain for this account
string authpackage = Marshal.PtrToStringUni(data.AuthenticationPackage.buffer).Trim(); //authentication package
LSAClass.SECURITY_LOGON_TYPE secType = (LSAClass.SECURITY_LOGON_TYPE)data.LogonType;
DateTime time = systime.AddTicks((long)data.LoginTime); //get the datetime the session was logged in
//do something with the extracted data, ie, add to a display control....
listBox1.Add("User: " + username + " *** Domain: " + domain + " *** Login Type: (" + data.LogonType + ") " + secType.ToString() + " *** Login Time: " + time.ToLocalTime().ToString());
}
iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(LSAClass.LUID))); //move the pointer forward
LSAClass.LsaFreeReturnBuffer(sessionData); //free the SECURITY_LOGON_SESSION_DATA memory in the struct
}
LSAClass.LsaFreeReturnBuffer(luidPtr); //free the array of LUIDs
}
}
}
The error is because sessionData is null. That's because LsaGetLogonSessionData is failing. To diagnose this further, you need to start paying attention to the return value of the API functions and checking error codes in case of failure. That's your next step.
As an aside, you have declared the count variable incorrectly. In the C header file it is declared as ULONG. That's an unsigned 32 bit integer which makes it uint in C#. I've not checked anything more than this.
I'm trying to check if computer on the net is online by using code which supposedly to check it by using ARP packets.
I am always getting message that host is offline even when I'm sure that it's online. I have checked on my localhost IP and on some always working IPs such as google.
That could be wrong with this code?
[DllImport("iphlpapi.dll", ExactSpelling = true)]
public static extern int SendARP(IPAddress DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen);
private byte[] macAddr = new byte[6];
private uint macAddrLen;
private void Ping(IPAddress address)
{
if (SendARP(address, 0, new byte[6], ref macAddrLen) == 0)
{
open++;
txtDisplay.AppendText("Host " + address + " is open." + Environment.NewLine);
}
else
{
closed++;
txtDisplay.AppendText("Host " + address + " is closed." + Environment.NewLine);
}
}
By using previous code I'm basically trying to do something like following code. But the problem with this code is that when host is closed that it takes like 2 seconds to get the respond which I want to eliminate. Someone suggested to use ARP ping:
private void Ping(IPAddress address)
{
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
if (cbDontFragment.Checked) options.DontFragment = true;
else options.DontFragment = false;
string dataa = string.Empty;
int dataCounter = 0;
options.Ttl = (int)nudTTL.Value;
for (int i = 0; i < nudData.Value; i++)
{
dataCounter++;
if (dataCounter == 10) dataCounter = 0;
dataa += dataCounter.ToString();
}
byte[] buffer = Encoding.ASCII.GetBytes(dataa);
int timeout = 120;
try
{
PingReply reply = pingSender.Send(address, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
open++;
txtDisplay.AppendText("Host " + address + " is open. ");
if (cbDontFragment.Checked) txtDisplay.AppendText(" Don't fragment. ");
txtDisplay.AppendText(" TTL: " + options.Ttl.ToString() + " ");
txtDisplay.AppendText(" Bytes: " + nudData.Value + " ");
txtDisplay.AppendText(Environment.NewLine);
}
else
{
closed++;
txtDisplay.AppendText("Host " + address + " is closed. ");
if (cbDontFragment.Checked) txtDisplay.AppendText(" Don't fragment. ");
txtDisplay.AppendText(" TTL: " + options.Ttl.ToString() + " ");
txtDisplay.AppendText(" Bytes: " + nudData.Value + " ");
txtDisplay.AppendText(Environment.NewLine);
}
}
catch (Exception ex)
{
txtDisplay.SelectedText += Environment.NewLine + ex.Message;
}
}
ARP cannot be used for what you are trying to do. It only works over a local network.
It's purpose is to resolve an IP address (which is routed) to a MAC address (which is not). It is never sent beyond a network segment (a lan)