Add code to Novell.Casa.MiCall.dll to allow access to SERVER_KEY_CHAIN.

Windows only change.
This commit is contained in:
Jim Norman 2008-05-12 17:42:41 +00:00
parent 83e1a14664
commit 7cfc9a8114
5 changed files with 2051 additions and 1440 deletions

View File

@ -1,3 +1,9 @@
-------------------------------------------------------------------
Mon May 11 11:38:53 MDT 2008 - jnorman@novell.com
- Add code to Novell.Casa.MiCasa.dll to allow access
to server key chain. Windows only.
-------------------------------------------------------------------
Mon May 5 11:51:53 MDT 2008 - jnorman@novell.com

View File

@ -22,6 +22,7 @@
using System;
using System.Collections.Specialized;
using Novell.Casa;
namespace Novell.Casa
@ -42,6 +43,9 @@ namespace Novell.Casa
private static uint SSCS_CRED_TYPE_BINARY_F = 0x00000002;
private static uint SSCS_CRED_TYPE_SERVER_F = 0x00000004;
public static string SESSION_KEY_CHAIN = "SSCS_SESSION_KEY_CHAIN_ID";
public static string SERVER_KEY_CHAIN = "SSCS_SERVER_KEY_CHAIN_ID";
public MiCasa()
{
//
@ -186,5 +190,25 @@ namespace Novell.Casa
{
NativeCalls.miCASAMergeCache(srcLuid, destLuid, bDestroySrcCache);
}
public static StringCollection GetSecretIDs()
{
return GetSecretIDs(SESSION_KEY_CHAIN);
}
public static StringCollection GetSecretIDs(String sKeyChainID)
{
return NativeCalls.EnumerateSecretIDs(0, sKeyChainID, "");
}
public static Secret GetSecret(String sSecretID)
{
return GetSecret(SESSION_KEY_CHAIN, sSecretID);
}
public static Secret GetSecret(String sKeyChainID, String sSecretID)
{
return NativeCalls.GetSecret(sKeyChainID, 0, sSecretID, Secret.SS_CREDSET, null);
}
}
}

View File

