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 } }