CASA/c_adlib/KWalletEngine.cs
2005-12-16 10:29:25 +00:00

544 lines
23 KiB
C#

using System;
using System.Collections;
using System.Xml;
using System.IO;
using Novell.CASA;
using Novell.CASA.DataEngines.Common;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using Novell.CASA.DataEngines.KWallet;
namespace Novell.CASA.DataEngines
{
/*
* This class is implementation of Data engine for KWallet.
*/
class KWalletEngine : DataEngine
{
string[] EntryTypes = {"Binary","Passwords","Unknown", "Maps"};
enum KWalletResult : int
{
KWALLET_RESULT_OK,
KWALLET_RESULT_CANNOT_OPEN_WALLET,
KWALLET_RESULT_CANNOT_OPEN_FOLDER,
KWALLET_RESULT_CANNOT_WRITE_ENTRY,
KWALLET_RESULT_MALFORMED_XML,
KWALLET_RESULT_CANNOT_CREATE_FOLDER,
KWALLET_RESULT_CANNOT_CREATE_WALLET,
KWALLET_RESULT_CANNOT_REMOVE_ENTRY,
KWALLET_RESULT_UNKNOWN_ERROR
};
public KWalletEngine()
{
// TBD: Read Policy information and have a list of wallet names;
}
public XmlNode Aggregate()
{
XmlDocument doc = new XmlDocument();
Hashtable lookup = new Hashtable();
XmlElement key1;
XmlAttribute Atr;
XmlElement value1;
XmlAttribute idAttr;
String secid, val;
XmlElement currentWallet;
XmlElement Folder;
XmlElement Type;
XmlElement Secret;
String walletName, foldername, entryType, secretval;
//Adding Kwallet Top Node
XmlElement elem = doc.CreateElement(ConstStrings.CCF_KW);
doc.AppendChild(elem);
EnumSecretList enumList = new EnumSecretList();
//kwallet.Try(enumList);
kwallet.AggregateKW(enumList);
EnumSecretList tempEnumSecretList1 = enumList;
//This can be Null only when nothing is aggregated.
if (((String)Marshal.PtrToStringAnsi(tempEnumSecretList1.walletName)) == null )
{
//TBD: Log that there are no secrets to aggregate
}
else // Something to Aggregate
{
while (tempEnumSecretList1 != null)
{
walletName = (String)Marshal.PtrToStringAnsi(tempEnumSecretList1.walletName);
// Console.WriteLine("\n\nWallet name is***# : "+walletName);
foldername = (String)Marshal.PtrToStringAnsi(tempEnumSecretList1.folderName);
//Console.WriteLine("\tFolder***# : "+foldername);
int entrytype = tempEnumSecretList1.entryType;
//Console.WriteLine("\t\tEntryType ***#: "+entrytype);
entryType = EntryTypes[entrytype];
//Console.WriteLine("\t\tEntryType in string ***#: "+entryType);
secretval = (String)Marshal.PtrToStringAnsi(tempEnumSecretList1.secretVal);
//Console.WriteLine("\t\tSecret***# : "+secretval);
//Adding Wallet
if (lookup.ContainsKey(walletName))
{
//Console.WriteLine("Wallet Node found");
currentWallet = (XmlElement)lookup[walletName];
}
else
{
currentWallet = doc.CreateElement(ConstStrings.CCF_WALLET);
idAttr = doc.CreateAttribute(ConstStrings.CCF_ID);
idAttr.Value = walletName;
currentWallet.SetAttributeNode(idAttr);
elem.AppendChild(currentWallet);
lookup.Add(walletName,currentWallet);
}
//Adding Folder
String xpath = "descendant::Folder[@Name='"+foldername+"']";
XmlNodeList folList = currentWallet.SelectNodes(xpath);
if (folList.Count == 0)
{
Folder = doc.CreateElement(ConstStrings.CCF_FOLDER);
XmlAttribute name_attr = doc.CreateAttribute(ConstStrings.CCF_NAME);
name_attr.Value = foldername;
Folder.SetAttributeNode(name_attr);
currentWallet.AppendChild(Folder);
}
//Adding Type
xpath = "descendant::Folder";
XmlNodeList folderlist = currentWallet.SelectNodes(xpath);
foreach(XmlNode folder in folderlist)
{
XmlAttributeCollection atcol = folder.Attributes;
XmlAttribute attr = atcol[ConstStrings.CCF_NAME];
if (attr.InnerXml.Equals(foldername))
{
xpath = "descendant::Type[@ID='"+entryType+"']";
XmlNodeList keylist = folder.SelectNodes(xpath);
if (keylist.Count == 0)
{
Type = doc.CreateElement(ConstStrings.CCF_TYPE);
XmlAttribute name_attr = doc.CreateAttribute(ConstStrings.CCF_ID);
name_attr.Value = entryType;
Type.SetAttributeNode(name_attr);
folder.AppendChild(Type);
}
else
{
//Console.WriteLine("Type Already Added");
}
}
}
//Adding the Secret
xpath = "descendant::Folder";
folderlist = currentWallet.SelectNodes(xpath);
foreach(XmlNode folder in folderlist)
{
XmlAttributeCollection atcol = folder.Attributes;
XmlAttribute attr = atcol[ConstStrings.CCF_NAME];
if (attr.InnerXml.Equals(foldername))
{
xpath = "descendant::Type[@ID='"+entryType+"']";
XmlNodeList keylist = folder.SelectNodes(xpath);
if (keylist.Count == 0)
{
//Console.WriteLine("Construction of CCF Failed");
}
else
{
XmlNode TargetType = keylist[0]; //Type Node
string[] split = null;
int index = secretval.IndexOf('=');
secid = secretval.Substring(0,index);
Secret = doc.CreateElement(ConstStrings.CCF_SECRET);
XmlAttribute idattr = doc.CreateAttribute(ConstStrings.CCF_ID);
idattr.Value = secid;
Secret.SetAttributeNode(idattr);
XmlAttribute typeAttr = doc.CreateAttribute(ConstStrings.CCF_TYPE);
typeAttr.Value = entryType;
Secret.SetAttributeNode(typeAttr);
if (entryType.Equals("Maps"))
{
string delim = ";";
char[] delimiter = delim.ToCharArray();
string realval = secretval.Substring(index+1);
for(int x = 1; x < 10 ; x++)
{
split = realval.Split(delimiter, x);
}
foreach(string s in split)
{
int ix;
string key;
string value;
//Console.WriteLine("The val is :" + s);
if (s.Equals(""))
{
//Console.WriteLine("No Secret Content for a Secret ID");
key = " ";
value = " ";
}
else
{
ix = s.IndexOf(':');
key = s.Substring(0,ix);
value = s.Substring(ix+1);
}
key1 = doc.CreateElement(ConstStrings.CCF_KEY);
Atr = doc.CreateAttribute(ConstStrings.CCF_ID);
Atr.Value = key;
key1.SetAttributeNode(Atr);
//Value
value1 = doc.CreateElement(ConstStrings.CCF_VALUE);
value1.InnerText = value;
key1.AppendChild(value1);
Secret.AppendChild(key1);
TargetType.AppendChild(Secret);
}
}//entrytype=Maps
else if (entryType.Equals("Passwords"))
{
//Console.WriteLine("Passwords");
val = secretval.Substring(index+1);
//Key
key1 = doc.CreateElement(ConstStrings.CCF_KEY);
Atr = doc.CreateAttribute(ConstStrings.CCF_ID);
Atr.Value = "Credential";
key1.SetAttributeNode(Atr);
//Value
value1 = doc.CreateElement(ConstStrings.CCF_VALUE);
value1.InnerText = val;
key1.AppendChild(value1);
Secret.AppendChild(key1);
TargetType.AppendChild(Secret);
}//entryType=Password
}
}
}
if (tempEnumSecretList1.next == IntPtr.Zero)
{
// Console.WriteLine("Reached End ##");
break;
}
tempEnumSecretList1 = (EnumSecretList)Marshal.PtrToStructure(tempEnumSecretList1.next, typeof(EnumSecretList));
}
}
kwallet.FreeResources();
#if TEST
XmlTextWriter writer = new XmlTextWriter("/root/kwtest.xml",null);
writer.Formatting = Formatting.Indented;
doc.Save(writer);
writer.Close();
#endif
return doc.ChildNodes[0];
}
/***********************************************************************************
SetSecret will modify the Value(s) of a Key(s) for an existing secret
SetSecret will also add new secrets
Parameters
secret : Secrets XMLNode
1. If a Key node of a secret is missing then that key will be deleted
2. For Gnome keyring, Key having Id "GkPassword" cannot be deleted as
Gnome Api's do not allow it.
3. All Time nodes for a Secret need not be passed as they cannot be set.
4. Keyring attributes have a fixed datatype of Int and String. Currently we support only String types.
To support int types CCF needs to be modified accordingly.
5. To signify that a GnomeKeyring secret should be added, append the secret's ID with a ":".
StoreID : int value
Novell.CASA.DataEngines.Common.ConstStrings.CASA_STORE_KWALLET;
Returns
An Error code or 0 if operation is successfull.
***************************************************************************************/
public int SetSecret(XmlNode secret)
{
try
{
string walletName = ExtractWalletName(secret);
string folderName = ExtractFolderName(secret);
string keyName = ExtractKeyName(secret);
int secretType = ExtractSecretType(secret);
if (secretType != 3) //Type not Map
{
string value = secret.ChildNodes[0].ChildNodes[0].InnerText; //Secret.Key.Value
return(kwallet.SetSecret(walletName, folderName, secretType, keyName, value, value.Length));
}
else //If type is Map
{
NameValueCollection nvc = new NameValueCollection();
for (int i =0; i< secret.ChildNodes.Count; i++)
{
XmlNode key = secret.ChildNodes[i];
XmlAttributeCollection atcol;
atcol = key.Attributes;
String keyMapName = atcol["ID"].InnerXml;
Console.WriteLine("Map Ele KeyName = " + keyMapName);
string value = key.ChildNodes[0].InnerText; //Secret.Key.Value
Console.WriteLine("Map Ele Value = " + value);
nvc.Add(keyMapName,value);
}
return(kwallet.SetSecret(walletName, folderName,keyName,nvc));
}
}
catch(NullReferenceException n)
{
Console.WriteLine("Exception in Set Secret Cause :" + n.ToString());
return (int)KWalletResult.KWALLET_RESULT_MALFORMED_XML;
}
catch(Exception e)
{
Console.WriteLine("Exception in Set Secret Cause :" + e.ToString());
return (int)KWalletResult.KWALLET_RESULT_UNKNOWN_ERROR;
}
}
public int GetSecret(XmlNode secret)
{
return ConstStrings.CASA_SUCCESS;
}
/**************************************************************************************
Remove will delete a Secret.
Parameters
secret : Secrets XmlNode
1. This node will be deleted from its parent.
StoreID : int value
Novell.CASA.DataEngines.Common.ConstStrings.CASA_STORE_KWALLET;
Returns
An Error code or 0 if operation is successfull. Error code is same as above
**************************************************************************************/
public int Remove(XmlNode secret)
{
try
{
string walletName = ExtractWalletName(secret);
string folderName = ExtractFolderName(secret);
string keyName = ExtractKeyName(secret);
int secretType = ExtractSecretType(secret);
int res = kwallet.DeleteSecret(walletName, folderName, keyName);
if (res == 0)
{
XmlNode root = secret.ParentNode;
root.RemoveChild(secret);
}
return res;
}
catch(NullReferenceException n)
{
Console.WriteLine("Exception in Set Secret Cause :" + n.ToString());
return (int)KWalletResult.KWALLET_RESULT_MALFORMED_XML;
}
catch(Exception e)
{
Console.WriteLine("Exception in Set Secret Cause :" + e.ToString());
return (int)KWalletResult.KWALLET_RESULT_UNKNOWN_ERROR;
}
}
string ExtractWalletName(XmlNode secret)
{
XmlAttributeCollection atcol;
XmlNode parentNode = secret.ParentNode.ParentNode.ParentNode;
Console.WriteLine("In Extract Wallet Name ");
atcol = parentNode.Attributes;
String walletname = atcol["ID"].InnerXml;
Console.WriteLine("In Extract Wallet Name Wallet Name = " + walletname);
return walletname;
}
string ExtractFolderName(XmlNode secret)
{
XmlAttributeCollection atcol;
XmlNode parentNode = secret.ParentNode.ParentNode; //Folder.Type.Secret
Console.WriteLine("In Extract Folder Name ");
atcol = parentNode.Attributes;
String foldername = atcol["Name"].InnerXml;
Console.WriteLine("In Extract Folder Name Folder Name = " + foldername);
return foldername;
}
string ExtractKeyName(XmlNode secret)
{
XmlAttributeCollection atcol;
Console.WriteLine("In Extract Key Name ");
atcol = secret.Attributes;
String keyname = atcol["ID"].InnerXml;
Console.WriteLine("In Extract Key Name Key Name = " + keyname);
return keyname;
}
int ExtractSecretType(XmlNode secret)
{
XmlAttributeCollection atcol;
XmlNode parentNode = secret.ParentNode; //Type.Secret
Console.WriteLine("In Extract Entry Type ");
atcol = parentNode.Attributes;
String entryType = atcol["ID"].InnerXml;
Console.WriteLine("In Extract Entry Type = " + entryType);
if (entryType.CompareTo("Passwords")== 0)
{
return 1;
}
if (entryType.CompareTo("Binary") == 0)
{
return 2;
}
if (entryType.CompareTo("Maps") == 0)
{
return 3;
}
return 0;
}
#if TEST
public static void Main()
{
Console.WriteLine("Hello there");
KWalletEngine kw = new KWalletEngine();
Console.WriteLine();
Console.WriteLine("********** Menu ***********");
Console.WriteLine("* 1. Set secret *");
Console.WriteLine("* 2. Remove secret *");
Console.WriteLine("* 3. Refresh *");
Console.WriteLine("* 4. Quit *");
Console.WriteLine("***************************");
Console.WriteLine("For all options the input is the file /root/kwtest.xml");
Console.WriteLine("Select option and Press enter");
String line = Console.ReadLine();
int res = 0;
if (line.Length > 0)
{
char[] c = line.Substring(0, 1).ToCharArray();
if (c.Length > 0)
{
if (c[0].Equals('4'))
return;
if (c[0].Equals('3'))
kw.Aggregate ();
else
{
XmlDocument xmlDoc = new XmlDocument();
XmlTextReader tr = new XmlTextReader("/root/kwtest.xml");
tr.Read();
xmlDoc.Load(tr);
XmlNode root = xmlDoc.FirstChild;
if (root == null)
{
Console.WriteLine("Root is null");
}
Console.WriteLine("Root is not null\n");
Console.WriteLine("Root Name \n" + root.Name);
Console.WriteLine("Wallet Name \n" + root.ChildNodes[0].Name);
Console.WriteLine("Folder Name \n" + root.ChildNodes[0].ChildNodes[0].Name);
Console.WriteLine("Type Name \n" + root.ChildNodes[0].ChildNodes[0].ChildNodes[0].Name);
Console.WriteLine("Secret Name \n" + root.ChildNodes[0].ChildNodes[0].ChildNodes[0].ChildNodes[0].Name);
XmlNode secret = root.ChildNodes[0].ChildNodes[0].ChildNodes[0].ChildNodes[0];
if (c[0].Equals('2'))
res =kw.Remove(secret);
else if (c[0].Equals('1'))
res = kw.SetSecret(secret);
}
}
}
Console.WriteLine("Result of Operation = " + res);
}
#endif
}
}