@ -129,6 +129,39 @@ namespace Novell.Casa
public int luidHigh;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_SRCH_KEY_T
{
public uint srchKeyLen;
[MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
public string srchKey; //[NSSCS_MAX_SRCH_KEY_LEN]; //* should be passed in # of chars
} ;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_SECRET_ID_LIST_T
{
public uint enumHandle;
public uint returnedIDs;
public IntPtr secretIDList; //* an array of secretID structures
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_SH_SECRET_ID_LIST_T
{
public uint enumHandle;
public uint returnedIDs;
public IntPtr secretIDList; //* an array of secretID structures
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_READEXT_T
{
public uint statFlags; //* OUT - return flags on the secret
public uint crtStamp; //* OUT - secret creation time stamp
public uint latStamp; //* OUT - last accessed time stamp (optional)
public uint lmtStamp; //* OUT - last modified time stamp
};
// * The following functions will be exposed as exported API:
// **************************************************************
// * These function calls will utilize the Support Functions for
@ -137,6 +170,18 @@ namespace Novell.Casa
private const string NDK_LIBRARY = "micasa";
[DllImport(NDK_LIBRARY)]
internal static extern int miCASAEnumerateSecretIDs
(
[In] IntPtr context,
[In] SSCS_KEYCHAIN_ID_T keyChainID,
[In] uint ssFlags,
[In] SSCS_SRCH_KEY_T searchKey,
[In, Out] SSCS_SH_SECRET_ID_LIST_T secretIDList,
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY)]
internal static extern int miCASAGetCredential
(
@ -204,13 +249,26 @@ namespace Novell.Casa
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY)]
internal static extern int miCASAReadSecret
(
[In] IntPtr context,
[In] SSCS_KEYCHAIN_ID_T keyChainID,
[In] uint ssFlags,
[In] IntPtr secretHandle,
[In] SSCS_SH_SECRET_ID_T sharedSecretID,
[In] SSCS_PASSWORD_T epPassword,
[In, Out] SSCS_READEXT_T readData,
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY, CharSet = CharSet.None)]
internal static extern int miCASAWriteKey
(
[In] IntPtr context,
[In] uint ssFlags,
[In] SSCS_KEYCHAIN_ID_T keyChainID,
[In] SSCS_SH_SECRET_ID_T sharedSecretID,
[In] SSCS_SECRET_ID_T sharedSecretID,
[MarshalAs(UnmanagedType.LPStr)]
string key,
[In] uint keyLenBytes, // in bytes
@ -221,6 +279,40 @@ namespace Novell.Casa
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY, CharSet = CharSet.None)]
internal static extern int miCASARemoveKey
(
[In] IntPtr context,
[In] uint ssFlags,
[In] SSCS_KEYCHAIN_ID_T keyChainID,
[In] SSCS_SECRET_ID_T sharedSecretID,
[MarshalAs(UnmanagedType.LPStr)]
string key,
[In] uint keyLenBytes, // in bytes
[In] SSCS_PASSWORD_T password,
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY)]
internal static extern IntPtr miCASA_CreateSHSHandle();
[DllImport(NDK_LIBRARY)]
internal static extern int miCASA_DestroySHSHandle(
[In] IntPtr secretHandle);
[DllImport(NDK_LIBRARY, CharSet = CharSet.None)]
internal static extern int miCASA_GetNextSHSEntry
(
[In] int restart, //* in (set to 1 to begin from head of list)
[In] IntPtr secretHandle, //* in
[In, Out] ref uint keyLen, //* out
IntPtr theKey,
[In, Out] ref uint valLen, //* out
IntPtr theValue
);
[DllImport(NDK_LIBRARY)]
internal static extern int miCASAMergeCache
(
@ -648,7 +740,362 @@ namespace Novell.Casa
}
return sb.ToString();
}
internal static IntPtr OpenSecretStore(string sSecretStoreName)
{
//check params
if (sSecretStoreName == null || sSecretStoreName.Length == 0)
throw new MiCasaException(MiCasaException.NSSCS_E_INVALID_PARAM);
SSCS_SECRET_STORE_ID_T SSid = new SSCS_SECRET_STORE_ID_T();
SSid.id = sSecretStoreName;
SSid.version = 0;
SSCS_EXT_T ext = new SSCS_EXT_T();
try
{
IntPtr hSC = miCASAOpenSecretStoreCache(SSid, 0, ext);
return hSC;
}
catch (Exception)
{
return IntPtr.Zero;
}
}
internal static void CloseSecretStore(IntPtr hSC)
{
SSCS_EXT_T ext = new SSCS_EXT_T();
miCASACloseSecretStoreCache(hSC, 0, ext);
}
internal static StringCollection EnumerateSecretIDs(
uint ssFlags,
string sKeyChainID,
string sSearchKey)
{
IntPtr context;
if (sKeyChainID == null || sSearchKey == null
|| sKeyChainID.Length == 0)
{
throw new MiCasaException(MiCasaException.NSSCS_E_INVALID_PARAM);
}
context = OpenSecretStore("SecretStore");
if (context == IntPtr.Zero)
{
throw new MiCasaException(MiCasaException.NSSCS_E_SYSTEM_FAILURE);
}
// setup structures
SSCS_KEYCHAIN_ID_T keyChainID = new SSCS_KEYCHAIN_ID_T();
keyChainID.keychainID = sKeyChainID;
SSCS_SRCH_KEY_T searchKey = new SSCS_SRCH_KEY_T();
SSCS_SH_SECRET_ID_LIST_T idList = new SSCS_SH_SECRET_ID_LIST_T();
SSCS_EXT_T ext = new SSCS_EXT_T();
int numIDS = 1024;
StringCollection sc = new StringCollection(); //null;
// setup keychainid
keyChainID.len = sKeyChainID.Length + 1;
searchKey.srchKey = sSearchKey;
searchKey.srchKeyLen = (uint)sSearchKey.Length;
idList.returnedIDs = (uint)numIDS;
SSCS_SH_SECRET_ID_T secretId = new SSCS_SH_SECRET_ID_T();
// secretId.name = new char[512];
StringBuilder buffer3 = new StringBuilder("content", 512);
buffer3.Append((char)0);
buffer3.Append('*', buffer3.Capacity - 8);
String tempStr = buffer3.ToString();
idList.secretIDList = Marshal.AllocHGlobal(numIDS * Marshal.SizeOf(secretId));
// make the call
int rcode = miCASAEnumerateSecretIDs(
context,
keyChainID,
ssFlags,
searchKey,
idList,
ext);
if (idList.returnedIDs > 0)
{
sc = new StringCollection();
if (idList.returnedIDs != numIDS)
{
// enumerate returned list
for (int i = 0; i < idList.returnedIDs; i++)
{
IntPtr temp = new IntPtr(idList.secretIDList.ToInt32() + (i * Marshal.SizeOf(secretId)));
secretId = (SSCS_SH_SECRET_ID_T)Marshal.PtrToStructure(temp, typeof(SSCS_SH_SECRET_ID_T));
String st = secretId.name;
sc.Add(st);
}
}
}
Marshal.FreeHGlobal(idList.secretIDList);
CloseSecretStore(context);
return sc;
}
internal static Secret GetSecret(
string sKeyChainID,
uint iFlags,
string sSharedSecretID,
int iSecretType,
string sEPPassword)
{
IntPtr pHsc = OpenSecretStore("SecretStore");
if (pHsc == IntPtr.Zero)
{
throw new MiCasaException(MiCasaException.NSSCS_E_SYSTEM_FAILURE);
}
if (sKeyChainID == null || sSharedSecretID == null
|| sKeyChainID.Length == 0 || sSharedSecretID.Length == 0)
throw new MiCasaException(MiCasaException.NSSCS_E_INVALID_PARAM);
// setup structures
SSCS_KEYCHAIN_ID_T keyChainID = new SSCS_KEYCHAIN_ID_T();
keyChainID.keychainID = sKeyChainID;
SSCS_SH_SECRET_ID_T sharedSecretID = new SSCS_SH_SECRET_ID_T();
sharedSecretID.name = sSharedSecretID;
sharedSecretID.type = iSecretType;
SSCS_PASSWORD_T epPassword = new SSCS_PASSWORD_T();
SSCS_READEXT_T readData = new SSCS_READEXT_T();
SSCS_EXT_T ext = new SSCS_EXT_T();
// get SecretHandle
IntPtr pSecretHandle = miCASA_CreateSHSHandle();
// setup keychainid
keyChainID.len = sKeyChainID.Length + 1;
// setup sharedSecretID
sharedSecretID.len = sSharedSecretID.Length + 1;
sharedSecretID.type = iSecretType; // TODO: type APP(1), CRED(2), or Binary(4)
epPassword.pwordType = 1; // TODO: ep or master password based on flags
if (sEPPassword != null)
{
epPassword.pword = sEPPassword;
epPassword.pwordLen = (uint)sEPPassword.Length;
}
else
epPassword.pwordLen = 0;
int rcode = miCASAReadSecret(
pHsc,
keyChainID,
iFlags,
pSecretHandle,
sharedSecretID,
epPassword,
readData,
ext);
// create new secret
Secret temp = new Secret(sKeyChainID, iFlags, pSecretHandle, sSharedSecretID, sharedSecretID.type);
// if read was sucessfull, read key value pairs
if (rcode == 0)
{
LoadKeyValuePairs(temp);
}
// close store
CloseSecretStore(pHsc);
return temp;
}
internal static void LoadKeyValuePairs(Secret secret)
{
int rcode = 0;
int iStart = 1;
IntPtr theKey = Marshal.AllocHGlobal(60416);
IntPtr theValue = Marshal.AllocHGlobal(60416);
String sKey;
String sValue;
while (true)
{
uint iKeyLen = 60416;
uint iValueLen = 60416;
sKey = "";
sValue = "";
rcode = miCASA_GetNextSHSEntry(
iStart,
secret.m_secretHandle,
ref iKeyLen,
theKey, //sKey,
ref iValueLen,
theValue // sValue
);
if (rcode != 0)
break;
else
{
if (iKeyLen > 1)
{
//sKey = Marshal.PtrToStringAnsi(theKey, (int)iKeyLen - 1);
// convert from UTF8
byte[] baKey = new byte[iKeyLen - 1];
Marshal.Copy(theKey, baKey, 0, (int)iKeyLen - 1);
sKey = System.Text.Encoding.UTF8.GetString(baKey, 0, baKey.Length);
}
if (iValueLen > 1)
{
//sValue = Marshal.PtrToStringAnsi(theValue, (int)iValueLen -1);
// convert from UTF8
byte[] baValue = new byte[iValueLen - 1];
Marshal.Copy(theValue, baValue, 0, (int)iValueLen - 1);
sValue = System.Text.Encoding.UTF8.GetString(baValue, 0, baValue.Length);
}
if (sKey != null && sValue != null)
secret.SetKeyValue(sKey, sValue, false);
iStart = 0;
}
}
Marshal.FreeHGlobal(theKey);
Marshal.FreeHGlobal(theValue);
}
internal static void WriteKey(
uint iFlags,
string sKeyChainID,
string sSharedSecretID,
string sKey,
string sValue,
string sEPPassword)
{
IntPtr context;
if (sKeyChainID == null
|| sKeyChainID.Length == 0)
{
throw new MiCasaException(MiCasaException.NSSCS_E_INVALID_PARAM);
}
context = OpenSecretStore("SecretStore");
if (context == IntPtr.Zero)
{
throw new MiCasaException(MiCasaException.NSSCS_E_SYSTEM_FAILURE);
}
// setup structures
SSCS_KEYCHAIN_ID_T keyChainID = new SSCS_KEYCHAIN_ID_T();
keyChainID.keychainID = sKeyChainID;
keyChainID.len = sKeyChainID.Length + 1;
SSCS_SECRET_ID_T sharedSecretID = new SSCS_SECRET_ID_T();
sharedSecretID.id = sSharedSecretID;
sharedSecretID.len = sSharedSecretID.Length + 1;
SSCS_PASSWORD_T epPassword = new SSCS_PASSWORD_T();
SSCS_EXT_T ext = new SSCS_EXT_T();
StringCollection sc = new StringCollection(); //null;
int rcode = miCASAWriteKey(
context,
iFlags,
keyChainID,
sharedSecretID,
sKey,
(uint) (sKey.Length+1),
sValue,
(uint) (sValue.Length+1),
epPassword,
ext);
CloseSecretStore(context);
if (rcode != 0)
{
throw new MiCasaException(rcode);
}
}
internal static void RemoveKey(
string sKeyChainID,
uint iFlags,
string sSharedSecretID,
string sKey,
string sEPPassword)
{
IntPtr context;
if (sKeyChainID == null
|| sKeyChainID.Length == 0)
{
throw new MiCasaException(MiCasaException.NSSCS_E_INVALID_PARAM);
}
context = OpenSecretStore("SecretStore");
if (context == IntPtr.Zero)
{
throw new MiCasaException(MiCasaException.NSSCS_E_SYSTEM_FAILURE);
}
// setup structures
SSCS_KEYCHAIN_ID_T keyChainID = new SSCS_KEYCHAIN_ID_T();
keyChainID.keychainID = sKeyChainID;
keyChainID.len = sKeyChainID.Length + 1;
SSCS_SECRET_ID_T sharedSecretID = new SSCS_SECRET_ID_T();
sharedSecretID.id = sSharedSecretID;
sharedSecretID.len = sSharedSecretID.Length + 1;
SSCS_PASSWORD_T epPassword = new SSCS_PASSWORD_T();
SSCS_EXT_T ext = new SSCS_EXT_T();
int rcode = miCASARemoveKey(
context,
iFlags,
keyChainID,
sharedSecretID,
sKey,
(uint)(sKey.Length + 1),
epPassword,
ext);
CloseSecretStore(context);
if (rcode != 0)
{
throw new MiCasaException(rcode);
}
}
}
}

