I have been banging my head against the wall for a while now, and can't
seem to id the problem. I've been through a ton of posts and the code
doesn't seem any different. Can anybody see it?
When I call to GetTokenInformation I receive a buffer size (see
//HERE... comment in code), but when I let the code continue, asp.net
just sits there returning nothing, apparently on the
Marshal.AllocHGlobal call.
Here's the library function:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
using System;
using System.Collections.Specialized;
using System.DirectoryServices;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text.RegularExpressions;
namespace foobar.Library
{
public class AdFunctions
{
enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin
}
public struct TOKEN_USER
{
public SID_AND_ATTRIBUTES User; // a single SID_AND_ATTRIBUTES
struct
}
public struct TOKEN_GROUPS
{
public int GroupCount; // DWORD number of groups
public SID_AND_ATTRIBUTES[] Groups; // array of SID_AND_ATTRIBUTES
structs
}
public struct SID_AND_ATTRIBUTES
{
public IntPtr Sid; // pointer to a sid
public int Attributes; // DWORD attributes
}
//[DllImport("advapi32.dll", CharSet=CharSet.Auto)]
//static extern bool ConvertSidToStringSid( IntPtr pSID,
[In,Out,MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid);
// Using IntPtr for pSID insted of Byte[]
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
static extern bool ConvertSidToStringSid(IntPtr pSID, out IntPtr
pSid);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
static extern bool ConvertStringSidToSid( string sStringSid, out
IntPtr pSID );
[DllImport("advapi32.dll", SetLastError=true)]
static extern bool GetTokenInformation(
IntPtr TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
IntPtr TokenInformation,
int TokenInformationLength,
out int ReturnLength);
[DllImport("kernel32.dll")]
static extern IntPtr LocalFree(IntPtr hMem);
public int GetGroupSidsFromToken(IntPtr pToken, ref string[] aSids)
{
int iTokenInfoLength = 0;
bool bResult = true;
// first call gets length of TokenInformation
bResult = GetTokenInformation( pToken,
TOKEN_INFORMATION_CLASS.TokenGroups, IntPtr.Zero, 0, out
iTokenInfoLength );
//HERE if I uncomment this, the call returns an integer rapidly
//return iTokenInfoLength;
// if we got a return, continue
if ( iTokenInfoLength > 0 )
{
// allocate a memory buffer for the TokenInformation
IntPtr pTokenInfo = Marshal.AllocHGlobal( iTokenInfoLength );
// get the TokenInformation
bResult = GetTokenInformation( pToken,
TOKEN_INFORMATION_CLASS.TokenGroups , pTokenInfo, iTokenInfoLength, out
iTokenInfoLength ) ;
if ( bResult == false ) { return 2; }
// convert the TokenInformation to a TOKEN_GROUPS struct
TOKEN_GROUPS TokenGroups = ( TOKEN_GROUPS )Marshal.PtrToStructure(
pTokenInfo , typeof( TOKEN_GROUPS ) ) ;
// loop through the groups
for ( int i=0; i < TokenGroups.GroupCount; i++ )
{
IntPtr pSid = IntPtr.Zero;
// get the string representation of the sid
bResult = ConvertSidToStringSid( TokenGroups.Groups[i].Sid, out
pSid );
if ( bResult == false ) { return 3; }
// put it into a c# string and free the memory
string sSid = Marshal.PtrToStringAuto( pSid );
LocalFree(pSid);
// add it to the array reference
aSids[i] = sSid;
}
}
else
{
// GetTokenInformation returned a 0 length
return 1;
}
// all set
return 0;
}
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
Here's the code behind file that calls it:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Security.Principal;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using foobar.Library;
namespace Users
{
/// <summary>
/// Summary description for WebForm1.
/// </summary>
public class Default : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Label lblStatusLine;
private void Page_Load(object sender, System.EventArgs e)
{
Trace.Write("debug", "Page_Load: entered function");
Trace.Write("debug", "Page_Load: user id is " +
System.Web.HttpContext.Current.User.Identity.Name. ToString() );
Trace.Write("debug", "Page_Load: process id is " +
WindowsIdentity.GetCurrent().Name.ToString() );
string[] aSids = new string[200];
Trace.Write("debug", "Page_Load: created array" );
AdFunctions oAdFunctions = new AdFunctions();
Trace.Write("debug", "Page_Load: created AdFunctions object" );
int iReturn =
oAdFunctions.GetGroupSidsFromToken(WindowsIdentity .GetCurrent().Token,
ref aSids);
Trace.Write("debug", "Page_Load: AdFunctions.GetGroupSidsFromToken
returned " + iReturn.ToString() );
if ( iReturn == 0 )
{
// TODO color the output
lblStatusLine.Text = "ok...";
}
else
{
lblStatusLine.Text = Application["ProductName"] + " could not
retrive your logon groups. Please contact your administrator
(GetGroupSidsFromToken:" + iReturn.ToString() + ").";
}
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
and finally the aspx page:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~
<%@ Page language="c#" Codebehind="Default.aspx.cs"
AutoEventWireup="false" Inherits="Users.Default" Trace="True"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<asp:Label id="lblStatusLine" style="Z-INDEX: 101; LEFT: 160px;
POSITION: absolute; TOP: 760px"
runat="server" Width="872px"></asp:Label>
</form>
</body>
</HTML>