/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 *  Author: Jim Norman
 *
 ***********************************************************************/

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace Novell.Casa.Client.Auth
{
	/// <summary>
	/// Summary description for Class1.
	/// </summary>
	public class Authtoken
	{
		private const string AUTH_LIBRARY = "C:\\Program Files\\Novell\\CASA\\lib\\authtoken";
		private const int BUFFER_OVERFLOW = 6;

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
		public struct LUID
		{	
			public int luidLow;
			public int luidHigh;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
		public class SSCS_EXT_T
		{
			public int			extID = 0; 		// defined to identify the extension 
			public int			version = 0;	// defined as the version of the specified extension
			public IntPtr		ext;			// points to the actual extension
		} ;

		[DllImport(AUTH_LIBRARY, CharSet=CharSet.None) ]
		private static extern int ObtainAuthToken
		(
			[In]		byte[] 			baService,		
			[In]		byte[]  		baHost,
			[In, Out]	byte[]	 		baToken,							
			[In, Out]	ref int 		iTokenLength
		);

		[DllImport(AUTH_LIBRARY, CharSet=CharSet.None) ]
		private static extern int ObtainAuthTokenEx
		(
			[In]		byte[] 			baService,		
			[In]		byte[]  		baHost,
			[In, Out]	byte[]	 		baToken,							
			[In, Out]	ref int 		iTokenLength,
			[In]		SSCS_EXT_T		ext
		);


		public Authtoken()
		{
		}


		public static byte[] ObtainAuthToken(string sService, string sHost)
		{
			return ObtainAuthToken(sService, sHost, null);
		}

		public static byte[] ObtainAuthToken(string sService, string sHost, WinLuid luid)
		{
			int rcode = 0;
			byte[] baService = null;
			byte[] baHost =  null;			
			int bufferSize = 0;			
			bool bLuidPassedIn = false;

			byte[] baToken = new byte[bufferSize];

			// convert service to ascii byte array
			if (sService != null)
			{
				baService = Encoding.ASCII.GetBytes(sService);
			}
			else
			{
				throw new Exception("Invalid parameter");
			}

			// convert host to ascii byte array
			if (sHost != null)
			{
				baHost = Encoding.ASCII.GetBytes(sHost);
			}
			else
			{
				throw new Exception("Invalid parameter");
			}
			

			SSCS_EXT_T ext = new SSCS_EXT_T();
			if ((luid.GetHighPart() != 0) || (luid.GetLowPart() != 0))
			{
				// allocate a structure to marshal
				LUID sluid = new LUID();
				sluid.luidHigh = luid.GetHighPart();
				sluid.luidLow = luid.GetLowPart();
				
				ext.extID = 1;
				ext.version = 1;
				ext.ext = Marshal.AllocHGlobal(Marshal.SizeOf(sluid));

				Marshal.StructureToPtr(sluid, ext.ext, false);
				bLuidPassedIn = true;
			}

			
			// call with buffersize of 0.  This way we determine the exact size.
			try
			{
				if (bLuidPassedIn)
				{	
					rcode = ObtainAuthTokenEx(baService, baHost, baToken, ref bufferSize, ext);
				}
				else
				{
					rcode = ObtainAuthToken(baService, baHost, baToken, ref bufferSize);
				}
				
				int test = (rcode & BUFFER_OVERFLOW);
				if (test == BUFFER_OVERFLOW)
				{				
					// now allocate the proper size
					baToken = new byte[bufferSize];
					rcode = ObtainAuthToken(baService, baHost, baToken, ref bufferSize);
				}
			}
			catch (Exception e)
			{
				LogMessage(e.ToString());
				return null;
			}
									
			if (ext.ext != IntPtr.Zero)
				Marshal.FreeHGlobal(ext.ext);

			if (rcode != 0)
			{				
				throw new Exception(rcode.ToString());
			}
			else
			{
				return baToken;
			}			
		}

		private static void LogMessage(string sMessage)
		{
			System.Diagnostics.Trace.WriteLine("(C#)AuthToken: " + sMessage);
		}
	}
}