private PGStream enableSSL(PGStream pgStream, boolean requireSSL, Properties info, Logger logger) throws IOException, SQLException { if (logger.logDebug()) logger.debug(" FE=> SSLRequest"); // Send SSL request packet pgStream.SendInteger4(8); pgStream.SendInteger2(1234); pgStream.SendInteger2(5679); pgStream.flush(); // Now get the response from the backend, one of N, E, S. int beresp = pgStream.ReceiveChar(); switch (beresp) { case 'E': if (logger.logDebug()) logger.debug(" <=BE SSLError"); // Server doesn't even know about the SSL handshake protocol if (requireSSL) throw new PSQLException( GT.tr("The server does not support SSL."), PSQLState.CONNECTION_FAILURE); // We have to reconnect to continue. pgStream.close(); return new PGStream(pgStream.getHost(), pgStream.getPort()); case 'N': if (logger.logDebug()) logger.debug(" <=BE SSLRefused"); // Server does not support ssl if (requireSSL) throw new PSQLException( GT.tr("The server does not support SSL."), PSQLState.CONNECTION_FAILURE); return pgStream; case 'S': if (logger.logDebug()) logger.debug(" <=BE SSLOk"); // Server supports ssl Driver.makeSSL(pgStream, info, logger); return pgStream; default: throw new PSQLException( GT.tr("An error occured while setting up the SSL connection."), PSQLState.CONNECTION_FAILURE); } }
private void sendStartupPacket(PGStream pgStream, String[][] params, Logger logger) throws IOException { if (logger.logDebug()) { String details = ""; for (int i = 0; i < params.length; ++i) { if (i != 0) details += ", "; details += params[i][0] + "=" + params[i][1]; } logger.debug(" FE=> StartupPacket(" + details + ")"); } /* * Precalculate message length and encode params. */ int length = 4 + 4; byte[][] encodedParams = new byte[params.length * 2][]; for (int i = 0; i < params.length; ++i) { encodedParams[i * 2] = params[i][0].getBytes("US-ASCII"); encodedParams[i * 2 + 1] = params[i][1].getBytes("US-ASCII"); length += encodedParams[i * 2].length + 1 + encodedParams[i * 2 + 1].length + 1; } length += 1; // Terminating \0 /* * Send the startup message. */ pgStream.SendInteger4(length); pgStream.SendInteger2(3); // protocol major pgStream.SendInteger2(0); // protocol minor for (int i = 0; i < encodedParams.length; ++i) { pgStream.Send(encodedParams[i]); pgStream.SendChar(0); } pgStream.SendChar(0); pgStream.flush(); }
private void doAuthentication(PGStream pgStream, String user, String password, Logger logger) throws IOException, SQLException { // Now get the response from the backend, either an error message // or an authentication request while (true) { int beresp = pgStream.ReceiveChar(); switch (beresp) { case 'E': // An error occured, so pass the error message to the // user. // // The most common one to be thrown here is: // "User authentication failed" // int l_elen = pgStream.ReceiveInteger4(); if (l_elen > 30000) { // if the error length is > than 30000 we assume this is really a v2 protocol // server, so trigger fallback. throw new UnsupportedProtocolException(); } ServerErrorMessage errorMsg = new ServerErrorMessage(pgStream.ReceiveString(l_elen - 4), logger.getLogLevel()); if (logger.logDebug()) logger.debug(" <=BE ErrorMessage(" + errorMsg + ")"); throw new PSQLException(errorMsg); case 'R': // Authentication request. // Get the message length int l_msgLen = pgStream.ReceiveInteger4(); // Get the type of request int areq = pgStream.ReceiveInteger4(); // Process the request. switch (areq) { case AUTH_REQ_CRYPT: { byte[] rst = new byte[2]; rst[0] = (byte) pgStream.ReceiveChar(); rst[1] = (byte) pgStream.ReceiveChar(); String salt = new String(rst, 0, 2, "US-ASCII"); if (logger.logDebug()) logger.debug(" <=BE AuthenticationReqCrypt(salt='" + salt + "')"); if (password == null) throw new PSQLException( GT.tr( "The server requested password-based authentication, but no password was provided."), PSQLState.CONNECTION_REJECTED); String result = UnixCrypt.crypt(salt, password); byte[] encodedResult = result.getBytes("US-ASCII"); if (logger.logDebug()) logger.debug(" FE=> Password(crypt='" + result + "')"); pgStream.SendChar('p'); pgStream.SendInteger4(4 + encodedResult.length + 1); pgStream.Send(encodedResult); pgStream.SendChar(0); pgStream.flush(); break; } case AUTH_REQ_MD5: { byte[] md5Salt = pgStream.Receive(4); if (logger.logDebug()) { logger.debug( " <=BE AuthenticationReqMD5(salt=" + Utils.toHexString(md5Salt) + ")"); } if (password == null) throw new PSQLException( GT.tr( "The server requested password-based authentication, but no password was provided."), PSQLState.CONNECTION_REJECTED); byte[] digest = MD5Digest.encode(user, password, md5Salt); if (logger.logDebug()) { logger.debug(" FE=> Password(md5digest=" + new String(digest, "US-ASCII") + ")"); } pgStream.SendChar('p'); pgStream.SendInteger4(4 + digest.length + 1); pgStream.Send(digest); pgStream.SendChar(0); pgStream.flush(); break; } case AUTH_REQ_PASSWORD: { if (logger.logDebug()) { logger.debug(" <=BE AuthenticationReqPassword"); logger.debug(" FE=> Password(password=<not shown>)"); } if (password == null) throw new PSQLException( GT.tr( "The server requested password-based authentication, but no password was provided."), PSQLState.CONNECTION_REJECTED); byte[] encodedPassword = password.getBytes("US-ASCII"); pgStream.SendChar('p'); pgStream.SendInteger4(4 + encodedPassword.length + 1); pgStream.Send(encodedPassword); pgStream.SendChar(0); pgStream.flush(); break; } case AUTH_REQ_OK: if (logger.logDebug()) logger.debug(" <=BE AuthenticationOk"); return; // We're done. default: if (logger.logDebug()) logger.debug(" <=BE AuthenticationReq (unsupported type " + ((int) areq) + ")"); throw new PSQLException( GT.tr( "The authentication type {0} is not supported. Check that you have configured the pg_hba.conf file to include the client''s IP address or subnet, and that it is using an authentication scheme supported by the driver.", new Integer(areq)), PSQLState.CONNECTION_REJECTED); } break; default: throw new PSQLException( GT.tr("Protocol error. Session setup failed."), PSQLState.CONNECTION_UNABLE_TO_CONNECT); } } }