View File

@ -38,6 +38,7 @@
<Compile Include="MiCasaException.cs" />
<Compile Include="NativeCalls.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Secret.cs" />
<Compile Include="WinLuid.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,133 @@
/***********************************************************************
*
* Copyright (C) 2005-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.
*
***********************************************************************/
using System;
using System.Collections;
using System.Collections.Specialized;
namespace Novell.Casa
{
/// <summary>
/// Summary description for Secret.
/// </summary>
public class Secret : MarshalByRefObject
{
private String m_keyChainID;
private uint m_ssFlags;
internal IntPtr m_secretHandle;
private String m_secretID;
internal int m_type = 0;
// holds name value pairs for this secret
private System.Collections.Specialized.NameValueCollection m_nvc;
public static int SS_APP = 1;
public static int SS_CREDSET = 2;
public static int SS_BINARY = 4;
// constructor
internal Secret(
String sKeyChainID,
uint iSSFlags,
IntPtr ptrHandle,
string sSecretID,
int iSecretType)
{
m_keyChainID = sKeyChainID;
m_ssFlags = iSSFlags;
m_secretHandle = ptrHandle;
m_secretID = sSecretID;
m_type = iSecretType;
if (sSecretID.StartsWith("SS_CredSet"))
m_type = Secret.SS_CREDSET;
else if (sSecretID.StartsWith("SS_App"))
m_type = Secret.SS_APP;
else if (sSecretID.StartsWith("SS_Binary"))
m_type = Secret.SS_BINARY;
// create collection
m_nvc = new System.Collections.Specialized.NameValueCollection();
}
// TO clean up SecretHandle
public string GetID()
{
return m_secretID;
}
public void SetKeyValue(String sKey, String sKeyValue)
{
SetKeyValue(sKey, sKeyValue, true);
}
internal void SetKeyValue(String sKey, String sKeyValue, bool bCommit)
{
if (m_type == Secret.SS_APP)
m_nvc.Add(sKey, sKeyValue);
else
{
if (bCommit)
{
NativeCalls.WriteKey(0, m_keyChainID, this.GetID(),
sKey, sKeyValue, null);
}
m_nvc.Set(sKey, sKeyValue);
}
}
public string GetKeyValue(String sKey)
{
return m_nvc.Get(sKey);
}
private int GetSecretType()
{
return this.m_type;
}
public NameValueCollection GetKeyValueCollection()
{
return m_nvc;
}
public void MergeKeyValueCollection(NameValueCollection nvc)
{
m_nvc = nvc;
}
public void RemoveKey(String sKey)
{
//call the ndk to remove that one too.
NativeCalls.RemoveKey(this.m_keyChainID, 0, this.GetID(), sKey, null);
// remove from our collection
m_nvc.Remove(sKey);
}
}
}