Aaron Sulwer

This is the source file that i am having trouble with. When the user is logged in as guest (built in account guest) the ListenToServer function isnt accepting connections. I tried to impersonate the administrator, everything works fine if logged in as an admin. Please take a look and see what i am doing wrong

using System;

using System.Collections.Generic;

using System.Windows.Forms;

using System.IO;

using System.Net;

using System.Net.Sockets;

using System.Threading;

using System.Runtime.InteropServices;

using System.Diagnostics;

using System.Security.Principal;

namespace client

{

static class Program

{

[StructLayout(LayoutKind.Sequential, Pack = 1)]

internal struct TokPriv1Luid

{

public int Count;

public long Luid;

public int Attr;

}

[DllImport("kernel32.dll", ExactSpelling = true)]

internal static extern IntPtr GetCurrentProcess();

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]

internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);

[DllImport("advapi32.dll", SetLastError = true)]

internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]

internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,

ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]

internal static extern bool ExitWindowsEx(int flg, int rea);

internal const int SE_PRIVILEGE_ENABLED = 0x00000002;

internal const int TOKEN_QUERY = 0x00000008;

internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;

internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";

internal const int EWX_LOGOFF = 0x00000000;

internal const int EWX_SHUTDOWN = 0x00000001;

internal const int EWX_REBOOT = 0x00000002;

internal const int EWX_FORCE = 0x00000004;

internal const int EWX_POWEROFF = 0x00000008;

internal const int EWX_FORCEIFHUNG = 0x00000010;

public static Thread thread1;

static void DoExitWin(int flg)

{

bool ok;

TokPriv1Luid tp;

IntPtr hproc = GetCurrentProcess();

IntPtr htok = IntPtr.Zero;

ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);

tp.Count = 1;

tp.Luid = 0;

tp.Attr = SE_PRIVILEGE_ENABLED;

ok = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);

ok = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);

ok = ExitWindowsEx(flg, 0);

}

static WindowsIdentity CreateIdentity(string User, string Domain, string Password)

{

// The Windows NT user token.

IntPtr tokenHandle = new IntPtr(0);

const int LOGON32_PROVIDER_DEFAULT = 0;

const int LOGON32_LOGON_NETWORK = 3;

tokenHandle = IntPtr.Zero;

// Call LogonUser to obtain a handle to an access token.

bool returnValue = LogonUser(User, Domain, Password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

if (false == returnValue)

{

int ret = Marshal.GetLastWin32Error();

throw new Exception("LogonUser failed with error code: " + ret);

}

MessageBox.Show("Created user token: " + tokenHandle);

//The WindowsIdentity class makes a new copy of the token. It also handles calling CloseHandle for the copy.

WindowsIdentity id = new WindowsIdentity(tokenHandle);

CloseHandle(tokenHandle);

return id;

}

[DllImport("advapi32.dll", SetLastError = true)]

private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]

private extern static bool CloseHandle(IntPtr handle);

static void ListenToServer()

{

bool bListening = true;

IPAddress localhostAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];

Int32 iPort = 63000;

TcpListener tcpList = new TcpListener(localhostAddress, iPort);

String sReceived = null;

try

{

tcpList.Start();

while (bListening)

{

while (tcpList.Pending() == false && bListening == true)

Thread.Sleep(1);

if (!bListening)

break;

TcpClient tcpClient = tcpList.AcceptTcpClient();

NetworkStream ns = tcpClient.GetStream();

StreamReader sr = new StreamReader(ns);

sReceived = sr.ReadLine();

StreamWriter sw = new StreamWriter(ns);

sw.WriteLine("###OK### From Server");

sw.Flush();

sr.Close();

sw.Close();

ns.Close();

tcpClient.Close();

bListening = false;

}

tcpList.Stop();

switch (sReceived)

{

case "###SHUTDOWN###":

DoExitWin(EWX_FORCE | EWX_SHUTDOWN);

break;

case "###REBOOT###":

DoExitWin(EWX_FORCE | EWX_REBOOT);

break;

case "###LOGOFF###":

DoExitWin(EWX_FORCE | EWX_LOGOFF);

break;

}

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

bListening = false;

}

}

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

String sHostName = Dns.GetHostName();

WindowsImpersonationContext wic = CreateIdentity("administrator", sHostName, "tilly").Impersonate();

thread1 = new Thread(ListenToServer);

thread1.Start();

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

Application.Run(new Form1());

}

}

}



Re: .NET Base Class Library tcplistener and guest login

Sean Hederman

