1#![forbid(unsafe_code)]
2
3use super::*;
4use crate::wire::ProtocolLimits;
5
6pub fn append_auth_phase_one(
7 out: &mut Vec<u8>,
8 user: &str,
9 program: &str,
10 machine: &str,
11 osuser: &str,
12 terminal: &str,
13 pid: u32,
14) -> Result<()> {
15 let mut writer = TtcWriter::new();
16 writer.write_function_code(TNS_FUNC_AUTH_PHASE_ONE);
17 write_auth_header(&mut writer, user, TNS_AUTH_MODE_LOGON, 5)?;
18 write_key_value(&mut writer, "AUTH_TERMINAL", terminal, 0)?;
19 write_key_value(&mut writer, "AUTH_PROGRAM_NM", program, 0)?;
20 write_key_value(&mut writer, "AUTH_MACHINE", machine, 0)?;
21 write_key_value(&mut writer, "AUTH_PID", &pid.to_string(), 0)?;
22 write_key_value(&mut writer, "AUTH_SID", osuser, 0)?;
23 out.extend_from_slice(&writer.into_bytes());
24 Ok(())
25}
26
27pub fn append_auth_phase_two_token(
36 out: &mut Vec<u8>,
37 user: &str,
38 token: &str,
39 driver_name: &str,
40 version_num: u32,
41 connect_string: &str,
42 edition: Option<&str>,
43) -> Result<()> {
44 let mut writer = TtcWriter::new();
45 writer.write_function_code(TNS_FUNC_AUTH_PHASE_TWO);
46 let mut num_pairs = 5u32;
49 if edition.is_some() {
50 num_pairs += 1;
51 }
52 if !connect_string.is_empty() {
53 num_pairs += 1;
54 }
55 write_auth_header(&mut writer, user, TNS_AUTH_MODE_LOGON, num_pairs)?;
56 write_key_value(&mut writer, "AUTH_TOKEN", token, 0)?;
57 write_key_value(&mut writer, "SESSION_CLIENT_CHARSET", "873", 0)?;
58 write_key_value(&mut writer, "SESSION_CLIENT_DRIVER_NAME", driver_name, 0)?;
59 write_key_value(
60 &mut writer,
61 "SESSION_CLIENT_VERSION",
62 &version_num.to_string(),
63 0,
64 )?;
65 write_key_value(
66 &mut writer,
67 "AUTH_ALTER_SESSION",
68 "ALTER SESSION SET TIME_ZONE='+00:00'\0",
69 1,
70 )?;
71 if let Some(edition) = edition {
76 write_key_value(&mut writer, "AUTH_ORA_EDITION", edition, 0)?;
77 }
78 if !connect_string.is_empty() {
79 write_key_value(&mut writer, "AUTH_CONNECT_STRING", connect_string, 0)?;
80 }
81 out.extend_from_slice(&writer.into_bytes());
82 Ok(())
83}
84
85pub fn build_auth_phase_two_payload(
86 user: &str,
87 encrypted: &crate::crypto::EncryptedPassword,
88 driver_name: &str,
89 version_num: u32,
90 connect_string: &str,
91) -> Result<Vec<u8>> {
92 build_auth_phase_two_payload_with_seq(
93 user,
94 encrypted,
95 driver_name,
96 version_num,
97 connect_string,
98 1,
99 )
100}
101
102pub fn build_auth_phase_two_payload_with_seq(
103 user: &str,
104 encrypted: &crate::crypto::EncryptedPassword,
105 driver_name: &str,
106 version_num: u32,
107 connect_string: &str,
108 seq_num: u8,
109) -> Result<Vec<u8>> {
110 build_auth_phase_two_payload_with_context_with_seq(
111 user,
112 encrypted,
113 driver_name,
114 version_num,
115 connect_string,
116 seq_num,
117 &[],
118 )
119}
120
121pub fn build_auth_phase_two_payload_with_context_with_seq(
122 user: &str,
123 encrypted: &crate::crypto::EncryptedPassword,
124 driver_name: &str,
125 version_num: u32,
126 connect_string: &str,
127 seq_num: u8,
128 app_context: &[(String, String, String)],
129) -> Result<Vec<u8>> {
130 build_auth_phase_two_payload_with_proxy_with_seq(
131 user,
132 encrypted,
133 driver_name,
134 version_num,
135 connect_string,
136 seq_num,
137 app_context,
138 None,
139 None,
140 ClientCapabilities::default().ttc_field_version,
141 )
142}
143
144#[allow(clippy::too_many_arguments)]
154pub fn build_auth_phase_two_payload_with_proxy_with_seq(
155 user: &str,
156 encrypted: &crate::crypto::EncryptedPassword,
157 driver_name: &str,
158 version_num: u32,
159 connect_string: &str,
160 seq_num: u8,
161 app_context: &[(String, String, String)],
162 proxy_user: Option<&str>,
163 edition: Option<&str>,
164 ttc_field_version: u8,
165) -> Result<Vec<u8>> {
166 let mut writer = TtcWriter::new();
167 writer.write_function_code_with_seq(TNS_FUNC_AUTH_PHASE_TWO, seq_num);
168 if version_gates::writes_pipeline_token(ttc_field_version) {
169 writer.write_ub8(0);
170 }
171 let mut num_pairs = 6u32;
172 if encrypted.speedy_key.is_some() {
173 num_pairs += 1;
174 }
175 if proxy_user.is_some() {
176 num_pairs += 1;
177 }
178 if !connect_string.is_empty() {
179 num_pairs += 1;
180 }
181 if edition.is_some() {
182 num_pairs += 1;
183 }
184 let app_context_pairs =
185 app_context
186 .len()
187 .checked_mul(3)
188 .ok_or(ProtocolError::InvalidPacketLength {
189 length: app_context.len(),
190 minimum: 0,
191 })?;
192 num_pairs +=
193 u32::try_from(app_context_pairs).map_err(|_| ProtocolError::InvalidPacketLength {
194 length: app_context.len(),
195 minimum: 0,
196 })?;
197 write_auth_header(
198 &mut writer,
199 user,
200 TNS_AUTH_MODE_LOGON | TNS_AUTH_MODE_WITH_PASSWORD,
201 num_pairs,
202 )?;
203 if let Some(proxy_user) = proxy_user {
204 write_key_value(&mut writer, "PROXY_CLIENT_NAME", proxy_user, 0)?;
205 }
206 write_key_value(&mut writer, "AUTH_SESSKEY", &encrypted.session_key, 1)?;
207 if let Some(speedy_key) = &encrypted.speedy_key {
208 write_key_value(&mut writer, "AUTH_PBKDF2_SPEEDY_KEY", speedy_key, 0)?;
209 }
210 write_key_value(&mut writer, "AUTH_PASSWORD", &encrypted.password, 0)?;
211 write_key_value(&mut writer, "SESSION_CLIENT_CHARSET", "873", 0)?;
212 write_key_value(&mut writer, "SESSION_CLIENT_DRIVER_NAME", driver_name, 0)?;
213 write_key_value(
214 &mut writer,
215 "SESSION_CLIENT_VERSION",
216 &version_num.to_string(),
217 0,
218 )?;
219 write_key_value(
220 &mut writer,
221 "AUTH_ALTER_SESSION",
222 "ALTER SESSION SET TIME_ZONE='+00:00'\0",
223 1,
224 )?;
225 if let Some(edition) = edition {
229 write_key_value(&mut writer, "AUTH_ORA_EDITION", edition, 0)?;
230 }
231 for (namespace, name, value) in app_context {
232 write_key_value(&mut writer, "AUTH_APPCTX_NSPACE\0", namespace, 0)?;
233 write_key_value(&mut writer, "AUTH_APPCTX_ATTR\0", name, 0)?;
234 write_key_value(&mut writer, "AUTH_APPCTX_VALUE\0", value, 0)?;
235 }
236 if !connect_string.is_empty() {
237 write_key_value(&mut writer, "AUTH_CONNECT_STRING", connect_string, 0)?;
238 }
239 Ok(writer.into_bytes())
240}
241
242pub fn build_change_password_payload_with_seq(
247 user: &str,
248 encoded_password: &str,
249 encoded_newpassword: &str,
250 seq_num: u8,
251 ttc_field_version: u8,
252) -> Result<Vec<u8>> {
253 let mut writer = TtcWriter::new();
254 writer.write_function_code_with_seq(TNS_FUNC_AUTH_PHASE_TWO, seq_num);
255 if version_gates::writes_pipeline_token(ttc_field_version) {
256 writer.write_ub8(0);
257 }
258 write_auth_header(
259 &mut writer,
260 user,
261 TNS_AUTH_MODE_WITH_PASSWORD | TNS_AUTH_MODE_CHANGE_PASSWORD,
262 2,
263 )?;
264 write_key_value(&mut writer, "AUTH_PASSWORD", encoded_password, 0)?;
265 write_key_value(&mut writer, "AUTH_NEWPASSWORD", encoded_newpassword, 0)?;
266 Ok(writer.into_bytes())
267}
268
269pub fn parse_auth_response(payload: &[u8]) -> Result<AuthResponse> {
270 parse_auth_response_with_limits(payload, ProtocolLimits::DEFAULT)
271}
272
273pub fn classic_connect_response_is_complete(
295 payload: &[u8],
296 limits: ProtocolLimits,
297) -> Result<bool> {
298 let Ok(mut reader) = TtcReader::with_limits(payload, limits) else {
299 return Ok(false);
300 };
301 while reader.remaining() > 0 {
302 let message_type = reader.read_u8()?;
303 let terminal = match message_type {
304 TNS_MSG_TYPE_PROTOCOL => match skip_protocol_message(&mut reader) {
305 Ok(_) => true,
306 Err(ProtocolError::TtcDecode(_)) => return Ok(false),
307 Err(err) => return Err(err),
308 },
309 TNS_MSG_TYPE_DATA_TYPES => match skip_data_types_response(&mut reader) {
310 Ok(()) => true,
311 Err(ProtocolError::TtcDecode(_)) => return Ok(false),
312 Err(err) => return Err(err),
313 },
314 TNS_MSG_TYPE_PARAMETER => match parse_return_parameters(&mut reader) {
315 Ok(_) => false,
316 Err(ProtocolError::TtcDecode(_)) => return Ok(false),
317 Err(err) => return Err(err),
318 },
319 TNS_MSG_TYPE_STATUS => {
320 let complete = reader.read_ub4().and_then(|_| reader.read_ub2());
321 match complete {
322 Ok(_) => true,
323 Err(ProtocolError::TtcDecode(_)) => return Ok(false),
324 Err(err) => return Err(err),
325 }
326 }
327 TNS_MSG_TYPE_SERVER_SIDE_PIGGYBACK => match skip_server_side_piggyback(&mut reader) {
328 Ok(_) => false,
329 Err(ProtocolError::TtcDecode(_)) => return Ok(false),
330 Err(err) => return Err(err),
331 },
332 TNS_MSG_TYPE_END_OF_RESPONSE => true,
333 TNS_MSG_TYPE_ERROR => match parse_server_error(&mut reader, 13) {
334 Ok(_) | Err(ProtocolError::ServerError(_)) => true,
335 Err(ProtocolError::TtcDecode(_)) => return Ok(false),
336 Err(err) => return Err(err),
337 },
338 _ => {
339 return Err(ProtocolError::UnknownMessageType {
340 message_type,
341 position: reader.position().saturating_sub(1),
342 })
343 }
344 };
345 if terminal {
346 return Ok(true);
347 }
348 }
349 Ok(false)
350}
351
352pub fn parse_auth_response_with_limits(
353 payload: &[u8],
354 limits: ProtocolLimits,
355) -> Result<AuthResponse> {
356 let mut reader = TtcReader::with_limits(payload, limits)?;
357 let mut response = AuthResponse::default();
358 while reader.remaining() > 0 {
359 let message_type = reader.read_u8()?;
360 match message_type {
361 TNS_MSG_TYPE_PROTOCOL => {
362 if let Some(capabilities) = skip_protocol_message(&mut reader)? {
363 response.capabilities = Some(capabilities);
364 }
365 }
366 TNS_MSG_TYPE_DATA_TYPES => skip_data_types_response(&mut reader)?,
367 TNS_MSG_TYPE_PARAMETER => {
368 let mut parsed = parse_return_parameters(&mut reader)?;
369 response.session_data.append(&mut parsed.session_data);
370 if parsed.verifier_type.is_some() {
371 response.verifier_type = parsed.verifier_type;
372 }
373 }
374 TNS_MSG_TYPE_STATUS => {
375 let _call_status = reader.read_ub4()?;
376 let _seq = reader.read_ub2()?;
377 }
378 TNS_MSG_TYPE_SERVER_SIDE_PIGGYBACK => {
379 let _ = skip_server_side_piggyback(&mut reader)?;
380 }
381 TNS_MSG_TYPE_END_OF_RESPONSE => break,
382 TNS_MSG_TYPE_ERROR => {
383 if let Some(message) = parse_server_error(&mut reader, 13)? {
384 return Err(ProtocolError::ServerError(message));
385 }
386 }
387 _ => {
388 return Err(ProtocolError::UnknownMessageType {
389 message_type,
390 position: reader.position().saturating_sub(1),
391 })
392 }
393 }
394 }
395 Ok(response)
396}
397
398pub(crate) fn write_auth_header(
399 writer: &mut TtcWriter,
400 user: &str,
401 auth_mode: u32,
402 num_pairs: u32,
403) -> Result<()> {
404 let user_bytes = user.as_bytes();
405 writer.write_u8(u8::from(!user_bytes.is_empty()));
406 writer.write_ub4(u32::try_from(user_bytes.len()).map_err(|_| {
407 ProtocolError::InvalidPacketLength {
408 length: user_bytes.len(),
409 minimum: 0,
410 }
411 })?);
412 writer.write_ub4(auth_mode);
413 writer.write_u8(1);
414 writer.write_ub4(num_pairs);
415 writer.write_u8(1);
416 writer.write_u8(1);
417 if !user_bytes.is_empty() {
418 writer.write_bytes_with_length(user_bytes)?;
419 }
420 Ok(())
421}
422
423pub(crate) fn write_key_value(
424 writer: &mut TtcWriter,
425 key: &str,
426 value: &str,
427 flags: u32,
428) -> Result<()> {
429 writer.write_str_two_lengths(key)?;
430 writer.write_str_two_lengths(value)?;
431 writer.write_ub4(flags);
432 Ok(())
433}
434
435pub(crate) fn parse_return_parameters(reader: &mut TtcReader<'_>) -> Result<AuthResponse> {
436 let num_params = reader.read_ub2()?;
437 reader
438 .limits()
439 .check_length_prefixed_elements(usize::from(num_params))?;
440 let mut response = AuthResponse::default();
441 for _ in 0..num_params {
442 let key = reader
443 .read_string_with_length()?
444 .ok_or(ProtocolError::TtcDecode("missing auth response key"))?;
445 let value = reader.read_string_with_length()?.unwrap_or_default();
446 if key == "AUTH_VFR_DATA" {
447 response.verifier_type = Some(reader.read_ub4()?);
448 } else {
449 let _flags = reader.read_ub4()?;
450 }
451 response.session_data.insert(key, value);
452 }
453 Ok(response)
454}
455
456#[cfg(test)]
457mod token_auth_tests {
458 use super::*;
459
460 fn read_ub4(bytes: &[u8], pos: &mut usize) -> u32 {
462 let len = bytes[*pos] as usize;
463 *pos += 1;
464 let mut value = 0u32;
465 for _ in 0..len {
466 value = (value << 8) | u32::from(bytes[*pos]);
467 *pos += 1;
468 }
469 value
470 }
471
472 fn contains(haystack: &[u8], needle: &[u8]) -> bool {
473 haystack.windows(needle.len()).any(|w| w == needle)
474 }
475
476 #[test]
481 fn token_message_carries_auth_token_not_password() {
482 let mut out = Vec::new();
483 append_auth_phase_two_token(
484 &mut out,
485 "scott",
486 "HEADER.PAYLOAD.SIG",
487 "drv",
488 300_000_000,
489 "cs",
490 None,
491 )
492 .unwrap();
493
494 assert_eq!(out[0], TNS_MSG_TYPE_FUNCTION);
496 assert_eq!(out[1], TNS_FUNC_AUTH_PHASE_TWO);
497 assert_eq!(out[3], 1, "user is present");
499 let mut pos = 4;
500 assert_eq!(read_ub4(&out, &mut pos), 5, "user length = len(\"scott\")");
501 assert_eq!(
502 read_ub4(&out, &mut pos),
503 TNS_AUTH_MODE_LOGON,
504 "token auth uses LOGON only — never the WITH_PASSWORD bit"
505 );
506 assert_eq!(out[pos], 1); pos += 1;
508 assert_eq!(
509 read_ub4(&out, &mut pos),
510 6,
511 "AUTH_TOKEN + 4 session pairs + AUTH_CONNECT_STRING"
512 );
513
514 assert!(contains(&out, b"AUTH_TOKEN"));
515 assert!(
516 contains(&out, b"HEADER.PAYLOAD.SIG"),
517 "the token value is sent"
518 );
519 assert!(contains(&out, b"AUTH_CONNECT_STRING"));
520 assert!(
521 !contains(&out, b"AUTH_PASSWORD") && !contains(&out, b"AUTH_SESSKEY"),
522 "token auth must not send any password material"
523 );
524 }
525
526 #[test]
529 fn token_message_pair_count_without_connect_string() {
530 let mut out = Vec::new();
531 append_auth_phase_two_token(&mut out, "u", "tok", "drv", 1, "", None).unwrap();
532 let mut pos = 4;
533 let _user_len = read_ub4(&out, &mut pos);
534 let _auth_mode = read_ub4(&out, &mut pos);
535 pos += 1; assert_eq!(read_ub4(&out, &mut pos), 5, "AUTH_TOKEN + 4 session pairs");
537 assert!(!contains(&out, b"AUTH_CONNECT_STRING"));
538 }
539
540 #[test]
544 fn token_message_carries_edition() {
545 let mut out = Vec::new();
546 append_auth_phase_two_token(&mut out, "u", "tok", "drv", 1, "", Some("E_TEST")).unwrap();
547 let mut pos = 4;
548 let _user_len = read_ub4(&out, &mut pos);
549 let _auth_mode = read_ub4(&out, &mut pos);
550 pos += 1; assert_eq!(
552 read_ub4(&out, &mut pos),
553 6,
554 "AUTH_TOKEN + 4 session pairs + AUTH_ORA_EDITION"
555 );
556 assert!(contains(&out, b"AUTH_ORA_EDITION"));
557 assert!(contains(&out, b"E_TEST"), "the edition value is sent");
558
559 let mut out2 = Vec::new();
561 append_auth_phase_two_token(&mut out2, "u", "tok", "drv", 1, "cs", Some("E_TEST")).unwrap();
562 let mut p = 4;
563 let _ = read_ub4(&out2, &mut p);
564 let _ = read_ub4(&out2, &mut p);
565 p += 1;
566 assert_eq!(read_ub4(&out2, &mut p), 7, "+ AUTH_CONNECT_STRING");
567 }
568}