475 lines
16 KiB
C#

/***********************************************************************
*
* 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.Runtime.InteropServices;
using System.Text;
using System.Collections.Specialized;
using System.Collections;
namespace Novell.Casa
{
/// <summary>
/// Summary description for NativeCalls.
/// </summary>
public class NativeCalls
{
private static SSCS_KEYCHAIN_ID_T DefaultKeychainID = null;
internal static uint SSCS_CRED_TYPE_BASIC_F = 1;
internal static uint SSCS_CRED_TYPE_SERVER_F = 4;
private static int USERNAME_LEN = 256;
private static int PASSWORD_LEN = 128;
public NativeCalls()
{
//
// TODO: Add constructor logic here
//
if (DefaultKeychainID == null)
{
DefaultKeychainID = new SSCS_KEYCHAIN_ID_T();
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_PASSWORD_T
{
public uint pwordType;
public uint pwordLen; // * enhanced protection len & pword to set
// [MarshalAs(UnmanagedType.LPStr, SizeConst = 128)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string pword; // * should be passed in # of chars
} ;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_KEYCHAIN_ID_T
{
public int len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string keychainID;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_SH_SECRET_ID_T
{
public int type; // The shared secret type i.e. SS_App or SS_CredSet
public int len; // except that it excludes the header and is not escaped.
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string name; // The shared secret name. This is the same as the identifier
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_SECRET_STORE_ID_T
{
public int version; // * max id len in bytes
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string id; // * should be passed in # of chars
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_SECRET_ID_T
{
public int len; // * max id len in bytes
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string id; // * should be passed in # of chars
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_EXT_T
{
public int extID; // defined to identify the extension
public int version; // defined as the version of the specified extension
public IntPtr ext; // points to the actual extension
} ;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_CONTEXT_T
{
public int version;
public int flags;
public SSCS_SECRET_ID_T ssid;
public UInt64 ssHandle;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SSCS_BASIC_CREDENTIAL_UTF8
{
public uint unFlags;
public uint unLen;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public byte[] username;
public uint pwordLen;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] password;
}
// * The following functions will be exposed as exported API:
// **************************************************************
// * These function calls will utilize the Support Functions for
// * populating or extracting data from a Shared Secret.
// **************************************************************
private const string NDK_LIBRARY = "micasa";
[DllImport(NDK_LIBRARY)]
internal static extern int miCASAGetCredential
(
[In] uint ssFlags,
[In] SSCS_SECRET_ID_T appSecretID,
[In] SSCS_SECRET_ID_T sharedSecretID,
[In, Out] ref uint credentialType,
[In, Out] IntPtr pCredential,
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY)]
internal static extern int miCASASetCredential
(
[In] uint ssFlags,
[In] SSCS_SECRET_ID_T appSecretID,
[In] SSCS_SECRET_ID_T sharedSecretID,
[In] uint credentialType,
[In] IntPtr credential,
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY)]
internal static extern int miCASARemoveCredential
(
[In] uint ssFlags,
[In] SSCS_SECRET_ID_T appSecretID,
[In] SSCS_SECRET_ID_T sharedSecretID,
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY)]
internal static extern int miCASAIsSecretPersistent
(
[In] uint ssFlags,
[In] SSCS_SECRET_ID_T secretID,
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY)]
internal static extern IntPtr miCASAOpenSecretStoreCache
(
[In, Out] SSCS_SECRET_STORE_ID_T ssid,
uint ssFlags,
[In, Out] SSCS_EXT_T ext
);
[DllImport(NDK_LIBRARY)]
internal static extern int miCASACloseSecretStoreCache
(
[In] IntPtr context,
[In] uint ssFlags,
[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,
[MarshalAs(UnmanagedType.LPStr)]
string key,
[In] uint keyLenBytes, // in bytes
[MarshalAs(UnmanagedType.LPStr)]
string val,
[In] uint valueLenBytes, // in bytes
[In] SSCS_PASSWORD_T password,
[In, Out] SSCS_EXT_T ext
);
/// <param name="ssFlags"></param>
/// <param name="sAppSecretID"></param>
/// <param name="sSharedSecretID"></param>
/// <param name="unFlag"></param>
/// <returns></returns>
internal static BasicCredential GetCredential(
uint ssFlags,
string sAppSecretID,
string sSharedSecretID,
uint unFlag,
uint credType)
{
if (sAppSecretID == null || sAppSecretID.Length == 0)
throw new MiCasaException(MiCasaException.NSSCS_E_INVALID_PARAM);
int rcode;
BasicCredential bc = null;
SSCS_SECRET_ID_T appSecretID = new SSCS_SECRET_ID_T();
appSecretID.id = sAppSecretID;
appSecretID.len = sAppSecretID.Length + 1;
SSCS_SECRET_ID_T sharedID = new SSCS_SECRET_ID_T();
if (sSharedSecretID != null)
{
sharedID.len = sSharedSecretID.Length + 1;
sharedID.id = sSharedSecretID;
}
SSCS_BASIC_CREDENTIAL_UTF8 credential = new SSCS_BASIC_CREDENTIAL_UTF8();
credential.unFlags = unFlag;
// alloc some memory
IntPtr pCredential = Marshal.AllocHGlobal(Marshal.SizeOf(credential));
Marshal.StructureToPtr(credential, pCredential, false);
try
{
rcode = miCASAGetCredential(
ssFlags,
appSecretID,
sharedID,
ref credType,
pCredential,
new SSCS_EXT_T()
);
}
catch (Exception)
{
//Console.WriteLine(e.ToString());
Marshal.FreeHGlobal(pCredential);
throw new MiCasaException(-803);
}
if (rcode == 0)
{
Marshal.PtrToStructure(pCredential, credential);
string sUsername = GetStringFromUTF8(credential.username, (int)credential.unLen - 1);
string sPassword = GetStringFromUTF8(credential.password, (int)credential.pwordLen - 1);
bc = new BasicCredential(sUsername, sPassword);
Marshal.FreeHGlobal(pCredential);
return bc;
}
else
{
Marshal.FreeHGlobal(pCredential);
throw new MiCasaException(rcode);
}
}
internal static void SetCredential(
uint ssFlags,
string sAppSecretID,
string sSharedSecretID,
uint unFlag,
uint uCredType,
string sUsername,
string sPassword)
{
if (sAppSecretID == null || sUsername == null || sPassword == null
|| sAppSecretID.Length == 0 || sUsername.Length == 0 || sPassword.Length == 0)
throw new MiCasaException(MiCasaException.NSSCS_E_INVALID_PARAM);
int rcode;
SSCS_SECRET_ID_T appSecretID = new SSCS_SECRET_ID_T();
appSecretID.id = sAppSecretID;
appSecretID.len = sAppSecretID.Length + 1;
SSCS_SECRET_ID_T sharedID = new SSCS_SECRET_ID_T();
if (sSharedSecretID != null)
{
sharedID.len = sSharedSecretID.Length + 1;
sharedID.id = sSharedSecretID;
}
SSCS_BASIC_CREDENTIAL_UTF8 credential = new SSCS_BASIC_CREDENTIAL_UTF8();
credential.unFlags = unFlag;
credential.unLen = GetUTF8ByteCount(sUsername) + 1;
credential.username = GetUTF8FromString(sUsername, USERNAME_LEN);
credential.pwordLen = GetUTF8ByteCount(sPassword) + 1;
credential.password = GetUTF8FromString(sPassword, PASSWORD_LEN);
IntPtr pCredential = Marshal.AllocHGlobal(Marshal.SizeOf(credential));
Marshal.StructureToPtr(credential, pCredential, true);
rcode = miCASASetCredential
(ssFlags,
appSecretID,
sharedID,
uCredType,
pCredential,
new SSCS_EXT_T()
);
if (rcode != 0)
{
throw new MiCasaException(rcode);
}
}
internal static void RemoveCredential(
uint ssFlags,
string sAppSecretID,
string sSharedSecretID)
{
if (sAppSecretID == null || sAppSecretID.Length == 0)
throw new MiCasaException(MiCasaException.NSSCS_E_INVALID_PARAM);
int rcode;
SSCS_SECRET_ID_T appSecretID = new SSCS_SECRET_ID_T();
appSecretID.id = sAppSecretID;
appSecretID.len = sAppSecretID.Length + 1;
SSCS_SECRET_ID_T sharedID = new SSCS_SECRET_ID_T();
if (sSharedSecretID != null)
{
sharedID.len = sSharedSecretID.Length + 1;
sharedID.id = sSharedSecretID;
}
rcode = miCASARemoveCredential(ssFlags, appSecretID, sharedID, new SSCS_EXT_T());
if (rcode != 0)
{
throw new MiCasaException(rcode);
}
}
internal static bool IsSecretPersistent(uint ssFlags, string id)
{
int rcode = 0;
SSCS_SECRET_ID_T secretID = new SSCS_SECRET_ID_T();
try
{
if (ssFlags == 0)
{
if ((null == id) || ("" == id))
return false;
secretID.len = id.Length;
secretID.id = id;
rcode = miCASAIsSecretPersistent(ssFlags,
secretID,
new SSCS_EXT_T());
}
else
{
rcode = miCASAIsSecretPersistent(ssFlags,
null,
new SSCS_EXT_T());
}
}
catch (Exception)
{
//Console.WriteLine(e.ToString());
}
if (rcode == 1)
return true;
else
return false;
}
// helper methods
private static string GetStringFromUTF8(byte[] utf8Bytes, int numBytes)
{
if (numBytes > 0)
{
Decoder utfDec = System.Text.Encoding.UTF8.GetDecoder();
int charCount = utfDec.GetCharCount(utf8Bytes, 0, numBytes);
char[] chars = new char[charCount];
int len = utfDec.GetChars(utf8Bytes, 0, numBytes, chars, 0);
string text = new string(chars);
text = text.Trim();
return text;
}
else
return "";
}
private static uint GetUTF8ByteCount(string str)
{
uint byteCount = (uint)System.Text.Encoding.UTF8.GetEncoder().GetByteCount(str.ToCharArray(), 0, str.Length, true);
return byteCount;
}
private static byte[] GetUTF8FromString(string str, int arrayLength)
{
// NOTE: Must return a padded array of arrayLength
Encoder utfEnc = System.Text.Encoding.UTF8.GetEncoder();
byte[] utf8Bytes = new byte[arrayLength];
int len = utfEnc.GetBytes(str.ToCharArray(), 0, str.Length, utf8Bytes, 0, true);
return utf8Bytes;
}
private static string EscapeReservedChars(string origString)
{
if (origString == null)
return origString;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < origString.Length; i++)
{
switch (origString[i])
{
case ':':
{
sb.Append("\\");
break;
}
case '\\':
{
sb.Append("\\");
break;
}
case '=':
{
sb.Append("\\");
break;
}
}
sb.Append(origString[i]);
}
return sb.ToString();
}
}
}