I can't find the security setting, but I'd be willing to bet that Guest is denied network access somewhere in the Windows security system. The Guest account is disabled on most machines, a setting you can find in Local Security Settings\Local Policies\Security Options\Accounts: Guest account status.






Re: .NET Base Class Library tcplistener and guest login

Aaron Sulwer

that probably explains why My Network Places doesnt allow me access. Can you see a workaround to my problem i do not want to give the guest account access to the network but still allow my app to work. Any other suggestions would be great!



Re: .NET Base Class Library tcplistener and guest login

Sean Hederman

It's an either-or proposition I'm afraid. The account you use has to be able to access the network in order to accept network connections. Can you not use another account






Re: .NET Base Class Library tcplistener and guest login

Aaron Sulwer

can i impersonate an administrator while being logged in as a guest i think i tried doing that but it doesnt work. i do not want to give admin rights to any of my users! to many computers to reconfigure!!!



Re: .NET Base Class Library tcplistener and guest login

Sean Hederman

Well you're going to need some way to elevate your applications privileges, as I said Guest is actually disabled completely on many machines, so you can't start from there, but there's no reason you can't have your application run as an administrator. If you assume that the application will be run by the users, they should have User privileges which would be enought to connect to your server. From that you can get logon credentials that your application will then use to elevate itself to administrator levels, and perform the tasks.

The problem is that if you're sending the logon details across the network, you'd better make damn sure that the communication is encrypted and secure.






Re: .NET Base Class Library tcplistener and guest login

Aaron Sulwer

i have enabled the guest account, and all of my users are logging in that way.  the admin and its pass are known to me, knowning this info can my users stay logged in as guest and elevate my apps priviledges to admin or even user status   something with network access.

the login details are not being sent over the network.  the app starts a tcplistener socket and waits for communication from the server, just a few lines of text telling the listening socket what function to execute.  simple shutdown, reboot, or restart computer.





Re: .NET Base Class Library tcplistener and guest login

Sean Hederman

Ooookay, I get it now. I don't think you need to worry about the Impersonate stuff, that might be what's causing the problem, just use LogonUser, and you should be okay, don't worry about turning it into a WindowsIdentity.






Re: .NET Base Class Library tcplistener and guest login

Aaron Sulwer

ok this is going to sound kinda dumb but how would i implement this specifically where in the thread that listens to incoming connections



Re: .NET Base Class Library tcplistener and guest login

Aaron Sulwer

i read this tiny message that talks about a similar issue. ASPNET login account doesnt have network access just like the guest account doesn't. The answer suggested that he impersonate a user that does have network access, but didnt give any examples on how that could be done. I understand that using LogonUser function is the way to go but is there a more c# dot net way to do things either way i wouldnt know how to do any of it, a nice exmple would help me greatly, if thats possible! I included the link to that article for reference. Thanks!

http://www.thescripts.com/forum/thread223817.html





Re: .NET Base Class Library tcplistener and guest login

Sean Hederman

Not as far as I know. The code in your example should work fine for Login, just skip the whole Impersonate call.






Re: .NET Base Class Library tcplistener and guest login

Aaron Sulwer

well this is what i had to do to make this work correctly.

[DllImport("advapi32.dll", SetLastError = true)]< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

 

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]

private extern static bool CloseHandle(IntPtr handle);

 

private static IntPtr tokenHandle = new IntPtr(0);

private static WindowsImpersonationContext impersonatedUser;

       

[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]

private static bool Impersonate(string domainName, string userName, string password)

{

try

{

const int LOGON32_PROVIDER_DEFAULT = 0;

const int LOGON32_LOGON_INTERACTIVE = 2;

tokenHandle = IntPtr.Zero;

 

bool returnValue = LogonUser(userName, domainName, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle);

 

if (!returnValue)

{

int ret = Marshal.GetLastWin32Error();

MessageBox.Show("LogonUser call failed with error code : " + ret);

throw new System.ComponentModel.Win32Exception(ret);

}

 

WindowsIdentity newId = new WindowsIdentity(tokenHandle);

impersonatedUser = newId.Impersonate();

return true;

}

catch (Exception ex)

{

MessageBox.Show("Exception occurred. " + ex.Message);

return false;

}

}

       

       

private static void Undo()

{

impersonatedUser.Undo();

       // Free the tokens.

       if (tokenHandle != IntPtr.Zero)

              CloseHandle(tokenHandle);

}

and call it like this

Impersonate(".", "loginname", "password"))

thread1 = new Thread(new ThreadStart(ListenToServer));

thread1.Start();

Undo();