475 lines
16 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|
|
|
|
|