/*********************************************************************** * * 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.Collections; using System.Collections.Specialized; using System.Text; using System.Threading; using sscs.verbs; using sscs.cache; using sscs.common; using sscs.constants; using System.Runtime.Serialization.Formatters.Binary; using System.IO; using Novell.CASA.MiCasa.Common; using Novell.CASA.MiCasa.Communication; namespace sscs.verbs { /* * There will be one instance existing for every call made by the client. */ internal class ObjectSerialization : SSVerb { private ushort msgId = 0; private uint inMsgLen = 0; private byte[] inBuf; private byte[] outBuf; /* * This method sets the class member with the byte array received. */ public void SetMessageContent(byte[] ipcBytes) { CSSSLogger.ExecutionTrace(this); inBuf = ipcBytes; } /* * This method does the actual implementation of ReadSecret * */ public byte[] ProcessRequest(UserIdentifier userId) { CSSSLogger.ExecutionTrace(this); /* If an exception occurs in message format decoding, * it is handled by AppHandler */ // Message Format decipher - Start msgId = BitConverter.ToUInt16(inBuf,0); inMsgLen = BitConverter.ToUInt32(inBuf,2); // check inMsgLen if ((inMsgLen < 6) || (inMsgLen > 65535)) { throw new FormatException(" MsgLen invalid."); } // deserialize the data BinaryFormatter formatter = new BinaryFormatter(); MemoryStream ms = new MemoryStream(inBuf, 6, (int)inMsgLen - 6); WrappedObject request; WrappedObject reply; try { request = (WrappedObject)formatter.Deserialize(ms); reply = ProcessMessage(request, userId); } catch (Exception e) { reply = new WrappedObject(-1, null); } // Serialize the WrappedObject and send the reply ms = new MemoryStream(); formatter.Serialize(ms, reply); int msLen = (int)ms.Length; outBuf = new byte[4+msLen]; byte[] t = new byte[10]; t = BitConverter.GetBytes(ms.Length); Array.Copy(t,0,outBuf,0,4); Array.Copy(ms.GetBuffer(), 0, outBuf, 4, msLen); SessionManager.RemoveUserSession(userId, false); return outBuf; } internal WrappedObject ProcessMessage(WrappedObject wo, UserIdentifier userId) { SecretStore ssStore = SessionManager.CreateUserSession(userId); try { int action = wo.GetAction(); switch (action) { case MiCasaRequestReply.VERB_PING_MICASAD: { return DoPing(wo); } case MiCasaRequestReply.VERB_SET_LINKED_KEY: { return DoSetLinkedKey(ssStore, wo); } case MiCasaRequestReply.VERB_REMOVE_LINKED_KEY: { return DoRemoveLinkedKey(ssStore, wo); } case MiCasaRequestReply.VERB_GET_LINKED_KEYS: { return DoGetLinkedKeys(ssStore, wo); } case MiCasaRequestReply.VERB_CREATE_TEST_SECRETS: { return DoCreateTestSecrets(ssStore, wo); } case MiCasaRequestReply.VERB_REMOVE_TEST_SECRETS: { return DoRemoveTestSecrets(ssStore, wo); } case MiCasaRequestReply.VERB_DUMP_LINKED_KEYS: { return DoDumpLinkedKeys(ssStore, wo); } case MiCasaRequestReply.VERB_WRITE_KEY: { return DoWriteKey(ssStore, wo); } case MiCasaRequestReply.VERB_LOCK_STORE: { ssStore.LockStore(); return wo; } case MiCasaRequestReply.VERB_UNLOCK_STORE: { return DoUnlockStore(ssStore, wo); } case MiCasaRequestReply.VERB_REMOVE_ALL_SECRETS: { // stop persistence //ssStore.StopPersistence(); // remove secrets return DoRemoveAllSecrets(ssStore, wo); } case MiCasaRequestReply.VERB_GET_STORE_STATUS: { wo.SetObject(ssStore.GetSecretStoreState()); return wo; } case MiCasaRequestReply.VERB_REMOVE_KEY: { return DoRemoveKey(ssStore, wo); } case MiCasaRequestReply.VERB_READ_KEY: { return DoReadKey(ssStore, wo); } case MiCasaRequestReply.VERB_GET_KEY_LIST: { return DoGetKeyList(ssStore, wo); } case MiCasaRequestReply.VERB_RESET_MASTER_PASSWORD: { return DoResetMasterPassword(ssStore, wo); } case MiCasaRequestReply.VERB_GET_SECRETIDS: { return DoGetSecretIDs(ssStore, wo); } default: { wo.SetError(constants.RetCodes.FAILURE, "Verb Not Supported"); return wo; } } } catch (Exception e) { wo.SetError(constants.RetCodes.FAILURE, e.ToString()); } return wo; } private WrappedObject DoGetSecretIDs(SecretStore ssStore, WrappedObject wo) { if (!ssStore.IsStoreLocked()) { // look up keychain string sKeyChainID = wo.GetKeychainID(); if (sKeyChainID != null) { KeyChain kc = ssStore.GetKeyChain(sKeyChainID); if (kc != null) { StringCollection sc = (StringCollection)wo.GetObject(); if (sc != null) { IDictionaryEnumerator etor = (IDictionaryEnumerator)kc.GetAllSecrets(); while(etor.MoveNext()) { string sID = (string)etor.Key; sID = sID.Substring(0, sID.Length - 1); sc.Add(UnescapeID(sID)); } } } else { wo.SetError(constants.RetCodes.FAILURE, "KeyChain not found"); } } } else { wo.SetError(constants.RetCodes.FAILURE, "Store locked"); } return wo; } private WrappedObject DoRemoveAllSecrets(SecretStore ssStore, WrappedObject wo) { if (!ssStore.IsStoreLocked()) { string sKeyChainID = wo.GetKeychainID(); if (sKeyChainID != null) { KeyChain kc = ssStore.GetKeyChain(sKeyChainID); kc.RemoveAllSecrets(); ssStore.UpdatePersistentStore(); } } else { wo.SetError(constants.RetCodes.FAILURE, "Store locked"); } return wo; } private WrappedObject DoUnlockStore(SecretStore ssStore, WrappedObject wo) { try { string sMasterPassword = (string)wo.GetObject(); ssStore.UnlockStore(null, sMasterPassword); } catch (Exception e) { wo.SetError(constants.RetCodes.FAILURE, e.ToString()); } return wo; } private WrappedObject DoRemoveKey(SecretStore ssStore, WrappedObject wo) { try { string keychainID = wo.GetKeychainID(); string secretID = wo.GetSecretID(); string keyID = wo.GetKeyID(); KeyChain keyChain = ssStore.GetKeyChain(keychainID); Secret secret = null; if( keyChain.CheckIfSecretExists(secretID) == false) { wo.SetError(constants.RetCodes.FAILURE,"Secret does not exist"); } else { secret = keyChain.GetSecret(secretID); secret.RemoveKeyValue(keyChain, keyID); wo.SetError(constants.RetCodes.SUCCESS, null); ssStore.UpdatePersistentStore(); } } catch (Exception e) { wo.SetError(constants.RetCodes.FAILURE, e.ToString()); } return wo; } private WrappedObject DoReadKey(SecretStore ssStore, WrappedObject wo) { if (!ssStore.IsStoreLocked()) { try { string keychainID = wo.GetKeychainID(); string secretID = wo.GetSecretID(); string keyID = wo.GetKeyID(); // string sValue = (String)wo.GetObject(); KeyChain keyChain = ssStore.GetKeyChain(keychainID); Secret secret = null; if( keyChain.CheckIfSecretExists(secretID) == false) { wo.SetError(constants.RetCodes.FAILURE,"Secret does not exist"); } else { secret = keyChain.GetSecret(secretID); KeyValue kv = secret.GetKeyValue(keyID); string value = kv.GetValue(); wo.SetObject(value); wo.SetError(constants.RetCodes.SUCCESS, null); } } catch (Exception e) { wo.SetError(constants.RetCodes.FAILURE, e.ToString()); } } else wo.SetError(constants.RetCodes.FAILURE, "Store locked"); return wo; } private WrappedObject DoGetKeyList(SecretStore ssStore, WrappedObject wo) { try { string keychainID = wo.GetKeychainID(); string secretID = wo.GetSecretID(); KeyChain keyChain = ssStore.GetKeyChain(keychainID); Secret secret = null; if( keyChain.CheckIfSecretExists(secretID) == false) { wo.SetError(constants.RetCodes.FAILURE,"Secret does not exist"); } else { secret = keyChain.GetSecret(secretID); if( null != secret ) { ArrayList keyList = secret.GetKeyList(); wo.SetObject(keyList); wo.SetError(constants.RetCodes.SUCCESS, null); } } } catch (Exception e) { wo.SetError(constants.RetCodes.FAILURE, e.ToString()); } return wo; } private WrappedObject DoWriteKey(SecretStore ssStore, WrappedObject wo) { if (!ssStore.IsStoreLocked()) { try { string keychainID = wo.GetKeychainID(); string secretID = wo.GetSecretID(); string keyID = wo.GetKeyID(); string sValue = (String)wo.GetObject(); if (secretID.IndexOf("*") < 0) { KeyChain keyChain = ssStore.GetKeyChain(keychainID); Secret secret; if( keyChain.CheckIfSecretExists(secretID) == false) { secret = new Secret(secretID); keyChain.AddSecret(secret); } else { secret = keyChain.GetSecret(secretID); } secret.SetKeyValue(keyID, sValue); ChangeLinkedKeys(keyChain, secret, keyID, sValue); wo.SetError(constants.RetCodes.SUCCESS, null); ssStore.UpdatePersistentStore(); } else wo.SetError(constants.RetCodes.FAILURE, null); } catch (Exception e) { wo.SetError(constants.RetCodes.FAILURE, e.ToString()); } } else wo.SetError(constants.RetCodes.FAILURE, "Store locked"); return wo; } private void ChangeLinkedKeys(KeyChain keyChain, Secret secret, string key, string valStr) { Hashtable htLinkedkeys = secret.GetLinkedKeys(key); if (htLinkedkeys != null) { // enumerate the hashtable, getting each secret/key and change it's value ICollection coll = htLinkedkeys.Values; IDictionaryEnumerator ienum = (IDictionaryEnumerator)coll.GetEnumerator(); LinkedKeyInfo linkedInfo; // = (LinkedKeyInfo)ienum.Current; while (ienum.MoveNext()) { linkedInfo = (LinkedKeyInfo)ienum.Value; // Get the target Secret Secret targetSecret = keyChain.GetSecret(linkedInfo.GetLinkedSecretID()); if (targetSecret != null) { // get target key value string targetKey = linkedInfo.GetLinkedKeyID(); string targetkv = targetSecret.GetKeyValue(targetKey).GetValue(); // if a change is required in the target, then call this method recursively using the TargetSecret if (!targetkv.Equals(valStr)) { // NOTE: ORDER IS IMPORTANT // first change this one targetSecret.SetKeyValue(linkedInfo.GetLinkedKeyID(), valStr); // now call the traget to change it's linked ones ChangeLinkedKeys(keyChain, targetSecret, targetKey, valStr); } } } } } private WrappedObject DoDumpLinkedKeys(SecretStore ssStore, WrappedObject wo) { // create 2 secrets string keychainID = wo.GetKeychainID(); KeyChain keyChain; Console.WriteLine("\r\n*********Dumping Linked Keys"); try { keyChain = ssStore.GetKeyChain(keychainID); } catch (Exception) { keyChain = new KeyChain(keychainID); ssStore.AddKeyChain(keyChain); } // enumerate all secrets IDictionaryEnumerator ienum = (IDictionaryEnumerator)keyChain.GetAllSecrets(); ienum.Reset(); while (ienum.MoveNext()) { string secretID = (string)ienum.Key; Secret secret = keyChain.GetSecret(secretID); IDictionaryEnumerator idenum = secret.GetKeyValueEnumerator(); idenum.Reset(); while (idenum.MoveNext()) { KeyValue kv = (KeyValue)idenum.Value; Hashtable htLKI = kv.GetLinkedKeys(); if (htLKI != null) { Console.WriteLine(secret.GetKey() + ":" + kv.Key + " is Linked to"); IDictionaryEnumerator htienum = (IDictionaryEnumerator)htLKI.GetEnumerator(); htienum.Reset(); while (htienum.MoveNext()) { LinkedKeyInfo lki = (LinkedKeyInfo) htienum.Value; Console.WriteLine(" " + lki.GetLinkID()); } } } } return wo; } string GW = "SS_CredSet:TestGroupwise\0"; string IFOLDER = "SS_CredSet:TestiFolder\0"; string GWIM = "SS_CredSet:TestGWIM\0"; private WrappedObject DoRemoveTestSecrets(SecretStore ssStore, WrappedObject wo) { string keychainID = wo.GetKeychainID(); KeyChain keyChain; try { keyChain = ssStore.GetKeyChain(keychainID); } catch (Exception) { return wo; } try { keyChain.RemoveSecret(GW); } catch (Exception) {} try { keyChain.RemoveSecret(GWIM); } catch (Exception) {} try { keyChain.RemoveSecret(IFOLDER); } catch (Exception) {} return wo; } private WrappedObject DoCreateTestSecrets(SecretStore ssStore, WrappedObject wo) { // create 2 secrets string keychainID = wo.GetKeychainID(); KeyChain keyChain; try { keyChain = ssStore.GetKeyChain(keychainID); } catch (Exception) { keyChain = new KeyChain(keychainID); ssStore.AddKeyChain(keyChain); } Secret secret1 = GetOrCreateSecret(keyChain, GW); secret1.SetKeyValue("CN", "User1"); secret1.SetKeyValue("Password", "GWPass"); try { keyChain.AddSecret(secret1); } catch (Exception) {} Secret secret2 = GetOrCreateSecret(keyChain, IFOLDER); secret2.SetKeyValue("CN", "User2"); secret2.SetKeyValue("Password", "IfolderPass"); secret2.SetKeyValue("EmployeeID", "123456"); try { keyChain.AddSecret(secret2); } catch (Exception) {} Secret secret3 = GetOrCreateSecret(keyChain,GWIM); secret3.SetKeyValue("CN", "User3"); secret3.SetKeyValue("Password", "GwimPass"); try { keyChain.AddSecret(secret3); } catch (Exception) {} try { // link password fields KeyValue kv = secret1.GetKeyValue("Password"); KeyValue kv2 = secret2.GetKeyValue("Password"); KeyValue kv3 = secret3.GetKeyValue("Password"); kv.AddLink(new LinkedKeyInfo(IFOLDER, "Password")); kv2.AddLink(new LinkedKeyInfo(GW, "Password")); kv2.AddLink(new LinkedKeyInfo(GWIM, "Password")); kv3.AddLink(new LinkedKeyInfo(IFOLDER, "Password")); kv3.AddLink(new LinkedKeyInfo(GW, "Password")); kv.AddLink(new LinkedKeyInfo(GWIM, "Password")); } catch (Exception e) { //Console.WriteLine(e.ToString()); } #if DEBUG DoDumpLinkedKeys(ssStore, wo); #endif return wo; } private Secret GetOrCreateSecret(KeyChain kc, string sID) { try { return kc.GetSecret(sID); } catch (Exception) { return new Secret(sID); } } private WrappedObject DoGetLinkedKeys(SecretStore ssStore, WrappedObject wo) { string keychainID = wo.GetKeychainID(); string secretID = wo.GetSecretID(); string keyID = wo.GetKeyID(); KeyChain keyChain = ssStore.GetKeyChain(keychainID); Secret secret = keyChain.GetSecret(secretID); KeyValue kv = secret.GetKeyValue(keyID); wo.SetObject(kv.GetLinkedKeys()); wo.SetError(constants.RetCodes.SUCCESS, null); return wo; } private WrappedObject DoRemoveLinkedKey(SecretStore ssStore, WrappedObject wo) { string keychainID = wo.GetKeychainID(); string secretID = wo.GetSecretID(); string keyID = wo.GetKeyID(); KeyChain keyChain = ssStore.GetKeyChain(keychainID); Secret secret = keyChain.GetSecret(secretID); KeyValue kv = secret.GetKeyValue(keyID); LinkedKeyInfo lki = (LinkedKeyInfo)wo.GetObject(); kv.RemoveLink(lki.GetLinkID()); // remove reverse link as well Secret targetSecret = keyChain.GetSecret(lki.GetLinkedSecretID()); KeyValue targetkv = targetSecret.GetKeyValue(lki.GetLinkedKeyID()); targetkv.RemoveLink(secretID+":"+keyID); ssStore.UpdatePersistentStore(); return wo; } private WrappedObject DoSetLinkedKey(SecretStore ssStore, WrappedObject wo) { string keychainID = wo.GetKeychainID(); string secretID = wo.GetSecretID(); string keyID = wo.GetKeyID(); KeyChain keyChain = ssStore.GetKeyChain(keychainID); Secret secret = keyChain.GetSecret(secretID); KeyValue kv = secret.GetKeyValue(keyID); LinkedKeyInfo lki = (LinkedKeyInfo)wo.GetObject(); kv.AddLink(lki); // add reverse link try { Secret target = keyChain.GetSecret(lki.GetLinkedSecretID()); KeyValue targetkv = target.GetKeyValue(lki.GetLinkedKeyID()); targetkv.AddLink(new LinkedKeyInfo(secretID, keyID, true)); ssStore.UpdatePersistentStore(); } catch (Exception e) { //Console.WriteLine("Reverse Link error: " + e.ToString()); wo.SetError(constants.RetCodes.FAILURE, "Reverse Link: " + e.ToString()); } return wo; } private WrappedObject DoResetMasterPassword(SecretStore ssStore, WrappedObject wo) { ResetMasterPassword rmp = (ResetMasterPassword)wo.GetObject(); // verify current master password try { string sMasterPassword = rmp.m_currentPassword; ssStore.UnlockStore(null, sMasterPassword); } catch (Exception e) { wo.SetError(constants.RetCodes.FAILURE, e.ToString()); return wo; } // change master master password string sNewPassword = rmp.m_newPassword; if (sNewPassword == null || sNewPassword.Length < 8) { wo.SetError(constants.RetCodes.FAILURE, null); return wo; } if (!ssStore.ChangeMasterPassword(rmp.m_currentPassword, rmp.m_newPassword)) wo.SetError(constants.RetCodes.FAILURE, null); else wo.SetError(constants.RetCodes.SUCCESS, null); return wo; } private WrappedObject DoPing(WrappedObject wo) { //Console.WriteLine("MICASAD received Ping from Client"); wo.SetError(IPCRetCodes.SSCS_REPLY_SUCCESS, null); Ping ping = (Ping)wo.GetObject(); ping.servermessage = "MICASAD echos client message: <" + ping.clientmessage + ">"; return wo; } /* internal WrappedObject ProcessMessage(WrappedObject wo, UserIdentifier userId) { Console.WriteLine("ObjectSerialization Called"); SecretStore ssStore = SessionManager.CreateUserSession(userId); Secret secret; try { keyChainId = wo.GetKeychainID(); secretId = wo.GetSecretID(); keyId = wo.GetKeyID(); int action = wo.GetAction(); if (action == WrappedObject.VERB_PING_MICASAD) { Console.WriteLine("MICASAD received Ping from Client"); wo.SetError(IPCRetCodes.SSCS_REPLY_SUCCESS, null); Ping ping = (Ping)wo.GetObject(); ping.servermessage = "MICASAD echos client message: <" + ping.clientmessage + ">"; return wo; } else if (action <= WrappedObject.VERB_REMOVE_LINKED_KEY) { wo.SetError(IPCRetCodes.SSCS_REPLY_SUCCESS, null); if (action == WrappedObject.VERB_GET_STORE) { wo.SetObject(ssStore); return wo; } // look up Keychain KeyChain keyChain = new KeyChain(keyChainId); // temporary try { if (true) ssStore.AddKeyChain(keyChain); } catch (Exception e) { } if( ssStore.CheckIfKeyChainExists(keyChainId) ) { keyChain = ssStore.GetKeyChain(keyChainId); if (action == WrappedObject.VERB_GET_KEYCHAIN) { wo.SetObject(keyChain); return wo; } if((action == WrappedObject.VERB_GET_SECRET) && (keyChain.CheckIfSecretExists(secretId) == false)) { wo.SetError(IPCRetCodes.SSCS_E_SECRETID_DOES_NOT_EXIST, null); return wo; } else { secret = keyChain.GetSecret(secretId); if (action == WrappedObject.VERB_GET_SECRET) { wo.SetObject(secret); return wo; } else if ((action == WrappedObject.VERB_SET_SECRET) && (null != wo.GetObject())) { keyChain.AddSecret((Secret)wo.GetObject()); } else if (action == WrappedObject.VERB_SET_LINKED_KEY) { KeyValue kv = secret.GetKeyValue(keyId); LinkedKeyInfo lki = (LinkedKeyInfo)wo.GetObject(); kv.AddLink(lki); // add reverse link try { Secret target = keyChain.GetSecret(lki.GetLinkedSecretID()); KeyValue targetkv = target.GetKeyValue(lki.GetLinkedKeyID()); targetkv.AddLink(new LinkedKeyInfo(secretId, keyId)); } catch (Exception e) { Console.WriteLine("Reverse Link error: " + e.ToString()); } } } } else { wo.SetError(IPCRetCodes.SSCS_E_KEYCHAIN_DOES_NOT_EXIST, null); } } else { wo.SetError(IPCRetCodes.SSCS_E_SYSTEM_ERROR, "Action not supported"); } } catch (Exception e) { String error = e.ToString(); Console.WriteLine(error); wo = new WrappedObject(constants.RetCodes.FAILURE, error); } return wo; } */ private static string UnescapeID(string sOrig) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < sOrig.Length; i++) { if (sOrig[i] == ('\\')) { if (i + 1 < sOrig.Length) { if (sOrig[i + 1] == (':') || sOrig[i + 1] == ('\\') || sOrig[i + 1] == ('=')) { sb.Append(sOrig[i + 1]); i++; } } else sb.Append(sOrig[i]); } else sb.Append(sOrig[i]); } return sb.ToString(); } public string GetVerbName() { CSSSLogger.ExecutionTrace(this); return this.ToString(); } } }