You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafodion.apache.org by db...@apache.org on 2016/05/02 18:12:09 UTC
[30/60] incubator-trafodion git commit: TRAFODION-1933 JDBC TYpe4
driver build scripts migrated to use maven instead of ant
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecPwd.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecPwd.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecPwd.java
new file mode 100644
index 0000000..60da5da
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecPwd.java
@@ -0,0 +1,274 @@
+/**********************************************************************
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+ //
+ **********************************************************************/
+
+/**
+ * class SecPwd - builds the password key, encrypts password,
+ * creates HMAC message based on password, rolename
+ * process info and time stamp. It also gets expiration
+ * date of a certificate.
+ *
+ */
+
+package org.trafodion.jdbc.t4;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.sql.Connection;
+
+
+public class SecPwd {
+ /**
+ *
+ *
+ * @return SecPwd
+ */
+ public static SecPwd getInstance(Connection con, String directory, String fileName,
+ String serverName, boolean spjMode, byte[] procInfo) throws SecurityException
+ {
+ if (con == null)
+ throw new SecurityException(SecClientMsgKeys.INPUT_PARAMETER_IS_NULL, new Object[]{"connection"});
+ SecPwd secpwd = new SecPwd(directory, fileName, serverName, spjMode, procInfo);
+
+ SymCrypto.insert(con, secpwd);
+
+
+ return secpwd;
+ }
+
+ public static void removeInstance(Connection con)
+ {
+ SymCrypto.remove(con);
+ }
+
+ /**
+ * Ctor for the SecPwd. There are two possible certificates: active
+ * certificate and certificate that is going to be active.
+ *
+ * If autodownload is true, certificate will always come from the
+ * server. In this case, only active certificate is used.
+ *
+ * If autodownload is false, active certificate is used to encrypt the
+ * password. When there is a new certificate, it will be stored in
+ * "certificate". As soon as this new certificate is activated on the
+ * server, the current active certificate will become stale, and the new
+ * certificate will be copied over and becomes the active certificate.
+ *
+ * If spjMode is true, the OS name is NONSTOP_KERNEL and the host name
+ * is the same as the server name then just setSpj mode to true
+ * and does nothing.
+ *
+ * @param directory
+ * specifies the directory to locate the certificate. The default
+ * value is %HOME% if set else %HOMEDRIVE%%HOMEPATH%.
+ * @param fileName
+ * specifies the certificate that is in waiting. The default
+ * value is the first 5 characters of server name.
+ * @param activeFileName
+ * specifies the current certificate in use. The default value is
+ * the first 5 character of server name + Active
+ * @param spjMode
+ * true - and if os.name == NSK and the host name
+ * matches the local host - token case. Certificate is not
+ * handled in this case.
+ * false - handles certificate
+ * @param serverName
+ * server name for this certificate.
+ * @throws SecurityException
+ */
+ private SecPwd(String directory, String fileName,
+ String serverName, boolean spjMode, byte[] procInfo) throws SecurityException {
+ String hostName = null;
+
+ try {
+ hostName = java.net.InetAddress.getLocalHost().getHostName();
+ } catch (java.net.UnknownHostException ex) {
+ throw new SecurityException(
+ SecClientMsgKeys.GET_LOCAL_HOST_NAME_FAILED, null);
+ }
+
+ // check USERID env variable for MXCI testing of SPJs. If set use normal password
+ // encryption
+ if ((spjMode == true) &&
+ // ((hostName.substring(0, 5)).compareToIgnoreCase(serverName.substring(0, 5)) == 0) &&
+ (System.getenv("USERID") == null))// token
+ {
+ m_spjMode = spjMode;
+ }
+ else // password
+ {
+ if (procInfo == null)
+ throw new SecurityException(SecClientMsgKeys.INPUT_PARAMETER_IS_NULL, new Object[]{"procInfo"});
+ // Stores procInfo with the time stamp for data message encryption used
+ m_procInfo = new byte [SecdefsCommon.PROCINFO_SIZE + SecdefsCommon.TIMESTAMP_SIZE];
+ System.arraycopy(procInfo, 0, m_procInfo, 0, (SecdefsCommon.PROCINFO_SIZE + SecdefsCommon.TIMESTAMP_SIZE));
+ directory = (directory != null) ? directory : System.getenv("HOME");
+ if (directory == null)
+ {
+ String hmdrive = System.getenv("HOMEDRIVE");
+ String hmpath = System.getenv("HOMEPATH");
+ if (hmdrive != null && hmpath != null)
+ {
+ directory = hmdrive + File.separator + hmpath;
+ }
+ else
+ {
+ directory = System.getProperty("user.home");
+ if (directory == null)
+ throw new SecurityException (SecClientMsgKeys.HOME_ENVIRONMENT_VAR_IS_NULL, null);
+ }
+ }
+ fileName = (fileName != null) ? fileName : serverName + ".cer";
+
+ File dir = new File(directory);
+ if (dir.isDirectory() == false)
+ throw new SecurityException(SecClientMsgKeys.DIR_NOTFOUND, new Object[]{dir.getPath()});
+
+ certFile = new File(directory, fileName);
+ }
+ }
+
+ /**
+ * Processes the active certificate when spjMode is false
+ * else does nothing. The certificate is processed by calling
+ * the Security ctor to creates the password key and initializes it
+ * with password id. Gets public key and the length of the public
+ * key from the certificate file. Generates nonce and session key.
+ * @throws SecurityException
+ */
+ public void openCertificate() throws SecurityException {
+ if (m_spjMode == false) // do nothing for the token case
+ m_sec = new Security(certFile);
+ }
+
+ /** This method builds the password key which consists 4 bytes of password id,
+ * 128 bytes of role name which would be 128 spaces when role name is null,
+ * 32 bytes of the digest message calculated using the session key on the data made up of
+ * the procInfo and the encrypted data and 256 bytes (if the 2048 public key is used) or
+ * 128 bytes (if the1024 public key is used) encrypted data calculated using the public key
+ * on the plain text made up of the session key, the nonce and the password.
+ * The password key is generated only when the spjMode is false. When
+ * the spjMode is true, 26 bytes of the token is returned instead.
+ * Builds password key
+ * @param pwd
+ * password to be encrypted
+ * @param rolename
+ * role name to build password key
+ * @param procInfo
+ * process information (PIN, CPU, segment name and time stamp)
+ * @return pwdkey
+ * returns the password key if spjMode is false
+ * returns the token when spjMode is true
+ * @throws SecurityException
+ */
+
+ public void encryptPwd(byte[] pwd, byte[] rolename, byte[] pwdkey) throws SecurityException {
+ // rolename is optional so can be NULL
+ if (pwd == null)
+ throw new SecurityException(SecClientMsgKeys.INPUT_PARAMETER_IS_NULL, new Object[]{"password"});
+ if (pwdkey == null)
+ throw new SecurityException(SecClientMsgKeys.INPUT_PARAMETER_IS_NULL, new Object[]{"password key"});
+ if (m_spjMode == true) // token
+ {
+ if (pwd.length != SecdefsCommon.TOKENSIZE)
+ throw new SecurityException(SecClientMsgKeys.BAD_TOKEN_LEN, null);
+ if ((pwd[0] != SecdefsCommon.USERTOKEN_ID_1)
+ || (pwd[1] != SecdefsCommon.USERTOKEN_ID_2))
+ throw new SecurityException(
+ SecClientMsgKeys.INCORRECT_TOKEN_FORMAT, null);
+ ByteBuffer.wrap(pwd).get(pwdkey, 0, SecdefsCommon.TOKENSIZE);
+ }
+ else
+ {
+ m_sec.encryptPwd(pwd, rolename, m_procInfo, pwdkey);
+ }
+ }
+
+ /** Gets length of buffer for password encryption (public)
+ * or the length of the token if it is the SPJ mode
+ * @returns
+ * If the spjMode is false
+ * the length of the password key is returnd if success
+ * 0 if failed
+ * If spjMode is true
+ * the length of the token is returned
+ * @throws SecurityException
+ */
+ public int getPwdEBufferLen() throws SecurityException {
+ if (m_spjMode == true)
+ return SecdefsCommon.TOKENSIZE;
+ else
+ return m_sec.getPwdEBufferLen();
+ }
+
+ /** Gets the expiration date of the certificate
+ * @return an array of bytes
+ * presents the certificate's
+ * expiration day in the format YYMMDDHHMMSS
+ * or a zero length byte array if the it is in the SPJ mode
+ */
+ public byte[] getCertExpDate() {
+ if (m_spjMode == false)
+ return m_sec.getCertExpDate();
+ else
+ return new byte[0];
+ }
+
+ /**
+ * When autodownload is on, client will download the certificate from server
+ * when there is no certificate or certificate is stale.
+ *
+ * @param buf
+ * content of the certificate pushed from server.
+ */
+ public void switchCertificate(byte[] buf) throws SecurityException {
+ FileChannel outChannel = null;
+ try {
+ outChannel = new FileOutputStream(certFile).getChannel();
+ outChannel.write(ByteBuffer.wrap(buf));
+ } catch (Exception e) {
+ throw new SecurityException(SecClientMsgKeys.ERR_WRITE_CERT_FILE, new Object[]{certFile});
+ } finally {
+ try {
+ if (outChannel != null)
+ outChannel.close();
+ } catch (Exception e) {
+ }
+ }
+ m_sec = new Security(certFile);
+ }
+
+ public byte[] getProcInfo()
+ {
+ return m_procInfo;
+ }
+
+ private Security m_sec;
+ private File certFile;
+ private boolean m_spjMode;
+ private byte[] m_procInfo; //stores only 4 bytes pid + 4 bytes nid
+
+
+};
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecResourceBundle.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecResourceBundle.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecResourceBundle.java
new file mode 100644
index 0000000..5400d55
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecResourceBundle.java
@@ -0,0 +1,57 @@
+/**********************************************************************
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+//
+**********************************************************************/
+
+package org.trafodion.jdbc.t4;
+
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+
+public class SecResourceBundle
+{
+
+ private static ResourceBundle rb = ResourceBundle.getBundle("secClient");
+
+ /**
+ * This method is used to obtain parameterized message text
+ *
+ */
+ static String obtainMessageText (String key, Object[] params) {
+ String pattern;
+ try {
+ pattern = rb.getString(key);
+ } catch (Exception e) {
+ return key;
+ }
+ if(pattern == null) {
+ return key;
+ }
+ String message;
+ try {
+ message = MessageFormat.format(pattern, params);
+ } catch (Exception e) {
+ return pattern;
+ }
+ return message;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecdefsCommon.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecdefsCommon.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecdefsCommon.java
new file mode 100644
index 0000000..f003588
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecdefsCommon.java
@@ -0,0 +1,84 @@
+/**********************************************************************
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+//
+**********************************************************************/
+
+package org.trafodion.jdbc.t4;
+
+/**
+ * This class contains defines
+ *
+ */
+
+public class SecdefsCommon {
+
+ public static final int NONCE_RANDOM = 24;
+ public static final int NONCE_SEQNUM = 8;
+ public static final int NONCE_SIZE = (NONCE_RANDOM+NONCE_SEQNUM);
+ public static final int SESSION_KEYLEN = 32;
+ public static final int DIGEST_LENGTH = 32;
+ // AES block size used in data encryption
+ public static final int AES_BLOCKSIZE = 16;
+ public static final int KEY_REFRESH = 30;
+ public static final int TIMESTAMP_SIZE = 8;
+ public static final int ROLENAME_SIZE = 128;
+ public static final int PROCINFO_SIZE = 8;
+ public static final int PWDID_SIZE = 4;
+ public static final int EXPDATESIZE = 12;
+ public static final int PWDKEY_SIZE_LESS_LOGINDATA = (PWDID_SIZE + ROLENAME_SIZE + DIGEST_LENGTH + TIMESTAMP_SIZE);
+ // For public key encryption, the number of bytes
+ // to be encrypted is 11 bytes less than the public key length
+ public static final int UNUSEDBYTES = 11;
+ public static final int TOKENSIZE = 68;
+ // User tokens begin with byte values 3,4.
+ public static final byte USERTOKEN_ID_1 = '\3'; // User token identifier, must be a sequence
+ public static final byte USERTOKEN_ID_2 = '\4'; // not allowed in password
+ public static final int DATA_BLOCK_BIT_SIZE = 128; // data encryption block size in bits. Java
+ // supports block size of 128 bits for AES
+ // algorithm using cryptographic key of 256 bits only.
+
+
+ // Structure used to describe layout of Encrypted data
+ // in login message
+ public static class LoginData {
+ //000 Session key
+ byte[] session_key = new byte[SecdefsCommon.SESSION_KEYLEN];
+ //032 Nonce
+ byte[] nonce = new byte[SecdefsCommon.NONCE_SIZE];
+ Byte password; // 064 User's password
+ } // 128 for 1024 or 256 for 2048
+
+// Structure used to describe layout of password key
+
+ public static class PwdKey {
+ //000 Key identifier, binary values 1,2,3,4
+ //or 1,2,2,4 keys, optional mode only
+ byte[] id= new byte[SecdefsCommon.PWDID_SIZE];
+ //004 RolenameA
+ byte[] rolename = new byte[SecdefsCommon.ROLENAME_SIZE];
+ //132 Digest of server id and encrypted data
+ byte[] digest = new byte[SecdefsCommon.DIGEST_LENGTH];
+ // 164 time stamp
+ byte[] ts = new byte[SecdefsCommon.TIMESTAMP_SIZE];
+ LoginData data; //172 Encrypted data
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/Security.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/Security.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/Security.java
new file mode 100644
index 0000000..1a02021
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/Security.java
@@ -0,0 +1,319 @@
+/**********************************************************************
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+//
+**********************************************************************/
+
+package org.trafodion.jdbc.t4;
+
+import java.nio.ByteBuffer;
+import java.security.SecureRandom;
+import java.util.Date;
+import java.security.NoSuchAlgorithmException;
+import java.io.File;
+import javax.crypto.SecretKey;
+
+
+
+class Security
+{
+ public static final Cipher cipher = org.trafodion.jdbc.t4.Cipher.getInstance();
+ public static final MessageDigest msgDigest = MessageDigest.getInstance();
+
+ /** Ctor - Creates the password key and initializes it with
+ * password id. Gets public key and the length of the public key
+ * from the certificate file. Generates nonce and session key.
+ * @param cert_file - fully qualified name of certificate file
+ * @throw SecurityException
+ */
+ public Security(File certFile) throws SecurityException
+ {
+ // m_encrypted = 0;
+ m_pwdkey = new SecdefsCommon.PwdKey();
+ m_pwdkey.data = new SecdefsCommon.LoginData();
+ m_pwdkey.id[0] = '\1';
+ m_pwdkey.id[1] = '\2';
+ m_pwdkey.id[2] = '\3';
+ m_pwdkey.id[3] = '\4';
+
+ try {
+ m_keyObj = new Key();
+ m_cert = new Certificate(certFile);
+ m_keyObj.getPubKeyFromFile(m_cert.getCert());
+ generateSessionKey();
+ }catch (SecurityException se) {
+ throw se;
+ }
+ }
+
+ /** This method builds the password key which consists 4 bytes of password id,
+ * 128 bytes of role name which would be 128 spaces when role name is null,
+ * 32 bytes of the digest message calculated using the session key on the data made up of
+ * the procInfo and the encrypted data and 256 bytes (if the 2048 public key is used) or
+ * 128 bytes (if the1024 public key is used) encrypted data calculated using the public key
+ * on the plain text made up of the session key, the nonce and the password.
+ * Builds password key
+ * @param pwd
+ * password to be encrypted
+ * @param rolename
+ * role name to build password key
+ * @param procInfo
+ * process information (PIN, CPU, segment name and time stamp)
+ * @return pwdkey
+ * returned password key
+ * @throws SecurityException
+ */
+ public void encryptPwd(byte[] pwd, byte[] rolename, byte[] procInfo,
+ byte[] pwdkey)
+ throws SecurityException
+ {
+ // Get public key length
+ int pubKeyLen = m_keyObj.getPubKeyLen();
+ int maxPlainTextLen = pubKeyLen - SecdefsCommon.UNUSEDBYTES;
+
+ // Password + nonce + session key can't be longer than the public
+ // key's length
+ if ((SecdefsCommon.NONCE_SIZE + SecdefsCommon.SESSION_KEYLEN
+ + pwd.length) > maxPlainTextLen)
+ throw new SecurityException(SecClientMsgKeys.
+ PWD_LENGTH_TOO_LONG, null);
+
+ byte[] to_encrypt = new byte[SecdefsCommon.SESSION_KEYLEN +
+ SecdefsCommon.NONCE_SIZE + pwd.length];
+ byte[] cipherText = new byte[pubKeyLen];
+ byte[] to_digest = new byte[SecdefsCommon.PROCINFO_SIZE +
+ SecdefsCommon.TIMESTAMP_SIZE + pubKeyLen];
+ byte[] digestedMsg = new byte[SecdefsCommon.DIGEST_LENGTH];
+
+ try {
+ // Build password key
+ // Copy 4 bytes of id
+ System.arraycopy(m_pwdkey.id, 0, pwdkey, 0, SecdefsCommon.PWDID_SIZE);
+ // Copy rolename
+ if (rolename != null)
+ System.arraycopy(rolename, 0, pwdkey, SecdefsCommon.PWDID_SIZE,
+ rolename.length);
+ // Copy 12 bytes of procInfo and 8 bytes of timestamp to
+ // password key store procInfo in the digest starting from
+ // digest[20]
+ System.arraycopy(procInfo, 0, pwdkey, (SecdefsCommon.PWDID_SIZE +
+ SecdefsCommon.ROLENAME_SIZE + SecdefsCommon.DIGEST_LENGTH -
+ SecdefsCommon.PROCINFO_SIZE), (SecdefsCommon.PROCINFO_SIZE +
+ SecdefsCommon.TIMESTAMP_SIZE));
+
+ // Build plain text to encrypt
+ System.arraycopy(m_pwdkey.data.session_key, 0, to_encrypt, 0,
+ SecdefsCommon.SESSION_KEYLEN);
+ System.arraycopy(m_pwdkey.data.nonce, 0, to_encrypt,
+ SecdefsCommon.SESSION_KEYLEN, SecdefsCommon.NONCE_SIZE);
+ System.arraycopy(pwd, 0, to_encrypt,
+ (SecdefsCommon.SESSION_KEYLEN + SecdefsCommon.NONCE_SIZE), pwd.length);
+
+ // Encrypt the data
+ int cipherTextLen = cipher.encrypt(to_encrypt, cipherText,
+ (java.security.Key)(m_keyObj.getPubKey()));
+
+ if(cipherTextLen != pubKeyLen)
+ throw new SecurityException(SecClientMsgKeys.
+ CIPHER_TEXT_LEN_NOT_EQUAL_KEY_LEN, null);
+
+ // Copy cipherText to pwdkey
+ System.arraycopy(cipherText, 0, pwdkey,
+ SecdefsCommon.PWDKEY_SIZE_LESS_LOGINDATA, cipherTextLen);
+
+ // Create digest
+ // Get bytes from digest[20] on
+ System.arraycopy(pwdkey, (SecdefsCommon.PWDKEY_SIZE_LESS_LOGINDATA -
+ SecdefsCommon.TIMESTAMP_SIZE - SecdefsCommon.PROCINFO_SIZE),
+ to_digest, 0, (SecdefsCommon.PROCINFO_SIZE +
+ SecdefsCommon.TIMESTAMP_SIZE + cipherTextLen));
+
+ int mdLen = msgDigest.digest(m_pwdkey.data.session_key,
+ to_digest, digestedMsg);
+
+ if (mdLen != SecdefsCommon.DIGEST_LENGTH)
+ throw new SecurityException(SecClientMsgKeys.
+ BAD_MESSAGE_DIGEST_LEN, null);
+
+ // copy digestedMsg into pwdkey
+ System.arraycopy(digestedMsg, 0, pwdkey,
+ (SecdefsCommon.PWDKEY_SIZE_LESS_LOGINDATA
+ - SecdefsCommon.TIMESTAMP_SIZE - SecdefsCommon.DIGEST_LENGTH), mdLen );
+
+ }catch (SecurityException se) {
+ throw se;
+ }catch (Exception e) {
+ throw new SecurityException(SecClientMsgKeys.FAILED_BUILDING_PWDKEY, null);
+ }finally {
+ if (to_digest != null)
+ to_digest = null;
+ if (digestedMsg != null)
+ digestedMsg = null;
+ if (to_encrypt != null)
+ to_encrypt = null;
+ }
+ }
+
+ /** Encrypts the data using AES256 algorithm.
+ *
+ * @param data - data to be encrypted
+ * @return array of bytes of 2 bytes PIN,
+ * 2 bytes of CPU, 8 bytes of seg_name
+ * and the encrypted data
+ * @throw SecurityException
+ */
+
+ public byte[] encryptData(byte[] data) throws SecurityException
+ {
+ //Creates a secret key from the session key
+ byte[] skey = new byte[SecdefsCommon.AES_BLOCKSIZE];
+ System.arraycopy(m_pwdkey.data.session_key, SecdefsCommon.AES_BLOCKSIZE,
+ skey, 0, SecdefsCommon.AES_BLOCKSIZE);
+ SecretKey seckey = Key.generateSymmetricKey(skey);
+ byte [] iv = new byte [SecdefsCommon.AES_BLOCKSIZE];
+ System.arraycopy(m_pwdkey.data.nonce, SecdefsCommon.AES_BLOCKSIZE,
+ iv, 0, SecdefsCommon.AES_BLOCKSIZE);
+ m_cipher = Cipher.getEASInstance("AES/CBC/PKCS5Padding");
+ return Cipher.encryptData(data, seckey, iv, m_cipher);
+ }
+
+ // Currently not implemented
+ // Generate message digest
+ // str - message to digest
+ // hmacMsg - Hashed message in bytes
+ // hmacMsgLen - Length of hashed message
+ public void HMAC_Message_Generate(byte[] str, byte[] hmacMsg,
+ int hmacMsgLen) throws SecurityException
+ {
+ // Not implemented yet
+ }
+
+ // Currently not implemented
+ // Verify message digest
+ // str - message digest
+ // length - message digest length
+ public boolean HMAC_Message_Verify(byte[] str) throws SecurityException
+ {
+ // Not implemented yet
+ return false;
+ }
+
+ /** increment the nonce sequence
+ *
+ */
+ public void incrementNonceSeq ()
+ {
+ m_nonceSeq++;
+ }
+
+ /** Gets length of buffer for password encryption (public)
+ * @Return pass word key length if success and 0 if failed
+ * @throw SecurityException
+ */
+ public int getPwdEBufferLen() throws SecurityException
+ {
+ int pubKLen = m_keyObj.getPubKeyLen();
+ if(pubKLen <= 0)
+ throw new SecurityException(SecClientMsgKeys.
+ PUBKEY_LENGTH_IS_ZERO, null);
+ else
+ return (pubKLen + SecdefsCommon.PWDKEY_SIZE_LESS_LOGINDATA);
+ }
+
+ /** Gets certificate's expiration date
+ * @Return an array of bytes represents the certificate's
+ * expiration day in the string format YYMMDDHHMMSS
+ */
+ public byte[] getCertExpDate()
+ {
+ return m_cert.getCertExpDate();
+ }
+
+ // Generates session key and nonce
+ private void generateSessionKey() throws SecurityException
+ {
+ //try {
+ SecureRandom random = new SecureRandom();
+ try {
+ random.setSeed(System.currentTimeMillis());
+
+ random.setSeed(Runtime.getRuntime().freeMemory());
+ random.setSeed(Runtime.getRuntime().totalMemory());
+ random.setSeed(Runtime.getRuntime().maxMemory());
+
+ String p = null;
+
+ p = System.getProperty("java.version", "unknown java version");
+ random.setSeed(p.getBytes());
+ p = System.getProperty("java.vendor", "unknown vendor");
+ random.setSeed(p.getBytes());
+ p = System.getProperty("os.name", "unknown os");
+ random.setSeed(p.getBytes());
+ p = System.getProperty("os.version", "unknown os version");
+ random.setSeed(p.getBytes());
+
+ // Add current time again
+
+ random.setSeed(System.currentTimeMillis());
+ }
+ catch(Exception e ) {
+ // Ignore
+ }
+ byte bytes[] = new byte[SecdefsCommon.SESSION_KEYLEN +
+ SecdefsCommon.NONCE_SIZE];
+ synchronized(random) {
+ random.nextBytes(bytes);
+ }
+
+ // Assign bytes to members m_pwdkey.data.session_key
+ // and m_pwdkey.data.nonce
+
+ System.arraycopy(bytes, 0, m_pwdkey.data.session_key, 0, SecdefsCommon.SESSION_KEYLEN);
+ System.arraycopy(bytes, SecdefsCommon.SESSION_KEYLEN, m_pwdkey.data.nonce, 0, SecdefsCommon.NONCE_SIZE);
+
+ m_nonceSeq = (ByteBuffer.wrap(m_pwdkey.data.nonce)).getLong(
+ SecdefsCommon.SESSION_KEYLEN -
+ SecdefsCommon.NONCE_SEQNUM);
+
+ // Set time when session key is generated
+ m_keyTime = (new Date()).getTime();
+ /*}catch (NoSuchAlgorithmException nae) {
+ throw new SecurityException(SecClientMsgKeys.SESSION_KEY_GENERATION_FAILED, null);
+ }*/
+ }
+
+ // encryption is required or not for replied message 0-yes, 1-no
+ //int m_encrypted;
+ // security option - mandatory - 1 or undocumented option - 0
+ // Time when session key is generated
+ private long m_keyTime;
+ // sequence nonce used in nonce increment
+ // Need to use 64 bit number type here
+ private long m_nonceSeq;
+ // certificate
+ private Certificate m_cert;
+ // key
+ private Key m_keyObj;
+ // password key
+ private SecdefsCommon.PwdKey m_pwdkey;
+ private javax.crypto.Cipher m_cipher;
+
+};
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecurityException.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecurityException.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecurityException.java
new file mode 100644
index 0000000..64d1a3d
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SecurityException.java
@@ -0,0 +1,47 @@
+/**********************************************************************
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+//
+ **********************************************************************/
+package org.trafodion.jdbc.t4;
+
+import java.lang.String;
+import java.lang.Integer;
+import java.sql.SQLException;
+
+public class SecurityException extends SQLException
+{
+ private static final String SQLState = "38001";
+
+ public SecurityException(String key, Object[] params)
+ {
+ // Get the text message from the file secClient.properties.
+ // Parse the message for the error message and error number.
+ this((SecResourceBundle.obtainMessageText(key, params)).substring(6),
+ Integer.parseInt((SecResourceBundle.obtainMessageText(key, params)).substring(0, 5)));
+ }
+
+ public SecurityException(String errMsg, int errNum)
+ {
+ super(errMsg, SQLState, errNum);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SetConnectionOptionMessage.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SetConnectionOptionMessage.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SetConnectionOptionMessage.java
new file mode 100644
index 0000000..8ee7c6c
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SetConnectionOptionMessage.java
@@ -0,0 +1,50 @@
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+
+package org.trafodion.jdbc.t4;
+
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.UnsupportedCharsetException;
+
+class SetConnectionOptionMessage {
+ // ----------------------------------------------------------
+ static LogicalByteArray marshal(int dialogueId, short connectionOption, int optionValueNum, String optionValueStr,
+ InterfaceConnection ic) throws CharacterCodingException, UnsupportedCharsetException {
+ int wlength = Header.sizeOf();
+ LogicalByteArray buf;
+
+ byte[] optionValueBytes = ic.encodeString(optionValueStr, InterfaceUtilities.SQLCHARSETCODE_UTF8);
+
+ wlength += TRANSPORT.size_int; // dialogueId
+ wlength += TRANSPORT.size_short; // connectionOption
+ wlength += TRANSPORT.size_int; // optionValueNum
+ wlength += TRANSPORT.size_bytes(optionValueBytes); // optionValueStr
+
+ buf = new LogicalByteArray(wlength, Header.sizeOf(), ic.getByteSwap());
+
+ buf.insertInt(dialogueId);
+ buf.insertShort(connectionOption);
+ buf.insertInt(optionValueNum);
+ buf.insertString(optionValueBytes);
+
+ return buf;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SetConnectionOptionReply.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SetConnectionOptionReply.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SetConnectionOptionReply.java
new file mode 100644
index 0000000..fa3ecc0
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SetConnectionOptionReply.java
@@ -0,0 +1,45 @@
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+
+package org.trafodion.jdbc.t4;
+
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.sql.SQLException;
+
+class SetConnectionOptionReply {
+ odbc_SQLSvc_SetConnectionOption_exc_ m_p1;
+ ERROR_DESC_LIST_def m_p2;
+
+ // -------------------------------------------------------------
+ SetConnectionOptionReply(LogicalByteArray buf, String addr, InterfaceConnection ic)
+ throws CharacterCodingException, UnsupportedCharsetException, SQLException {
+ buf.setLocation(Header.sizeOf());
+
+ m_p1 = new odbc_SQLSvc_SetConnectionOption_exc_();
+ m_p1.extractFromByteArray(buf, addr, ic);
+
+ if (m_p1.exception_nr == TRANSPORT.CEE_SUCCESS) {
+ m_p2 = new ERROR_DESC_LIST_def();
+ m_p2.extractFromByteArray(buf, ic);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SymCrypto.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SymCrypto.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SymCrypto.java
new file mode 100644
index 0000000..a0e10ad
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/SymCrypto.java
@@ -0,0 +1,87 @@
+/**********************************************************************
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+ //
+ **********************************************************************/
+
+/**
+ * class SymCrypto - Stores connections and correspondence SecPwd
+ * objects.
+ */
+
+package org.trafodion.jdbc.t4;
+
+import java.util.HashMap;
+import java.sql.Connection;
+
+public class SymCrypto
+{
+ static HashMap<Connection, SymCrypto> storage = new HashMap<Connection, SymCrypto> ();
+
+ /**
+ * Ctor -
+ * @param secpwd
+ */
+ private SymCrypto(SecPwd secpwd)
+ {
+ m_secPwd = secpwd;
+ }
+
+ /**
+ * Returns the SymCrypto object correspondence to the connection passed in
+ * @param con
+ * @return the value to which the SymCrypto object maps the connection passed in or
+ * null if the map contains no mapping for the connection.
+ * @throws SecurityException
+ */
+ public static SymCrypto getInstance(Connection con) throws SecurityException
+ {
+ if (con == null)
+ throw new SecurityException (SecClientMsgKeys.INPUT_PARAMETER_IS_NULL, new Object[]{"connection"});
+ return storage.get(con);
+ }
+
+ /**
+ * Creates and SymCrypto object from the SecPwd object and inserts the connection
+ * and the equivalent SymCRypto object into the hash table storage. If the table previously
+ * contained a mapping for the connection, the old value is replaced.
+ * @param con - the JDBC connection
+ * @param secpwd - the SecPwd object associated with the JDBC connection
+ */
+ public static void insert(Connection con, SecPwd secpwd)
+ {
+ SymCrypto symcrypto = new SymCrypto(secpwd);
+ storage.put(con, symcrypto);
+ }
+
+ /**
+ * Removed the mapping of this JDBC connection from the hash table if present
+ * @param con - JDBC connection whose entry is to be removed from the hash table storage
+ */
+ public static void remove(Connection con)
+ {
+ if (con != null)
+ storage.remove(con);
+ }
+
+ private SecPwd m_secPwd;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/T4Address.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/T4Address.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/T4Address.java
new file mode 100644
index 0000000..6cc2085
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/T4Address.java
@@ -0,0 +1,315 @@
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+
+package org.trafodion.jdbc.t4;
+
+/**********************************************************
+ * This class represents an address reference.
+ *
+ * @version 1.0
+ **********************************************************/
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.Locale;
+import java.util.Properties;
+
+final class T4Address extends Address {
+
+ private static final String t4ConnectionPrefix = "jdbc:t4jdbc:";
+ private static final String urlPrefix = t4ConnectionPrefix + "//";
+ private static final int minT4ConnectionAddrLen = t4ConnectionPrefix.length() + 4;
+ private static final int AS_type = 1; // jdbc:subprotocol:subname
+
+ /**
+ * The constructor.
+ *
+ * @param addr
+ * The addr has two forms:
+ *
+ * DriverManager getConnection addr parameter format for connecting via the
+ * Fast JDBC Type 4 driver.
+ *
+ * jdbc:subprotocol:subname
+ *
+ * Where:
+ *
+ * subprotocol = t4jdbc
+ *
+ * subname = //<{IP Address|Machine Name}[:port]>/<properties>
+ *
+ * Example: jdbc:t4jdbc://130.168.200.30:1433/database1
+ *
+ */
+
+ // ----------------------------------------------------------
+ T4Address(T4Properties t4props, Locale locale, String addr) throws SQLException {
+ super(t4props, locale, addr);
+
+ if (addr == null) {
+ SQLException se = HPT4Messages.createSQLException(m_t4props, m_locale, "address_null_error", null);
+ throw se;
+ }
+
+ //
+ // We are now expecting addr = "//<{IP Address|Machine
+ // Name}[:port]>/<properties>"
+ //
+ m_type = AS_type;
+
+ //
+ // We don't recognize this address syntax
+ //
+ if (acceptsURL(addr) == false) {
+ SQLException se = HPT4Messages.createSQLException(m_t4props, m_locale, "address_parsing_error", addr);
+ SQLException se2 = HPT4Messages.createSQLException(m_t4props, m_locale, "unknown_prefix_error", null);
+
+ se.setNextException(se2);
+ throw se;
+ }
+
+ //
+ // We are now expecting addr = "<{IP Address|Machine Name}[:port]>"
+ // Get the IP or Name
+ //
+ String IPorName = extractHostFromUrl(addr);
+ if (isIPAddress(IPorName)) {
+ m_ipAddress = IPorName;
+ } else {
+ m_machineName = IPorName;
+
+ //
+ // Get the port number if there is one.
+ //
+ }
+ m_portNumber = new Integer(extractPortFromUrl(addr));
+ m_properties = extractPropertiesFromString(addr);
+
+ m_url = recreateAddress();
+
+ validateAddress();
+ setInputOutput();
+ }
+
+ String recreateAddress() {
+ String addr = null;
+
+ addr = t4ConnectionPrefix + "//";
+
+ if (m_machineName != null) {
+ addr = addr + m_machineName;
+ } else if (m_ipAddress != null) {
+ addr = addr + m_ipAddress;
+
+ }
+ if (m_portNumber != null) {
+ addr = addr + ":" + m_portNumber;
+
+ }
+ addr = addr + "/";
+
+ return addr;
+ } // end recreateAddress
+
+ static boolean acceptsURL(String url) throws SQLException {
+ try {
+ return url.toLowerCase().startsWith(t4ConnectionPrefix);
+ } catch (Exception ex) {
+ throw new SQLException(ex.toString());
+ }
+ }
+
+ // ----------------------------------------------------------
+ String getUrl() {
+ return urlPrefix + getIPorName() + ':' + getPort().toString() + "/:";
+ } // end getProps()
+
+ // ----------------------------------------------------------
+ Properties getProps() {
+ return m_properties;
+ } // end getProps()
+
+ /**
+ * Return the host value
+ *
+ * @param url
+ * of format jdbc:t4jdbc://host:port/:[prop-name=prop-value]..
+ * @return host string
+ */
+ private String extractHostFromUrl(String url) throws SQLException {
+ if (url.length() < minT4ConnectionAddrLen) {
+ SQLException se = HPT4Messages.createSQLException(m_t4props, m_locale, "address_parsing_error", url);
+ SQLException se2 = HPT4Messages.createSQLException(m_t4props, m_locale, "min_address_length_error", null);
+
+ se.setNextException(se2);
+ throw se;
+ }
+
+ int hostStartIndex = urlPrefix.length();
+ int hostEndIndex = -1;
+ if (isIPV6(url)) {
+ hostEndIndex = url.lastIndexOf(']', hostStartIndex); // IP6
+ } else {
+ hostEndIndex = url.indexOf(':', hostStartIndex); // IP4
+
+ }
+ if (hostEndIndex < 0) {
+ SQLException se = HPT4Messages.createSQLException(m_t4props, m_locale, "address_parsing_error", url);
+ SQLException se2 = HPT4Messages.createSQLException(m_t4props, m_locale, "address_format_error", url);
+
+ se.setNextException(se2);
+ throw se;
+ }
+
+ String host = url.substring(hostStartIndex, hostEndIndex);
+ if ((host == null) || (host.length() == 0)) {
+ SQLException se = HPT4Messages.createSQLException(m_t4props, m_locale, "address_parsing_error", url);
+ SQLException se2 = HPT4Messages.createSQLException(m_t4props, m_locale, "address_format_error", null);
+ SQLException se3 = HPT4Messages.createSQLException(m_t4props, m_locale, "missing_ip_or_name_error", null);
+ se.setNextException(se2);
+ se2.setNextException(se3);
+ throw se;
+ }
+
+ return host;
+ }
+
+ /**
+ * Return the port value
+ *
+ * @param url
+ * of format jdbc:t4jdbc://host:port/:[prop-name=prop-value]..
+ * @return port string
+ */
+ private String extractPortFromUrl(String url) throws SQLException {
+ int portStartIndex = url.indexOf(':', urlPrefix.length()) + 1;
+ int portEndIndex = url.indexOf('/', portStartIndex);
+ if (portEndIndex < 0) {
+ portEndIndex = url.length();
+
+ }
+ String port = url.substring(portStartIndex, portEndIndex);
+ if (port.length() < 1) {
+ throw new SQLException("Incorrect port value in the URL.");
+ }
+ ;
+
+ int asPort;
+ try {
+ asPort = Integer.parseInt(port);
+ } catch (Exception e) {
+ throw new SQLException("Incorrect port value in the URL.");
+ }
+
+ if ((asPort < 0) || (asPort > 65535)) {
+ throw new SQLException("Port value out of range in the URL.");
+ }
+
+ return port;
+ }
+
+ /**
+ * Checks if the url is of IP6 protocol
+ */
+ private boolean isIPV6(String url) throws SQLException {
+ if (url == null) {
+ SQLException se = HPT4Messages.createSQLException(m_t4props, m_locale, "address_parsing_error", url);
+ SQLException se2 = HPT4Messages.createSQLException(m_t4props, m_locale, "address_format_2_error", null);
+ se.setNextException(se2);
+ throw se;
+
+ }
+ int hostStartIndex = urlPrefix.length();
+ return (url.charAt(hostStartIndex) == '[');
+ }
+
+ /**
+ * Extracts the property name, value pair from a url String, seperated by ;
+ *
+ * @param url
+ * of format jdbc:t4jdbc://host:port/:[prop-name=prop-value]..
+ * @return Propeties object
+ * @throws IOException
+ */
+ private Properties extractPropertiesFromString(String url) throws SQLException {
+ int urLength = url.length();
+ int hostStartIndex = urlPrefix.length();
+ int propStartIndex = url.indexOf('/', hostStartIndex);
+ if (propStartIndex < 0) {
+ return null;
+ }
+
+ if (propStartIndex == urLength) {
+ return null;
+ }
+
+ if (url.charAt(propStartIndex) == '/') {
+ propStartIndex++;
+
+ }
+ if (propStartIndex == urLength) {
+ return null;
+ }
+
+ if (url.charAt(propStartIndex) == ':') {
+ propStartIndex++;
+
+ }
+ if (propStartIndex == urLength) {
+ return null;
+ }
+
+ String propStr = url.substring(propStartIndex);
+ if ((propStr == null) || (propStr.length() == 0)) {
+ return null;
+ }
+
+ Properties props = new Properties();
+ propStr = propStr.replace(';', '\n');
+ ByteArrayInputStream byteArrIPStream = new ByteArrayInputStream(propStr.getBytes());
+
+ try {
+ props.load(byteArrIPStream);
+ } catch (IOException ioex) {
+ throw new SQLException(ioex.getMessage());
+ }
+
+ return props;
+ }
+
+ /**
+ * Checks the string is host or port.
+ *
+ * @param IPorName
+ * @return true if the address is a IP address
+ */
+ private boolean isIPAddress(String IPorName) {
+ // Minimum length = 7; 1.1.1.1
+ if (IPorName.length() < 7)
+ return false;
+ //
+ // If first letter is a digit or ":" (i.e. IPv6), I'll assume it is an
+ // IP address
+ //
+ return (Character.isDigit(IPorName.charAt(0)) || (IPorName.charAt(1) == ':'));
+ }
+} // end class Address
http://git-wip-us.apache.org/repos/asf/incubator-trafodion/blob/72e17019/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/T4Connection.java
----------------------------------------------------------------------
diff --git a/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/T4Connection.java b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/T4Connection.java
new file mode 100644
index 0000000..d1ce34f
--- /dev/null
+++ b/core/conn/jdbcT4/src/main/java/org/trafodion/jdbc/t4/T4Connection.java
@@ -0,0 +1,505 @@
+// @@@ START COPYRIGHT @@@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// @@@ END COPYRIGHT @@@
+
+package org.trafodion.jdbc.t4;
+
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.sql.SQLException;
+import java.util.Locale;
+import java.util.logging.Level;
+
+class T4Connection {
+ protected Locale m_locale;
+ protected int m_dialogueId;
+ protected NCSAddress m_ncsAddress;
+ private InputOutput m_io;
+ private USER_DESC_def m_userDesc;
+ private CONNECTION_CONTEXT_def m_inContext;
+ private String m_sessionName;
+ InterfaceConnection m_ic;
+
+ static final int INCONTEXT_OPT1_SESSIONNAME = 0x80000000; // (2^31)
+ static final int INCONTEXT_OPT1_FETCHAHEAD = 0x40000000; // (2^30)
+ static final int INCONTEXT_OPT1_CERTIFICATE_TIMESTAMP = 0x20000000; //(2^29)
+ static final int INCONTEXT_OPT1_CLIENT_USERNAME = 0x10000000; //(2^28)
+
+ T4Connection(InterfaceConnection ic) throws SQLException {
+ if (ic == null) {
+ throwInternalException();
+
+ }
+ m_ic = ic;
+ m_locale = ic.getLocale();
+ m_dialogueId = ic.getDialogueId();
+ m_ncsAddress = ic.getNCSAddress();
+ m_userDesc = ic.getUserDescription();
+ m_inContext = ic.getInContext();
+ m_sessionName = ic.getSessionName();
+
+ if (m_dialogueId < 1 || m_ncsAddress == null || m_userDesc == null || m_inContext == null) {
+ throwInternalException();
+
+ }
+ m_io = m_ncsAddress.getInputOutput();
+ if (m_io == null) {
+ throwInternalException();
+ }
+ m_io.setDialogueId(m_dialogueId);
+ m_io.setConnectionIdleTimeout(ic.getConnectionTimeout());
+ // trace_connection - AM
+ m_io.setT4Connection(this);
+ m_io.openIO();
+ getInputOutput().setTimeout(ic.getLoginTimeout());
+ checkConnectionIdleTimeout();
+ resetConnectionIdleTimeout();
+ }
+
+ public void finalizer() {
+ closeTimers();
+ }
+
+ protected int getDialogueId() {
+ return m_dialogueId;
+ }
+
+ protected Locale getLocale() {
+ return m_locale;
+ }
+
+ protected String getSessionName() {
+ return this.m_sessionName;
+ }
+
+ protected NCSAddress getNCSAddress() {
+ return m_ncsAddress;
+ }
+
+ void closeTimers() {
+ if (m_io != null) {
+ m_io.closeTimers();
+ }
+ }
+
+ protected void reuse() {
+ resetConnectionIdleTimeout();
+ }
+
+ private void setConnectionIdleTimeout() {
+ m_io.startConnectionIdleTimeout();
+ }
+
+ private void resetConnectionIdleTimeout() {
+ m_io.resetConnectionIdleTimeout();
+ }
+
+ private void checkConnectionIdleTimeout() throws SQLException {
+ if (m_io.checkConnectionIdleTimeout()) {
+ try {
+ m_ic.close();
+ } catch (SQLException sqex) {
+ // ignores
+ }
+ throw HPT4Messages.createSQLException(m_ic.t4props_, m_locale, "ids_s1_t00", null);
+ }
+ }
+
+ protected boolean connectionIdleTimeoutOccured() {
+ return m_io.checkConnectionIdleTimeout();
+ }
+
+ protected InputOutput getInputOutput() throws SQLException {
+ checkConnectionIdleTimeout();
+ resetConnectionIdleTimeout();
+ return m_io;
+ }
+
+ protected void throwInternalException() throws SQLException {
+ T4Properties tempP = null;
+
+ if (m_ic != null) {
+ tempP = m_ic.t4props_;
+
+ }
+ SQLException se = HPT4Messages.createSQLException(tempP, m_locale, "internal_error", null);
+ SQLException se2 = HPT4Messages.createSQLException(tempP, m_locale, "contact_hp_error", null);
+
+ se.setNextException(se2);
+ throw se;
+ }
+
+ // --------------------------------------------------------------------------------
+ protected LogicalByteArray getReadBuffer(short odbcAPI, LogicalByteArray wbuffer) throws SQLException {
+ // trace_connection - AM
+ if (m_ic.t4props_.t4Logger_.isLoggable(Level.FINEST) == true) {
+ Object p[] = T4LoggingUtilities.makeParams(m_ic.t4props_);
+ String temp = "LogicalByteArray";
+ m_ic.t4props_.t4Logger_.logp(Level.FINEST, "T4Connection", "getReadBuffer", temp, p);
+ }
+ LogicalByteArray rbuffer = m_io.doIO(odbcAPI, wbuffer);
+
+ return rbuffer;
+ }
+
+ // --------------------------------------------------------------------------------
+ /**
+ * This class corresponds to the ODBC client driver function
+ * odbc_SQLSvc_InitializeDialogue_pst_ as taken from odbccs_drvr.cpp.
+ * @version 1.0
+ *
+ * This method will make a connection to an ODBC server. The ODBC server's
+ * locaiton This method will make a connection to an ODBC server. The ODBC
+ * server's locaiton (i.e. ip address and port number), were provided by an
+ * earlier call to the ODBC association server.
+ *
+ * @param inContext
+ * a CONNETION_CONTEXT_def object containing connection
+ * information
+ * @param userDesc
+ * a USER_DESC_def object containing user information
+ * @param inContext
+ * a CONNECTION_CONTEXT_def object containing information for
+ * this connection
+ * @param dialogueId
+ * a unique id identifing this connection as supplied by an
+ * earlier call to the association server
+ *
+ * @retrun a InitializeDialogueReply class representing the reply from the
+ * ODBC server is returned
+ *
+ * @exception A
+ * SQLException is thrown
+ */
+
+ InitializeDialogueReply InitializeDialogue(boolean setTimestamp, boolean downloadCert) throws SQLException {
+ try {
+ int optionFlags1 = INCONTEXT_OPT1_CLIENT_USERNAME;
+ int optionFlags2 = 0;
+
+ if(setTimestamp) {
+ optionFlags1 |= INCONTEXT_OPT1_CERTIFICATE_TIMESTAMP;
+ }
+
+ if (m_sessionName != null && m_sessionName.length() > 0) {
+ optionFlags1 |= INCONTEXT_OPT1_SESSIONNAME;
+ }
+
+ if (this.m_ic.t4props_.getFetchAhead()) {
+ optionFlags1 |= INCONTEXT_OPT1_FETCHAHEAD;
+ }
+
+ // trace_connection - AM
+ if (m_ic.t4props_.t4Logger_.isLoggable(Level.FINEST) == true) {
+ Object p[] = T4LoggingUtilities.makeParams(m_ic.t4props_);
+ String temp = "m_dialogueId=" + m_dialogueId;
+ m_ic.t4props_.t4Logger_.logp(Level.FINEST, "T4Connection", "InitializeDialogue", temp, p);
+ }
+ LogicalByteArray wbuffer = InitializeDialogueMessage.marshal(m_userDesc, m_inContext, m_dialogueId,
+ optionFlags1, optionFlags2, m_sessionName, m_ic);
+
+ getInputOutput().setTimeout(m_ic.t4props_.getLoginTimeout());
+
+ LogicalByteArray rbuffer = getReadBuffer(TRANSPORT.SRVR_API_SQLCONNECT, wbuffer);
+
+ //
+ // Process output parameters
+ //
+ InitializeDialogueReply idr1 = new InitializeDialogueReply(rbuffer, m_ncsAddress.getIPorName(), m_ic, downloadCert);
+
+ return idr1;
+ } catch (SQLException se) {
+ throw se;
+ } catch (CharacterCodingException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale,
+ "translation_of_parameter_failed", "InitializeDialogueMessage", e.getMessage());
+ se.initCause(e);
+ throw se;
+ } catch (UnsupportedCharsetException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale, "unsupported_encoding", e
+ .getCharsetName());
+ se.initCause(e);
+ throw se;
+ }
+
+ catch (Exception e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale,
+ "initialize_dialogue_message_error", e.getMessage());
+
+ se.initCause(e);
+ throw se;
+ } // end catch
+ } // end InitializeDialogue
+
+ /**
+ * This method will end a connection to an ODBC server. The ODBC server's
+ * locaiton (i.e. ip address and port number), were provided by an earlier
+ * call to the ODBC association server.
+ *
+ * @retrun a TerminateDialogueReply class representing the reply from the
+ * ODBC server is returned
+ *
+ * @exception A
+ * SQLException is thrown
+ */
+ TerminateDialogueReply TerminateDialogue() throws SQLException {
+ try {
+ // trace_connection - AM
+ if (m_ic.t4props_.t4Logger_.isLoggable(Level.FINEST) == true) {
+ Object p[] = T4LoggingUtilities.makeParams(m_ic.t4props_);
+ String temp = "m_dialogueId=" + m_dialogueId;
+ m_ic.t4props_.t4Logger_.logp(Level.FINEST, "T4Connection", "TerminateDialogue", temp, p);
+ }
+ LogicalByteArray wbuffer = TerminateDialogueMessage.marshal(m_dialogueId, this.m_ic);
+
+ //
+ // used m_ic instead of getInputOutput, because getInputOutput
+ // implicitly calls close at timeout, which will call
+ // TerminateDialogue
+ // which causes recursion.
+ //
+ // m_io.setTimeout(m_ic.t4props_.getCloseConnectionTimeout());
+ m_io.setTimeout(m_ic.t4props_.getLoginTimeout());
+
+ LogicalByteArray rbuffer = getReadBuffer(TRANSPORT.SRVR_API_SQLDISCONNECT, wbuffer);
+
+ //
+ // Process output parameters
+ //
+ TerminateDialogueReply tdr1 = new TerminateDialogueReply(rbuffer, m_ncsAddress.getIPorName(), m_ic);
+
+ //
+ // Send a close message and close the port if we don't have an
+ // error.
+ // If there is an error, it's up to the calling routine to decide
+ // what to do.
+ //
+ if (tdr1.m_p1.exception_nr == TRANSPORT.CEE_SUCCESS) {
+ m_io.CloseIO(wbuffer); // note, I'm re-using wbuffer
+
+ }
+
+ closeTimers();
+
+ return tdr1;
+ } // end try
+ catch (SQLException se) {
+ throw se;
+ } catch (CharacterCodingException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale,
+ "translation_of_parameter_failed", "TerminateDialogMessage", e.getMessage());
+ se.initCause(e);
+ throw se;
+ } catch (UnsupportedCharsetException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale, "unsupported_encoding", e
+ .getCharsetName());
+ se.initCause(e);
+ throw se;
+ } catch (Exception e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale,
+ "terminate_dialogue_message_error", e.getMessage());
+
+ se.initCause(e);
+ throw se;
+ } // end catch
+ } // end TerminateDialogue
+
+ /**
+ * This method will send a set connection option command to the server.
+ *
+ * @param connetionOption
+ * The connection option to be set
+ * @param optionValueNum
+ * The number value of the option
+ * @param optionValueStr
+ * The string value of the option
+ *
+ * @retrun a SetConnectionOptionReply class representing the reply from the
+ * ODBC server is returned
+ *
+ * @exception A
+ * SQLException is thrown
+ */
+ SetConnectionOptionReply SetConnectionOption(short connectionOption, int optionValueNum, String optionValueStr)
+ throws SQLException {
+
+ if (optionValueStr == null) {
+ throwInternalException();
+
+ }
+ try {
+
+ LogicalByteArray wbuffer = SetConnectionOptionMessage.marshal(m_dialogueId, connectionOption,
+ optionValueNum, optionValueStr, this.m_ic);
+
+ getInputOutput().setTimeout(m_ic.t4props_.getNetworkTimeout());
+
+ LogicalByteArray rbuffer = getReadBuffer(TRANSPORT.SRVR_API_SQLSETCONNECTATTR, wbuffer);
+
+ SetConnectionOptionReply scor = new SetConnectionOptionReply(rbuffer, m_ncsAddress.getIPorName(), m_ic);
+
+ return scor;
+ } // end try
+ catch (SQLException se) {
+ throw se;
+ } catch (CharacterCodingException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale,
+ "translation_of_parameter_failed", "SetConnectionOptionReply", e.getMessage());
+ se.initCause(e);
+ throw se;
+ } catch (UnsupportedCharsetException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale, "unsupported_encoding", e
+ .getCharsetName());
+ se.initCause(e);
+ throw se;
+ } catch (Exception e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale,
+ "set_connection_option_message_error", e.getMessage());
+
+ se.initCause(e);
+ throw se;
+ } // end catch
+ } // end SetConnectionOption
+
+ /**
+ * This method will send an End Transaction command, which does not return
+ * any rowsets, to the ODBC server.
+ *
+ * @param transactionOpt
+ * A transaction opt
+ *
+ * @retrun A EndTransactionReply class representing the reply from the ODBC
+ * server is returned
+ *
+ * @exception A
+ * SQLException is thrown
+ */
+ EndTransactionReply EndTransaction(short transactionOpt) throws SQLException {
+
+ try {
+ LogicalByteArray wbuffer = EndTransactionMessage.marshal(m_dialogueId, transactionOpt, this.m_ic);
+
+ getInputOutput().setTimeout(m_ic.t4props_.getNetworkTimeout());
+
+ LogicalByteArray rbuffer = getReadBuffer(TRANSPORT.SRVR_API_SQLENDTRAN, wbuffer);
+
+ EndTransactionReply cr = new EndTransactionReply(rbuffer, m_ncsAddress.getIPorName(), m_ic);
+ return cr;
+ } // end try
+ catch (SQLException se) {
+ throw se;
+ } catch (CharacterCodingException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale,
+ "translation_of_parameter_failed", "EndTransactionMessage", e.getMessage());
+ se.initCause(e);
+ throw se;
+ } catch (UnsupportedCharsetException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale, "unsupported_encoding", e
+ .getCharsetName());
+ se.initCause(e);
+ throw se;
+ } catch (Exception e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale, "end_transaction_message_error",
+ e.getMessage());
+
+ se.initCause(e);
+ throw se;
+ } // end catch
+
+ } // end EndTransaction
+
+ /**
+ * This method will send an get SQL catalogs command to the ODBC server.
+ *
+ * @param stmtLabel
+ * a statement label for use by the ODBC server
+ * @param APIType
+ * @param catalogNm
+ * @param schemaNm
+ * @param tableNm
+ * @param tableTypeList
+ * @param columnNm
+ * @param columnType
+ * @param rowIdScope
+ * @param nullable
+ * @param uniqueness
+ * @param accuracy
+ * @param sqlType
+ * @param metadataId
+ * @param fkcatalogNm
+ * @param fkschemaNm
+ * @param fktableNm
+ *
+ * @retrun a GetSQLCatalogsReply class representing the reply from the ODBC
+ * server is returned
+ *
+ * @exception A
+ * SQLException is thrown
+ */
+ GetSQLCatalogsReply GetSQLCatalogs(String stmtLabel, short APIType, String catalogNm, String schemaNm,
+ String tableNm, String tableTypeList, String columnNm, int columnType, int rowIdScope, int nullable,
+ int uniqueness, int accuracy, short sqlType, int metadataId, String fkcatalogNm, String fkschemaNm,
+ String fktableNm) throws SQLException {
+
+ if (stmtLabel == null) {
+ throwInternalException();
+
+ }
+ try {
+ LogicalByteArray wbuffer;
+
+ wbuffer = GetSQLCatalogsMessage.marshal(m_dialogueId, stmtLabel, APIType, catalogNm, schemaNm, tableNm,
+ tableTypeList, columnNm, columnType, rowIdScope, nullable, uniqueness, accuracy, sqlType,
+ metadataId, fkcatalogNm, fkschemaNm, fktableNm, m_ic);
+
+ getInputOutput().setTimeout(m_ic.t4props_.getNetworkTimeout());
+
+ LogicalByteArray rbuffer = getReadBuffer(TRANSPORT.SRVR_API_GETCATALOGS, wbuffer);
+
+ //
+ // Process output parameters
+ //
+ GetSQLCatalogsReply gscr = new GetSQLCatalogsReply(rbuffer, m_ncsAddress.getIPorName(), m_ic);
+
+ return gscr;
+ } // end try
+ catch (SQLException se) {
+ throw se;
+ } catch (CharacterCodingException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale,
+ "translation_of_parameter_failed", "GetSQLCatalogsMessage", e.getMessage());
+ se.initCause(e);
+ throw se;
+ } catch (UnsupportedCharsetException e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale, "unsupported_encoding", e
+ .getCharsetName());
+ se.initCause(e);
+ throw se;
+ } catch (Exception e) {
+ SQLException se = HPT4Messages.createSQLException(m_ic.t4props_, m_locale,
+ "get_sql_catalogs_message_error", e.getMessage());
+
+ se.initCause(e);
+ throw se;
+ } // end catch
+
+ } // end GetSQLCatalogs
+
+}