ec113054eb
Keyring
544 lines
23 KiB
C#
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
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|