using System; using System.Diagnostics; using System.Text; using System.IO; using System.Net.Sockets; using System.Net; using System.Security.Cryptography; using System.Security.Permissions; using System.Security.Principal; using System.Threading; using System.Timers; using IndianHealthService.BMXNet.Net; using IndianHealthService.BMXNet.Services; using IndianHealthService.BMXNet.Model; using System.Windows.Forms; namespace IndianHealthService.BMXNet { /// /// BMXNetSessionConnection implements low-level connectivity to RPMS databases. /// [DnsPermission(SecurityAction.Assert, Unrestricted = true)] internal abstract class BMXNetSessionConnection { public BMXNetSessionConnection(BMXNetBroker aBroker) { this.Broker = aBroker; m_sWKID = "BMX"; m_sWINH = ""; m_sPRCH = ""; m_sWISH = ""; m_cHDR = ADEBHDR(m_sWKID, m_sWINH, m_sPRCH, m_sWISH); } protected BMXNetBroker _broker=null; public BMXNetBroker Broker { get { return _broker; } set { _broker=value;} } protected EncryptionProvider EncryptionProvider { get { return this.Broker.EncryptionProvider; } } #region RPX Fields private string m_sWKID; private string m_sWISH; private string m_sPRCH; private string m_sWINH; private string m_cHDR; protected string m_cAppContext; private string m_cDUZ; #endregion RPX Fields #region RPX Functions /// /// Given strInput = "13" builds "013" if nLength = 3. Default for nLength is 3. /// /// /// protected string ADEBLDPadString(string strInput) { return ADEBLDPadString(strInput, 3); } /// /// Given strInput = "13" builds "013" if nLength = 3 Default for nLength is 3. /// /// /// Default = 3 /// protected string ADEBLDPadString(string strInput, int nLength /*=3*/) { return strInput.PadLeft(nLength, '0'); } /// /// Concatenates zero-padded length of sInput to sInput /// Given "Hello" returns "004Hello" /// If nSize = 5, returns "00004Hello" /// Default for nSize is 3. /// /// /// protected string ADEBLDB(string sInput) { return ADEBLDB(sInput, 3); } /// /// Concatenates zero-padded length of sInput to sInput /// Given "Hello" returns "004Hello" /// If nSize = 5, returns "00004Hello" /// Default for nSize is 3. /// /// /// /// protected string ADEBLDB(string sInput, int nSize /*=3*/) { int nLen = sInput.Length; string sLen = this.ADEBLDPadString(nLen.ToString(), nSize); return sLen + sInput; } /// /// Build protocol header /// /// /// /// /// /// protected string ADEBHDR(string sWKID, string sWINH, string sPRCH, string sWISH) { string strResult; strResult = sWKID + ";" + sWINH + ";" + sPRCH + ";" + sWISH + ";"; strResult = ADEBLDB(strResult); return strResult; } protected string ADEBLDMsg(string cHDR, string cRPC, string cParam) { string sMult = ""; return ADEBLDMsg(cHDR, cRPC, cParam, ref sMult); } protected string ADEBLDPadString(int anInteger) { return ADEBLDPadString(anInteger.ToString(), 3); } protected string ADEBLDPadString(int anInteger, int nLength /*=3*/) { return this.ADEBLDPadString(anInteger.ToString(), nLength); } protected string ADEBLDMsg(string cHDR, string cRPC, string cParam, ref string cMult) { //Builds RPC message //Automatically splits parameters longer than 200 into subscripted array String body; cMult = ""; if (cParam == "") { body = "0" + cRPC; } else { StringBuilder parametersBuilder = new StringBuilder((int)(cParam.Length * 1.2)); int parameterCount = M.PieceLength(cParam, "^"); int maxChunkLength = 400; for (int j = 1; j <= parameterCount; j++) { String piece = M.Piece(cParam, "^", j); if (piece.Length > maxChunkLength) { if (j == parameterCount) { //Place holder for the long parameter String prefix = ".x"; parametersBuilder.Append(ADEBLDPadString(prefix.Length + 1) + "2" + prefix); StringBuilder encodedMultiPart = new StringBuilder((int)(piece.Length * 1.2)); int subscript = 1; int startChunk = 0; do { int chunkLength = Math.Min(piece.Length - startChunk, maxChunkLength); String chunk = piece.Substring(startChunk, chunkLength); String subscriptString = subscript.ToString(); encodedMultiPart.Append(ADEBLDPadString(subscriptString.Length)); encodedMultiPart.Append(subscriptString); encodedMultiPart.Append(ADEBLDPadString(chunk.Length)); encodedMultiPart.Append(chunk); subscript++; startChunk += chunkLength; } while (startChunk < piece.Length); cMult = encodedMultiPart.ToString(); } else { throw new BMXNetException("RPC parameter exceeds " + maxChunkLength.ToString() + ". Lone long parameter must be last."); } } else { parametersBuilder.Append(ADEBLDPadString(piece.Length + 1) + "0" + piece); } } String parameters = parametersBuilder.ToString(); body = (cMult.Length > 0 ? "1" : "0") + cRPC + "^" + ADEBLDPadString(parameters.Length, 5) + parameters; } return cHDR + ADEBLDB(body, 5); } public static int FindChar(byte[] c, char y) { int n = 0; int nRet = -1; for (n = 0; n < c.Length; n++) { if (y == (char)c[n]) { nRet = n; break; } } return nRet; } public static int FindChar(string s, char y) { int n = 0; int nRet = -1; foreach (char c in s) { if (y == c) { nRet = n; break; } n++; } return nRet; } /// /// Returns index of first instance of sSubString in sString. /// If sSubString not found, returns -1. /// /// /// /// public static int FindSubString(string sString, string sSubString) { int nFound = -1; int nLimit = sString.Length - sSubString.Length + 1; if (nLimit < 0) return -1; int nSubLength = sSubString.Length; for (int j = 0; j < nLimit; j++) { if (sString.Substring(j, nSubLength) == sSubString) { nFound = j; break; } } return nFound; } protected StreamWriter m_LogWriter; bool m_bLogging = false; public void StartLog() { try { if (m_bLogging) { throw new Exception("Already logging."); } string sFile = "BMXLog " + DateTime.Now.DayOfYear.ToString() + " " + DateTime.Now.Hour.ToString() + " " + DateTime.Now.Minute.ToString() + " " + DateTime.Now.Second.ToString() + ".log"; StartLog(sFile); return; } catch (Exception ex) { throw ex; } } public void StartLog(string LogFileName) { try { if (m_bLogging) { throw new Exception("Already logging."); } m_LogWriter = File.AppendText(LogFileName); m_bLogging = true; return; } catch (Exception ex) { throw ex; } } public void StopLog() { try { //Close the writer and underlying file. if (m_bLogging == false) { return; } m_LogWriter.Close(); m_bLogging = false; return; } catch (Exception ex) { throw ex; } } private static void Log(String logMessage, TextWriter w) { w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString()); w.WriteLine(" :"); w.WriteLine(" :{0}", logMessage); w.WriteLine("-------------------------------"); // Update the underlying file. w.Flush(); } public bool Lock(string Variable) { return Lock(Variable, "", ""); } public bool Lock(string Variable, string Increment) { return Lock(Variable, Increment, ""); } /// /// Lock a local or global M variable /// Returns true if lock is obtained during TimeOut seconds /// Use + to increment, - to decrement lock. /// /// /// /// /// public bool Lock(string Variable, string Increment, string TimeOut) { try { Variable = Variable.Replace("^", "~"); string sParam = Variable + "^" + Increment + "^" + TimeOut; string sRet = TransmitRPC("BMX LOCK", sParam); return (sRet == "1"); } catch (Exception ex) { string sMsg = ex.Message; return false; } } static ReaderWriterLock m_rwl = new ReaderWriterLock(); /// /// Returns a reference to the internal ReaderWriterLock member. /// public ReaderWriterLock BMXRWL { get { return m_rwl; } } public abstract bool IsConnected { get; } public abstract void Close(); protected string EncodeSendString(String cSendString, String cMulti) { String encoded = null; int nLen = cSendString.Length; string sLen = nLen.ToString(); sLen = sLen.PadLeft(5, '0'); encoded = sLen + cSendString; nLen += 15; sLen = nLen.ToString(); sLen = sLen.PadLeft(5, '0'); encoded = "{BMX}" + sLen + encoded; encoded = encoded + cMulti; return encoded; } protected string DecodeReceiveString(String aString) { return aString; } protected String SendReceiveString(String sendString) { return this.SendReceiveString(sendString, ""); } private String _createContextRpc = "BMX CREATE CONTEXT"; protected String CreateContextRpc { get { return _createContextRpc; } set { _createContextRpc = value; } } protected abstract String SendReceiveString(String sendString, String multi); public abstract int ReceiveTimeout { get; set; } public abstract int SendTimeout { get; set; } /// /// AppContext is managed an client and server with c/s calls to change /// appContext on the server. There is no use for AppContext on the client /// so recommend integrated AppContext into BMX Protocol so always passing /// it and managing switching it on the server. /// public string TransmitRPC(string anRpc, string rpcParameter) { this.AssertConnected(); if (rpcParameter.Length > 32600) { throw new Exception("RPC parameter length exceeds maximum allowable size."); } try { string sMult = ""; string sSend = ADEBLDMsg(m_cHDR, anRpc, rpcParameter, ref sMult); return this.SendReceiveString(sSend, sMult); } catch (ApplicationException exception) { // The writer lock request timed out. //TODO: Remark: to writer lock for Transmit RPC Debug.Write("TransmitRPC writer lock request timed out.\n"); throw exception; } catch (Exception problem) { throw problem; } } public abstract string GetLoginFacility(String aDuz); #endregion RPX Functions protected void AssertConnected() { if (!this.IsConnected) { throw new BMXNetException("BMXNetBroker.TransmitRPC failed because BMXNetBroker is not connected to RPMS."); } } private String _job = ""; public String Job { get { return _job; } set { _job = value; } } /// /// Gets/sets the Kernel Application context /// Throws an exception if unable to set the context. /// public string AppContext { get { return m_cAppContext; } set { if (m_cAppContext == value) return; //Send the changed context to RPMS if ((value != null) && (value != "")) { string encryptedContext = this.EncryptionProvider.Encrypt(value); string sAuthentication = this.TransmitRPC("BMX CREATE CONTEXT", encryptedContext); if (BMXNetBroker.FindSubString(sAuthentication, "does not have access to option") > -1) { throw new BMXNetException(sAuthentication); } if (BMXNetBroker.FindSubString(sAuthentication, "is not registered with port") > -1) { throw new BMXNetException(sAuthentication); } m_cAppContext = value; } } } public string DUZ { get { return m_cDUZ; } set { this.m_cDUZ = value; } } private EncryptionKeyProvider _keyProvider = null; public EncryptionKeyProvider KeyProvider { get { return _keyProvider; } set { _keyProvider = value; } } protected string RemoveADEEncryp(string sInput) { //Encrypt a string string strResult = null; string strPercent = null; string strAssoc = null; string strIdix = null; int nPercent = 0; int nAssocix = 0; int nIdix = 0; Debug.Assert(sInput != ""); System.Random rRand = new Random(DateTime.Now.Second); nPercent = rRand.Next(0, 10000); nPercent += 72439; nAssocix = nPercent % 20; nAssocix++; Debug.Assert(nAssocix < 21); strPercent = nPercent.ToString(); strPercent = strPercent.Substring(1, 2); nIdix = Convert.ToInt32(strPercent); nIdix = nIdix % 20; nIdix++; Debug.Assert(nIdix < 21); Debug.Assert(strAssoc.Length == 94); Debug.Assert(strIdix.Length == 94); string sEncrypted = ""; foreach (char c in sInput) { string d = c.ToString(); int nFindChar = strIdix.IndexOf(c); if (nFindChar > -1) { d = strAssoc.Substring(nFindChar, 1); } sEncrypted += d; } strResult = (char)(nIdix + 31) + sEncrypted + (char)(nAssocix + 31); return strResult; } protected string RemoveLoadKey(int nID) { nID -= 102; Debug.Assert(nID < 20); return this.KeyProvider.Keys[nID]; } internal string RemoveADEDecryp(string sInput) { //Encrypt a string string strAssoc = null; string strIdix = null; int nAssocix; int nIdix; Debug.Assert(sInput != ""); //get associator string index char cAssocix = sInput[sInput.Length - 1]; nAssocix = (int)cAssocix; nAssocix -= 31; Debug.Assert(nAssocix < 21); //get identifier string index char cIdix = sInput[0]; nIdix = (int)cIdix; nIdix -= 31; Debug.Assert(nIdix < 21); //get associator string Debug.Assert(strAssoc.Length == 94); Debug.Assert(strIdix.Length == 94); //translated result string sDecrypted = ""; sInput = sInput.Substring(1, sInput.Length - 2); foreach (char c in sInput) { string d = c.ToString(); int nFindChar = strAssoc.IndexOf(c); if (nFindChar > -1) { d = strIdix.Substring(nFindChar, 1); } sDecrypted += d; } return sDecrypted; } internal string RemoveBMXEncrypt(string sInput) { ASCIIEncoding textConverter = new ASCIIEncoding(); RijndaelManaged myRijndael = new RijndaelManaged(); byte[] encrypted; byte[] toEncrypt; byte[] key; byte[] IV; string sKey = "pouphfoz sfdbqjuvmbwft qizmphfoz"; string sIV = "Gichin Funakoshi"; key = textConverter.GetBytes(sKey); IV = textConverter.GetBytes(sIV); //Get an encryptor. ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV); //Encrypt the data. MemoryStream msEncrypt = new MemoryStream(); CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write); //Convert the input data to a byte array. toEncrypt = textConverter.GetBytes(sInput); //Write all data to the crypto stream and flush it. csEncrypt.Write(toEncrypt, 0, toEncrypt.Length); csEncrypt.FlushFinalBlock(); //Get encrypted array of bytes. encrypted = msEncrypt.ToArray(); //Convert to string to send to RPMS string sEncrypted = ""; byte bTmp; string sTmp; for (int j = 0; j < encrypted.Length; j++) { bTmp = encrypted[j]; sTmp = bTmp.ToString(); sEncrypted += sTmp; if (j < (encrypted.Length - 1)) sEncrypted += "~"; } return sEncrypted; } internal string BMXDecrypt(string sInput) { try { byte[] fromEncrypt; ASCIIEncoding textConverter = new ASCIIEncoding(); RijndaelManaged myRijndael = new RijndaelManaged(); string sRPMSEncrypted = sInput; string sBar = "~"; char[] cBar = sBar.ToCharArray(); string[] sArray; sArray = sRPMSEncrypted.Split(cBar); byte[] bRPMSEncrypted = new byte[sArray.GetLength(0)]; byte[] key; byte[] IV; //Convert the RPMS-stored string to a byte array for (int j = 0; j < sArray.GetLength(0); j++) { bRPMSEncrypted[j] = Byte.Parse(sArray[j]); } //Get a decryptor that uses the same key and IV as the encryptor. string sKey = "pouphfoz sfdbqjuvmbwft qizmphfoz"; string sIV = "Gichin Funakoshi"; key = textConverter.GetBytes(sKey); IV = textConverter.GetBytes(sIV); ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV); MemoryStream msDecrypt = new MemoryStream(bRPMSEncrypted); CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read); fromEncrypt = new byte[bRPMSEncrypted.Length - 2]; //Read the data out of the crypto stream. csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length); int nZ = FindChar(fromEncrypt, (char)0); //Convert the byte array back into a string. string sResult; if (nZ < 0) { sResult = textConverter.GetString(fromEncrypt); } else { sResult = textConverter.GetString(fromEncrypt, 0, nZ); } return sResult; } catch (Exception ex) { Debug.Write(ex.Message); return ""; } } private String _userName = null; public String UserName { get { if (_userName == null) { this._userName = this.TransmitRPC("BMX USER", this.DUZ); } return _userName; } set { _userName = value; } } } }