Documentation
¶
Index ¶
- Constants
- Variables
- func GenerateO5LogonVerifier(password string) ([]byte, []byte, error)
- func IsExecSQL(ttcPayload []byte) bool
- func IsPiggybackClose(ttcPayload []byte) bool
- func IsPiggybackExecSQL(ttcPayload []byte) bool
- type ConnectDescriptor
- type O5LogonServer
- func (s *O5LogonServer) CustomHashEnabled() bool
- func (s *O5LogonServer) DecryptPassword(encClientSessKey, encPassword string) (string, error)
- func (s *O5LogonServer) DeriveCombinedKey(encClientSessKey string) error
- func (s *O5LogonServer) EnableCustomHash()
- func (s *O5LogonServer) GenerateChallenge() (string, string, error)
- func (s *O5LogonServer) PBKDF2ChkSalt() string
- func (s *O5LogonServer) PBKDF2SderCount() int
- func (s *O5LogonServer) PBKDF2VgenCount() int
- type OALL8Result
- type OFETCHResult
- type QueryResultV2
- type Server
- type TNSPacket
- type TNSPacketType
- type TTCFunctionCode
- type TTCResponse
Constants ¶
const ( ORA01017 uint16 = 1017 // ORA-01017: invalid username/password; logon denied ORA12505 uint16 = 12505 // TNS:listener does not currently know of SID ORA12514 uint16 = 12514 // TNS:listener does not currently know of service ORA12520 uint16 = 12520 // TNS:listener could not find available handler ORA12535 uint16 = 12535 // TNS:operation timed out ORA12541 uint16 = 12541 // TNS:no listener )
ORA error codes for TNS Refuse packets.
const ( PiggybackSubClose byte = 0x09 // Close cursor PiggybackSubExecSQL byte = 0x5e // Execute with SQL (OALL8 equivalent) PiggybackSubAuth1 byte = 0x76 // AUTH Phase 1 PiggybackSubAuth2 byte = 0x73 // AUTH Phase 2 )
Piggyback sub-operation codes (byte 1 when func=0x03).
const ( OracleTypeVARCHAR2 uint8 = 1 OracleTypeNUMBER uint8 = 2 OracleTypeDATE uint8 = 12 OracleTypeRAW uint8 = 23 OracleTypeCHAR uint8 = 96 OracleTypeBINFLOAT uint8 = 100 OracleTypeBINDOUBLE uint8 = 101 OracleTypeCLOB uint8 = 112 OracleTypeBLOB uint8 = 113 OracleTypeTIMESTAMP uint8 = 180 OracleTypeTIMESTAMPTZ uint8 = 181 OracleTypeTIMESTAMPLTZ uint8 = 231 )
Oracle data type codes.
const ( // VerifierType6949 selects the SHA-1 / MD5-XOR (or SHA-1 / PBKDF2 customHash) // derivation paths. VerifierType6949 = 6949 // VerifierType18453 selects the modern PBKDF2 / HMAC-SHA512 path. VerifierType18453 = 18453 )
Oracle verifier types observed in AUTH_VFR_DATA's flag field.
Variables ¶
var ( ErrAuthSvrResponseKeyNotFound = errors.New("AUTH_SVR_RESPONSE key not found in AUTH OK") ErrAuthSvrResponseTruncated = errors.New("AUTH_SVR_RESPONSE value truncated") ErrAuthSvrResponseNotHex = errors.New("AUTH_SVR_RESPONSE value not uppercase hex") ErrAuthSvrResponseBadLength = errors.New("AUTH_SVR_RESPONSE rebuilt with wrong length") )
AUTH_SVR_RESPONSE patcher errors.
var ( // ErrEmptyUsername indicates an AUTH message with no username. ErrEmptyUsername = errors.New("empty username in AUTH message") // ErrNoActiveGrant indicates no active grant exists for the user/database pair. ErrNoActiveGrant = errors.New("no active grant for this user/database") // ErrQueryLimitExceed indicates the grant's query count quota has been reached. ErrQueryLimitExceed = errors.New("query limit exceeded") // ErrDataLimitExceed indicates the grant's data transfer quota has been reached. ErrDataLimitExceed = errors.New("data transfer limit exceeded") // ErrDatabaseNotFound indicates the requested database was not found in the store. ErrDatabaseNotFound = errors.New("database not found") // ErrUserNotFound indicates the requested user was not found in the store. ErrUserNotFound = errors.New("user not found") // ErrTTCPayloadTooShort indicates a TTC payload is shorter than expected. ErrTTCPayloadTooShort = errors.New("TTC payload too short") // ErrNotDataPacket indicates a non-Data TNS packet was received where Data was expected. ErrNotDataPacket = errors.New("expected TNS Data packet") // ErrAuthFailed indicates upstream authentication did not succeed. ErrAuthFailed = errors.New("upstream authentication failed") // ErrExpectedConnectPacket indicates a non-Connect packet was received at session start. ErrExpectedConnectPacket = errors.New("expected TNS Connect packet") // ErrNoServiceName indicates the connect descriptor lacks a SERVICE_NAME. ErrNoServiceName = errors.New("no SERVICE_NAME in connect descriptor") // ErrUpstreamRefused indicates the upstream Oracle server refused the connection. ErrUpstreamRefused = errors.New("upstream refused connection") // ErrClientAuthFailed indicates client authentication to dbbat failed. ErrClientAuthFailed = errors.New("client authentication failed") // ErrNoO5LogonVerifier indicates no API key with O5LOGON verifier was found. ErrNoO5LogonVerifier = errors.New("no API key with O5LOGON verifier found") // ErrAPIKeyOwnerMismatch indicates the API key does not belong to the authenticated user. ErrAPIKeyOwnerMismatchOracle = errors.New("API key does not belong to user") // ErrColumnDefTooShort indicates a column definition is shorter than expected. ErrColumnDefTooShort = errors.New("column definition too short") // ErrColumnNameTruncated indicates a column name extends beyond the payload. ErrColumnNameTruncated = errors.New("column name exceeds payload") // ErrNoTypeCode indicates a column definition is missing the type code byte. ErrNoTypeCode = errors.New("column definition missing type code") // ErrEmptyRowData indicates an empty row data payload. ErrEmptyRowData = errors.New("empty row data") // ErrRowValueTruncated indicates a row value extends beyond the payload. ErrRowValueTruncated = errors.New("row value exceeds payload") // ErrInvalidFloatLength indicates float data has an unexpected length. ErrInvalidFloatLength = errors.New("invalid float data length") // O5LOGON and TTC auth errors. ErrDecryptedPasswordTooShort = errors.New("decrypted password too short") ErrNoCombinedKeyCandidate = errors.New("no combined-key candidate available") ErrCiphertextNotAligned = errors.New("ciphertext is not a multiple of block size") ErrInvalidPadding = errors.New("invalid PKCS7 padding") ErrAuthPhase1TooShort = errors.New("AUTH Phase 1 payload too short") ErrAuthPhase1NoData = errors.New("AUTH Phase 1: no data after sub-op") ErrAuthPhase1BadUsername = errors.New("AUTH Phase 1: invalid username length") ErrAuthPhase2TooShort = errors.New("AUTH Phase 2 payload too short") ErrAuthPhase2MissingSessKey = errors.New("AUTH Phase 2: missing AUTH_SESSKEY") ErrAuthPhase2MissingPassword = errors.New("AUTH Phase 2: missing AUTH_PASSWORD") ErrUnexpectedPacketType = errors.New("unexpected TNS packet type") ErrMaxResendExceeded = errors.New("exceeded maximum resend attempts") ErrUpstreamTooManyRedirects = errors.New("upstream: too many redirects") ErrRedirectMissingHostPort = errors.New("redirect: could not extract HOST/PORT from descriptor") )
Oracle proxy errors.
var ( ErrTNSHeaderTooShort = errors.New("TNS header too short: need at least 8 bytes") ErrTNSPacketTooLarge = errors.New("TNS packet length exceeds maximum") )
TNS errors.
var ( ErrEmptySQL = errors.New("OALL8 message contains empty SQL") ErrOALL8TooShort = errors.New("OALL8 payload too short") ErrOFETCHTooShort = errors.New("OFETCH payload too short") ErrSQLLengthInvalid = errors.New("OALL8 SQL length exceeds payload") )
Decoding errors.
var ( ErrInvalidDateLength = errors.New("oracle DATE requires exactly 7 bytes") ErrInvalidTimestampLength = errors.New("oracle TIMESTAMP requires at least 11 bytes") ErrInvalidNumberData = errors.New("oracle NUMBER data is empty") )
Type decoding errors.
var ( ErrUpstreamConnNotSet = errors.New("upstream connection not set before AUTH") ErrPhase1MissingSessKey = errors.New("AUTH Phase 1 response: missing AUTH_SESSKEY") ErrPhase1MissingVerifierData = errors.New("AUTH Phase 1 response: missing AUTH_VFR_DATA") ErrInvalidHex = errors.New("invalid hex character") ErrInvalidHexLength = errors.New("invalid hex string length") ErrUpstreamAuthPhase1Rejected = errors.New("upstream AUTH Phase 1 rejected") ErrUpstreamAuthPhase2Rejected = errors.New("upstream AUTH Phase 2 rejected") )
errors specific to the upstream AUTH client.
var ErrAuthPhase1Rewrite = errors.New("AUTH Phase 1 rewrite failed")
ErrAuthPhase1Rewrite signals a Phase 1 body that does not match the expected piggyback/sub-op/userLen/mode/magic/username layout.
var ErrAuthPhase2Rewrite = errors.New("AUTH Phase 2 rewrite failed")
ErrAuthPhase2Rewrite signals a Phase 2 body that does not match the expected piggyback / has-username / user_id_len / mode / pair_count layout or whose KV pairs cannot be parsed.
var ErrUnsupportedVerifier = errors.New("unsupported Oracle verifier type")
ErrUnsupportedVerifier indicates an Oracle verifier type dbbat does not implement.
Functions ¶
func GenerateO5LogonVerifier ¶ added in v0.5.0
GenerateO5LogonVerifier creates salt + verifier key from a plaintext password. Called at API key creation time; the results are stored in the database. Delegates to the crypto package for the core computation.
func IsExecSQL ¶ added in v0.5.0
IsExecSQL checks if a func=0x11 payload is an execute-with-SQL message rather than a plain OFETCH. Different clients use different sub-ops.
func IsPiggybackClose ¶
IsPiggybackClose checks if a piggyback payload is a close cursor message.
func IsPiggybackExecSQL ¶
IsPiggybackExecSQL checks if a piggyback payload is an execute-with-SQL message.
Types ¶
type ConnectDescriptor ¶
type ConnectDescriptor struct {
ServiceName string
SID string
Host string
Port int
Program string // From CID
OSUser string // From CID
}
ConnectDescriptor holds metadata parsed from an Oracle connect descriptor.
type O5LogonServer ¶ added in v0.5.0
type O5LogonServer struct {
// CombinedKey is set by DecryptPassword to the negotiated combined key
// — either MD5/XOR (legacy) or the PBKDF2-customHash derivation. It is
// the AES key the client expects for AUTH_SVR_RESPONSE in the AUTH OK
// forwarded back.
CombinedKey []byte
// contains filtered or unexported fields
}
O5LogonServer implements server-side O5LOGON authentication. This is the mirror of the client-side implementation in go-ora.
func NewO5LogonServer ¶ added in v0.5.0
func NewO5LogonServer(salt, verifierKey []byte) *O5LogonServer
NewO5LogonServer creates a server from stored verifier data.
func (*O5LogonServer) CustomHashEnabled ¶ added in v0.9.0
func (s *O5LogonServer) CustomHashEnabled() bool
CustomHashEnabled reports whether the server is in customHash mode. Used by the challenge builder to decide whether to include AUTH_PBKDF2_* fields.
func (*O5LogonServer) DecryptPassword ¶ added in v0.5.0
func (s *O5LogonServer) DecryptPassword(encClientSessKey, encPassword string) (string, error)
DecryptPassword extracts the plaintext password from the client's AUTH Phase 2. The client encrypts: random_prefix(16 bytes) + password using AES-192-CBC with a combined key derived from both session keys.
In customHash mode the server attempts both the customHash combined-key derivation (matching go-ora and JDBC, where the server-advertised customHash bit and the AUTH_PBKDF2_* fields are honored) and the legacy MD5/XOR path (matching python-oracledb thin, which always picks legacy when the session_key is 48 bytes regardless of caps[4]&0x20). The first candidate that yields a printable plaintext password wins. Out of customHash mode, only the legacy path is tried.
Side-effect: on success, the negotiated combined key is stored on the receiver as CombinedKey so callers can reuse it (e.g. to encrypt AUTH_SVR_RESPONSE in the AUTH OK payload forwarded to the client).
func (*O5LogonServer) DeriveCombinedKey ¶ added in v0.9.0
func (s *O5LogonServer) DeriveCombinedKey(encClientSessKey string) error
DeriveCombinedKey computes the combined-key the client used (the first candidate per combinedKeyCandidates) and stores it on the receiver, without requiring an AUTH_PASSWORD plaintext to verify against. Used by the empty-AUTH_PASSWORD branch (SQLcl / JDBC thin 23c+) where the proxy has no way to validate by password decryption — but still needs the combined key so it can re-encrypt AUTH_SVR_RESPONSE before forwarding the upstream's AUTH OK to the client.
In customHash mode the customHash PBKDF2 derivation is preferred (matches JDBC and go-ora). Otherwise the legacy MD5/XOR combined key is used.
func (*O5LogonServer) EnableCustomHash ¶ added in v0.9.0
func (s *O5LogonServer) EnableCustomHash()
EnableCustomHash switches the server into customHash mode. GenerateChallenge will then advertise per-session AUTH_PBKDF2_CSK_SALT / VGEN_COUNT / SDER_COUNT fields and DecryptPassword will use the PBKDF2-customHash combined-key derivation. Used when the upstream's Set Protocol response had caps[4]&0x20 set — keeping the bit on the client side avoids the verifier-6949 downgrade that real Oracle emits when the client signals "no customHash support".
func (*O5LogonServer) GenerateChallenge ¶ added in v0.5.0
func (s *O5LogonServer) GenerateChallenge() (string, string, error)
GenerateChallenge produces the AUTH_SESSKEY and AUTH_VFR_DATA for the client. Returns hex-encoded encrypted server session key and auth verifier data.
In customHash mode it also generates a fresh AUTH_PBKDF2_CSK_SALT (accessible via PBKDF2ChkSalt) so the caller can include the matching KV fields in the Phase 1 challenge sent on the wire.
func (*O5LogonServer) PBKDF2ChkSalt ¶ added in v0.9.0
func (s *O5LogonServer) PBKDF2ChkSalt() string
PBKDF2ChkSalt returns the per-session salt as an uppercase hex string. Empty until GenerateChallenge has run in customHash mode.
func (*O5LogonServer) PBKDF2SderCount ¶ added in v0.9.0
func (s *O5LogonServer) PBKDF2SderCount() int
PBKDF2SderCount returns the session-key-derivation iteration count advertised in the challenge as AUTH_PBKDF2_SDER_COUNT.
func (*O5LogonServer) PBKDF2VgenCount ¶ added in v0.9.0
func (s *O5LogonServer) PBKDF2VgenCount() int
PBKDF2VgenCount returns the verifier-generation iteration count advertised in the challenge as AUTH_PBKDF2_VGEN_COUNT.
type OALL8Result ¶
OALL8Result contains the decoded fields from an OALL8 (parse+execute) message.
func (*OALL8Result) IsPLSQL ¶
func (r *OALL8Result) IsPLSQL() bool
IsPLSQL returns true if the SQL text is a PL/SQL block.
type OFETCHResult ¶
OFETCHResult contains the decoded fields from an OFETCH message.
type QueryResultV2 ¶
type QueryResultV2 struct {
Columns []string
Rows [][]string
NoData bool // true if ORA-01403 (normal end-of-data)
}
QueryResultV2 contains parsed data from a v315+ TTC QueryResult (func=0x10).
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the Oracle proxy server.
func NewServer ¶
func NewServer( dataStore *store.Store, encryptionKey []byte, authCache *cache.AuthCache, queryStorage config.QueryStorageConfig, dumpConfig config.DumpConfig, logger *slog.Logger, ) *Server
NewServer creates a new Oracle proxy server.
type TNSPacket ¶
type TNSPacket struct {
Type TNSPacketType
Flags byte
Length uint16
Payload []byte
Raw []byte // Original raw bytes (for forwarding without re-encoding)
}
TNSPacket represents a single TNS protocol packet.
type TNSPacketType ¶
type TNSPacketType byte
TNSPacketType represents a TNS packet type code.
const ( TNSPacketTypeConnect TNSPacketType = 1 TNSPacketTypeAccept TNSPacketType = 2 TNSPacketTypeRefuse TNSPacketType = 3 TNSPacketTypeRedirect TNSPacketType = 4 TNSPacketTypeMarker TNSPacketType = 5 TNSPacketTypeData TNSPacketType = 6 TNSPacketTypeResend TNSPacketType = 11 TNSPacketTypeControl TNSPacketType = 12 )
TNS packet type codes.
func (TNSPacketType) String ¶
func (t TNSPacketType) String() string
String returns a human-readable name for the packet type.
type TTCFunctionCode ¶
type TTCFunctionCode byte
TTCFunctionCode represents a TTC function code inside a TNS Data packet. TTC (Two-Task Common) is Oracle's RPC protocol layered inside TNS Data packets.
Layout of a TNS Data packet payload:
Offset Size Field 0 2 Data flags (usually 0x0000) 2 1 TTC function code 3 ... Function-specific payload
const ( TTCFuncSetProtocol TTCFunctionCode = 0x01 // OSETPRO — session init TTCFuncSetDataTypes TTCFunctionCode = 0x02 // ODTYPES — session init TTCFuncPiggyback TTCFunctionCode = 0x03 // Generic piggyback (sub-op at byte 1) TTCFuncOCLOSE TTCFunctionCode = 0x05 // OCLOSE — close cursor (legacy) TTCFuncContinuation TTCFunctionCode = 0x06 // Continuation data (multi-packet result rows) TTCFuncResponse TTCFunctionCode = 0x08 // Server response TTCFuncOClosev2 TTCFunctionCode = 0x09 // OCLOSE — close cursor (v315+) TTCFuncOVersion TTCFunctionCode = 0x0B // OVERSION — version request TTCFuncOALL8 TTCFunctionCode = 0x0E // OALL8 — parse+execute (legacy) TTCFuncQueryResult TTCFunctionCode = 0x10 // Query result with row data TTCFuncOFETCH TTCFunctionCode = 0x11 // OFETCH — fetch rows TTCFuncOCANCEL TTCFunctionCode = 0x14 // OCANCEL — cancel query )
TTC function codes for Oracle's Two-Task Common protocol. In modern Oracle (v315+), function 0x03 is a generic "piggyback" that carries sub-operations (auth, execute, close, etc.) identified by byte 1.
func (TTCFunctionCode) String ¶
func (fc TTCFunctionCode) String() string
String returns a human-readable name for the TTC function code.