-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hello All,
The attached patch is to address an issue with the Network Server
regarding the handling of the EXCSAT codepoint. Army told me that he
hit this with the C client tests that he is running.
There are three kinds of EXCSAT's we might get
1) Initial Exchange attributes. For this we need to initialize the
apprequester. Session state is set to ATTEXC (attributes exchanged) then
the AR must follow up with ACCSEC and SECCHK to get the connection.
2) Send of EXCSAT as ping or manager level adjustment. For this we just
ignore the EXCSAT objects that are already set. JCC doesn't use this,
but it is in DRDA.
3) Send of EXCSAT for connection reset. (see parseEXCSAT2()) This is
treated just like ping and will be followed up
by an ACCSEC request if in fact it is a connection reset.
If we have already exchanged attributes once just
process any new manager levels and return (case 2 and 3 above)
Before the XA checkin, 1 and 2 worked. After the XA checkin 1 and 3
worked and with this patch 1, 2, and 3 all work.
I had to rearrange the code a bit to do this because in DRDAConnThread,
processCommands() the EXCSAT case just called parseDRDAConnection which
expected the ACCSEC and SECCHK codepoints in the correct order.
As a solution I
1) Moved the handling of the ACCSEC and SECCHK codepoints from
parseDRDAConnection up to processCommands().
2) Put the security state in the Session object. The session has
4 states.
two existed before:
INIT - initial state
ATTEXC - attributes exchanged
(After first EXSAT - ACCSEC required)
now there are two new ones:
SECACC - security accessed (After successful ACCSEC - need SECCHK)
CHKSEC - checked security. After successful SECCHK and connection.
no more required security codepoits.
The session.getRequiredSecurityCodepoint() method is used by
process_commands to determine if the next codepoint must be ACCSEC or
SECCHK.
Also the patch includes the fix Dan suggested for jdk 131 for
BrokeredPreparedStatent.getStatement(). But how to call
Connection.prepareStatement is still an issue.
Please let me know if you have any questions or issues.
Ran derbynetmats. Changed some protocol tests that are still on the to
be contributed list.
I will check this in noon tomorrow if there are no objections if Army
gives the all clear with his tests.
Thanks
Kathey
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFB7z3DG0h36bFmkocRAqcuAKCfyQhbXua3VMiqm3RIIAbFXyQyHQCfZp6M
YoDq/cAhR4sb9TcU9kYpU3g=
=3QZ5
-----END PGP SIGNATURE-----
Index: java/engine/org/apache/derby/iapi/jdbc/BrokeredCallableStatement.java
===================================================================
--- java/engine/org/apache/derby/iapi/jdbc/BrokeredCallableStatement.java
(revision 125687)
+++ java/engine/org/apache/derby/iapi/jdbc/BrokeredCallableStatement.java
(working copy)
@@ -217,7 +217,7 @@
protected final CallableStatement getCallableStatement() throws
SQLException {
return control.getRealCallableStatement();
}
- protected final PreparedStatement getPreparedStatement() throws
SQLException {
+ public final PreparedStatement getPreparedStatement() throws
SQLException {
return getCallableStatement();
}
/**
Index: java/engine/org/apache/derby/iapi/jdbc/BrokeredPreparedStatement.java
===================================================================
--- java/engine/org/apache/derby/iapi/jdbc/BrokeredPreparedStatement.java
(revision 125687)
+++ java/engine/org/apache/derby/iapi/jdbc/BrokeredPreparedStatement.java
(working copy)
@@ -491,14 +491,14 @@
** Control methods.
*/
- protected PreparedStatement getPreparedStatement() throws SQLException {
+ public PreparedStatement getPreparedStatement() throws SQLException {
return control.getRealPreparedStatement();
}
/**
Override the BrokeredStatement's getStatement() to always
return a PreparedStatement.
*/
- protected final Statement getStatement() throws SQLException {
+ public final Statement getStatement() throws SQLException {
return getPreparedStatement();
}
Index: java/engine/org/apache/derby/iapi/jdbc/BrokeredStatement.java
===================================================================
--- java/engine/org/apache/derby/iapi/jdbc/BrokeredStatement.java
(revision 125687)
+++ java/engine/org/apache/derby/iapi/jdbc/BrokeredStatement.java
(working copy)
@@ -510,7 +510,7 @@
newStatement.setQueryTimeout(oldStatement.getQueryTimeout());
}
- protected Statement getStatement() throws SQLException {
+ public Statement getStatement() throws SQLException {
return control.getRealStatement();
}
protected final ResultSet wrapResultSet(ResultSet rs) {
Index: java/drda/org/apache/derby/impl/drda/DRDAStatement.java
===================================================================
--- java/drda/org/apache/derby/impl/drda/DRDAStatement.java (revision
125687)
+++ java/drda/org/apache/derby/impl/drda/DRDAStatement.java (working copy)
@@ -39,6 +39,7 @@
import org.apache.derby.impl.jdbc.Util;
import org.apache.derby.impl.jdbc.EmbedConnection;
import org.apache.derby.iapi.jdbc.BrokeredConnection;
+import org.apache.derby.iapi.jdbc.BrokeredPreparedStatement;
import org.apache.derby.impl.jdbc.EmbedResultSet;
import org.apache.derby.impl.jdbc.EmbedParameterSetMetaData;
import org.apache.derby.iapi.services.sanity.SanityManager;
@@ -276,7 +277,7 @@
try {
Method sh =
rsstmt.getClass().getMethod("getResultSetHoldability",
getResultSetHoldabilityParam);
- holdValue = ((Integer) sh.invoke(ps,null)).intValue();
+ holdValue = ((Integer)
sh.invoke(rsstmt,null)).intValue();
}
catch (Exception e) {
handleReflectionException(e);
@@ -518,9 +519,13 @@
*
* @return prepared statement
*/
- protected PreparedStatement getPreparedStatement()
+ protected PreparedStatement getPreparedStatement() throws SQLException
{
- return ps;
+ if (ps instanceof BrokeredPreparedStatement)
+ return (PreparedStatement)(
+ ((BrokeredPreparedStatement)
ps).getStatement());
+ else
+ return ps;
}
Index: java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
===================================================================
--- java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (revision
125687)
+++ java/drda/org/apache/derby/impl/drda/DRDAConnThread.java (working copy)
@@ -560,12 +560,10 @@
else
{
// exchange attributes with application requester
- if (exchangeServerAttributes())
- session.state = Session.ATTEXC;
- else
- closeSession();
+ exchangeServerAttributes();
}
}
+
/**
* Process DRDA commands we can receive once server attributes have been
* exchanged.
@@ -577,11 +575,16 @@
DRDAStatement stmt = null;
int updateCount = 0;
boolean PRPSQLSTTfailed = false;
+ boolean checkSecurityCodepoint =
session.requiresSecurityCodepoint();
do
{
correlationID = reader.readDssHeader();
int codePoint = reader.readLengthAndCodePoint();
int writerMark = writer.markDSSClearPoint();
+
+ if (checkSecurityCodepoint)
+
verifyInOrderACCSEC_SECCHK(codePoint,session.getRequiredSecurityCodepoint());
+
switch(codePoint)
{
case CodePoint.CNTQRY:
@@ -801,8 +804,20 @@
}
break;
case CodePoint.EXCSAT:
- parseDRDAConnection();
+ parseEXCSAT();
+ writeEXCSATRD();
+ finalizeChain();
break;
+ case CodePoint.ACCSEC:
+ int securityCheckCode = parseACCSEC();
+ writeACCSECRD(securityCheckCode);
+ checkSecurityCodepoint = true;
+ break;
+ case CodePoint.SECCHK:
+ if(parseDRDAConnection())
+ // security all checked and
connection ok
+ checkSecurityCodepoint = false;
+ break;
/* since we don't support sqlj, we won't get
bind commands from jcc, we
* might get it from ccc; just skip them.
*/
@@ -916,11 +931,10 @@
/**
* Exchange server attributes with application requester
*
- * @return true if the session was started successfully; false otherwise
- * @exception DRDAProtocolException, SQLException
+ * @exception DRDAProtocolException
*/
- private boolean exchangeServerAttributes()
- throws DRDAProtocolException, SQLException
+ private void exchangeServerAttributes()
+ throws DRDAProtocolException
{
int codePoint;
correlationID = reader.readDssHeader();
@@ -944,10 +958,10 @@
CodePoint.PRCCNVCD_EXCSAT_FIRST_AFTER_CONN);
}
- // set up a new Application Requester to store information
about the
- // application requester for this session
-
- return parseDRDAConnection();
+ parseEXCSAT();
+ writeEXCSATRD();
+ finalizeChain();
+ session.setState(session.ATTEXC);
}
@@ -956,49 +970,8 @@
int codePoint;
boolean sessionOK = true;
- appRequester = new AppRequester();
- parseEXCSAT();
- writeEXCSATRD();
- finalizeChain();
- //we may have to do the access security more than once if we
don't
- //provide the requested security mechanism or we run into errors
- //if we don't know the requested security mechanism
- //we'll send our known security mechanisms and the requester
will pick
- //if he picks one that requires a security token then another
ACCSEC
- //will flow
- int securityCheckCode = 0;
- boolean notdone = true;
- while (notdone)
- {
- correlationID = reader.readDssHeader();
- codePoint = reader.readLengthAndCodePoint();
- verifyInOrderACCSEC_SECCHK(codePoint,CodePoint.ACCSEC);
- securityCheckCode = parseACCSEC();
- // need security token
- if (securityCheckCode == 0 &&
- database.securityMechanism ==
CodePoint.SECMEC_EUSRIDPWD &&
- database.publicKeyIn == null)
- securityCheckCode =
CodePoint.SECCHKCD_SECTKNMISSING;
-
- // shouldn't have security token
- if (securityCheckCode == 0 &&
- database.securityMechanism ==
CodePoint.SECMEC_USRIDPWD &&
- database.publicKeyIn != null)
- securityCheckCode =
CodePoint.SECCHKCD_SECTKNMISSING;
- if (SanityManager.DEBUG)
- trace("** ACCSECRD securityCheckCode is:
"+securityCheckCode);
- writeACCSECRD(securityCheckCode);
- // everything is O.K., we're done
- if (securityCheckCode == 0)
- {
- notdone = false;
- }
- }
- correlationID = reader.readDssHeader();
- codePoint = reader.readLengthAndCodePoint();
- verifyInOrderACCSEC_SECCHK(codePoint,CodePoint.SECCHK);
- securityCheckCode = parseSECCHK();
+ int securityCheckCode = parseSECCHK();
if (SanityManager.DEBUG)
trace("*** SECCHKRM securityCheckCode is:
"+securityCheckCode);
writeSECCHKRM(securityCheckCode);
@@ -1231,7 +1204,32 @@
int codePoint;
String strVal;
+ // There are three kinds of EXCSAT's we might get.
+ // 1) Initial Exchange attributes.
+ // For this we need to initialize the apprequester.
+ // Session state is set to ATTEXC and then the AR must
+ // follow up with ACCSEC and SECCHK to get the connection.
+ // 2) Send of EXCSAT as ping or mangager level adjustment.
+ // (see parseEXCSAT2())
+ // For this we just ignore the EXCSAT objects that
+ // are already set.
+ // 3) Send of EXCSAT for connection reset. (see parseEXCSAT2())
+ // This is treated just like ping and will be followed up
+ // by an ACCSEC request if in fact it is a connection reset.
+ // If we have already exchanged attributes once just
+ // process any new manager levels and return (case 2 and 3
above)
+ if (appRequester != null)
+ {
+ parseEXCSAT2();
+ return;
+ }
+
+ // set up a new Application Requester to store information
about the
+ // application requester for this session
+
+ appRequester = new AppRequester();
+
reader.markCollection();
codePoint = reader.getCodePoint();
@@ -1611,9 +1609,32 @@
database.securityMechanism = securityMechanism;
database.publicKeyIn = publicKeyIn;
+ // need security token
+ if (securityCheckCode == 0 &&
+ database.securityMechanism ==
CodePoint.SECMEC_EUSRIDPWD &&
+ database.publicKeyIn == null)
+ securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING;
+
+ // shouldn't have security token
+ if (securityCheckCode == 0 &&
+ database.securityMechanism == CodePoint.SECMEC_USRIDPWD
&&
+ database.publicKeyIn != null)
+ securityCheckCode = CodePoint.SECCHKCD_SECTKNMISSING;
+ if (SanityManager.DEBUG)
+ trace("** ACCSECRD securityCheckCode is:
"+securityCheckCode);
+
+ // If the security check was successful set the session state to
+ // security accesseed. Otherwise go back to attributes
exchanged so we
+ // require another ACCSEC
+ if (securityCheckCode == 0)
+ session.setState(session.SECACC);
+ else
+ session.setState(session.ATTEXC);
+
return securityCheckCode;
}
+
/**
* Parse OPNQRY
* Instance Variables
@@ -2612,6 +2633,11 @@
{
securityCheckCode = verifyUserIdPassword();
}
+
+ // Security all checked
+ if (securityCheckCode == 0)
+ session.setState(session.CHKSEC);
+
return securityCheckCode;
}
Index: java/drda/org/apache/derby/impl/drda/Session.java
===================================================================
--- java/drda/org/apache/derby/impl/drda/Session.java (revision 125687)
+++ java/drda/org/apache/derby/impl/drda/Session.java (working copy)
@@ -36,10 +36,12 @@
class Session
{
- // session states
+ // session states
protected static final int INIT = 1; // before exchange of server
attributes
- protected static final int ATTEXC = 2; // after exchange of server
attributes
- protected static final int CLOSED = 3; // session has ended
+ protected static final int ATTEXC = 2; // after first exchange of
server attributes
+ protected static final int SECACC = 3; // after ACCSEC (Security
Manager Accessed)
+ protected static final int CHKSEC = 4; // after SECCHK (Checked
Security)
+ protected static final int CLOSED = 5; // session has ended
// session types
protected static final int DRDA_SESSION = 1;
@@ -196,8 +198,51 @@
return (Database)dbtable.get(dbName);
}
+ /**
+ * Get requried security checkpoint.
+ * Used to verify EXCSAT/ACCSEC/SECCHK order.
+ *
+ * @return next required Security checkpoint or -1 if
+ * neither ACCSEC or SECCHK are required at this time.
+ *
+ */
+ protected int getRequiredSecurityCodepoint()
+ {
+ switch (state)
+ {
+ case ATTEXC:
+ // On initial exchange of attributes we require
ACCSEC
+ // to access security manager
+ return CodePoint.ACCSEC;
+ case SECACC:
+ // After security manager has been accessed
successfully we
+ // require SECCHK to check security
+ return CodePoint.SECCHK;
+ default:
+ return -1;
+ }
+ }
/**
+ * Check if a security codepoint is required
+ *
+ * @return true if ACCSEC or SECCHK are required at this time.
+ */
+ protected boolean requiresSecurityCodepoint()
+ {
+ return (getRequiredSecurityCodepoint() != -1);
+ }
+
+ /**
+ * Set Session state
+ *
+ */
+ protected void setState(int s)
+ {
+ state = s;
+ }
+
+ /**
* Get session into initial state
*
* @param traceDirectory - directory for trace files