1#![forbid(unsafe_code)]
2
3use super::*;
4
5pub fn append_auth_phase_one(
6 out: &mut Vec<u8>,
7 user: &str,
8 program: &str,
9 machine: &str,
10 osuser: &str,
11 terminal: &str,
12 pid: u32,
13) -> Result<()> {
14 let mut writer = TtcWriter::new();
15 writer.write_function_code(TNS_FUNC_AUTH_PHASE_ONE);
16 write_auth_header(&mut writer, user, TNS_AUTH_MODE_LOGON, 5)?;
17 write_key_value(&mut writer, "AUTH_TERMINAL", terminal, 0)?;
18 write_key_value(&mut writer, "AUTH_PROGRAM_NM", program, 0)?;
19 write_key_value(&mut writer, "AUTH_MACHINE", machine, 0)?;
20 write_key_value(&mut writer, "AUTH_PID", &pid.to_string(), 0)?;
21 write_key_value(&mut writer, "AUTH_SID", osuser, 0)?;
22 out.extend_from_slice(&writer.into_bytes());
23 Ok(())
24}
25
26pub fn append_auth_phase_two_token(
35 out: &mut Vec<u8>,
36 user: &str,
37 token: &str,
38 driver_name: &str,
39 version_num: u32,
40 connect_string: &str,
41 edition: Option<&str>,
42) -> Result<()> {
43 let mut writer = TtcWriter::new();
44 writer.write_function_code(TNS_FUNC_AUTH_PHASE_TWO);
45 let mut num_pairs = 5u32;
48 if edition.is_some() {
49 num_pairs += 1;
50 }
51 if !connect_string.is_empty() {
52 num_pairs += 1;
53 }
54 write_auth_header(&mut writer, user, TNS_AUTH_MODE_LOGON, num_pairs)?;
55 write_key_value(&mut writer, "AUTH_TOKEN", token, 0)?;
56 write_key_value(&mut writer, "SESSION_CLIENT_CHARSET", "873", 0)?;
57 write_key_value(&mut writer, "SESSION_CLIENT_DRIVER_NAME", driver_name, 0)?;
58 write_key_value(
59 &mut writer,
60 "SESSION_CLIENT_VERSION",
61 &version_num.to_string(),
62 0,
63 )?;
64 write_key_value(
65 &mut writer,
66 "AUTH_ALTER_SESSION",
67 "ALTER SESSION SET TIME_ZONE='+00:00'\0",
68 1,
69 )?;
70 if let Some(edition) = edition {
75 write_key_value(&mut writer, "AUTH_ORA_EDITION", edition, 0)?;
76 }
77 if !connect_string.is_empty() {
78 write_key_value(&mut writer, "AUTH_CONNECT_STRING", connect_string, 0)?;
79 }
80 out.extend_from_slice(&writer.into_bytes());
81 Ok(())
82}
83
84pub fn build_auth_phase_two_payload(
85 user: &str,
86 encrypted: &crate::crypto::EncryptedPassword,
87 driver_name: &str,
88 version_num: u32,
89 connect_string: &str,
90) -> Result<Vec<u8>> {
91 build_auth_phase_two_payload_with_seq(
92 user,
93 encrypted,
94 driver_name,
95 version_num,
96 connect_string,
97 1,
98 )
99}
100
101pub fn build_auth_phase_two_payload_with_seq(
102 user: &str,
103 encrypted: &crate::crypto::EncryptedPassword,
104 driver_name: &str,
105 version_num: u32,
106 connect_string: &str,
107 seq_num: u8,
108) -> Result<Vec<u8>> {
109 build_auth_phase_two_payload_with_context_with_seq(
110 user,
111 encrypted,
112 driver_name,
113 version_num,
114 connect_string,
115 seq_num,
116 &[],
117 )
118}
119
120pub fn build_auth_phase_two_payload_with_context_with_seq(
121 user: &str,
122 encrypted: &crate::crypto::EncryptedPassword,
123 driver_name: &str,
124 version_num: u32,
125 connect_string: &str,
126 seq_num: u8,
127 app_context: &[(String, String, String)],
128) -> Result<Vec<u8>> {
129 build_auth_phase_two_payload_with_proxy_with_seq(
130 user,
131 encrypted,
132 driver_name,
133 version_num,
134 connect_string,
135 seq_num,
136 app_context,
137 None,
138 None,
139 )
140}
141
142#[allow(clippy::too_many_arguments)]
146pub fn build_auth_phase_two_payload_with_proxy_with_seq(
147 user: &str,
148 encrypted: &crate::crypto::EncryptedPassword,
149 driver_name: &str,
150 version_num: u32,
151 connect_string: &str,
152 seq_num: u8,
153 app_context: &[(String, String, String)],
154 proxy_user: Option<&str>,
155 edition: Option<&str>,
156) -> Result<Vec<u8>> {
157 let mut writer = TtcWriter::new();
158 writer.write_function_code_with_seq(TNS_FUNC_AUTH_PHASE_TWO, seq_num);
159 writer.write_ub8(0);
160 let mut num_pairs = 6u32;
161 if encrypted.speedy_key.is_some() {
162 num_pairs += 1;
163 }
164 if proxy_user.is_some() {
165 num_pairs += 1;
166 }
167 if !connect_string.is_empty() {
168 num_pairs += 1;
169 }
170 if edition.is_some() {
171 num_pairs += 1;
172 }
173 let app_context_pairs =
174 app_context
175 .len()
176 .checked_mul(3)
177 .ok_or(ProtocolError::InvalidPacketLength {
178 length: app_context.len(),
179 minimum: 0,
180 })?;
181 num_pairs +=
182 u32::try_from(app_context_pairs).map_err(|_| ProtocolError::InvalidPacketLength {
183 length: app_context.len(),
184 minimum: 0,
185 })?;
186 write_auth_header(
187 &mut writer,
188 user,
189 TNS_AUTH_MODE_LOGON | TNS_AUTH_MODE_WITH_PASSWORD,
190 num_pairs,
191 )?;
192 if let Some(proxy_user) = proxy_user {
193 write_key_value(&mut writer, "PROXY_CLIENT_NAME", proxy_user, 0)?;
194 }
195 write_key_value(&mut writer, "AUTH_SESSKEY", &encrypted.session_key, 1)?;
196 if let Some(speedy_key) = &encrypted.speedy_key {
197 write_key_value(&mut writer, "AUTH_PBKDF2_SPEEDY_KEY", speedy_key, 0)?;
198 }
199 write_key_value(&mut writer, "AUTH_PASSWORD", &encrypted.password, 0)?;
200 write_key_value(&mut writer, "SESSION_CLIENT_CHARSET", "873", 0)?;
201 write_key_value(&mut writer, "SESSION_CLIENT_DRIVER_NAME", driver_name, 0)?;
202 write_key_value(
203 &mut writer,
204 "SESSION_CLIENT_VERSION",
205 &version_num.to_string(),
206 0,
207 )?;
208 write_key_value(
209 &mut writer,
210 "AUTH_ALTER_SESSION",
211 "ALTER SESSION SET TIME_ZONE='+00:00'\0",
212 1,
213 )?;
214 if let Some(edition) = edition {
218 write_key_value(&mut writer, "AUTH_ORA_EDITION", edition, 0)?;
219 }
220 for (namespace, name, value) in app_context {
221 write_key_value(&mut writer, "AUTH_APPCTX_NSPACE\0", namespace, 0)?;
222 write_key_value(&mut writer, "AUTH_APPCTX_ATTR\0", name, 0)?;
223 write_key_value(&mut writer, "AUTH_APPCTX_VALUE\0", value, 0)?;
224 }
225 if !connect_string.is_empty() {
226 write_key_value(&mut writer, "AUTH_CONNECT_STRING", connect_string, 0)?;
227 }
228 Ok(writer.into_bytes())
229}
230
231pub fn build_change_password_payload_with_seq(
236 user: &str,
237 encoded_password: &str,
238 encoded_newpassword: &str,
239 seq_num: u8,
240) -> Result<Vec<u8>> {
241 let mut writer = TtcWriter::new();
242 writer.write_function_code_with_seq(TNS_FUNC_AUTH_PHASE_TWO, seq_num);
243 writer.write_ub8(0);
244 write_auth_header(
245 &mut writer,
246 user,
247 TNS_AUTH_MODE_WITH_PASSWORD | TNS_AUTH_MODE_CHANGE_PASSWORD,
248 2,
249 )?;
250 write_key_value(&mut writer, "AUTH_PASSWORD", encoded_password, 0)?;
251 write_key_value(&mut writer, "AUTH_NEWPASSWORD", encoded_newpassword, 0)?;
252 Ok(writer.into_bytes())
253}
254
255pub fn parse_auth_response(payload: &[u8]) -> Result<AuthResponse> {
256 let mut reader = TtcReader::new(payload);
257 let mut response = AuthResponse::default();
258 while reader.remaining() > 0 {
259 let message_type = reader.read_u8()?;
260 match message_type {
261 TNS_MSG_TYPE_PROTOCOL => {
262 if let Some(capabilities) = skip_protocol_message(&mut reader)? {
263 response.capabilities = Some(capabilities);
264 }
265 }
266 TNS_MSG_TYPE_DATA_TYPES => skip_data_types_response(&mut reader)?,
267 TNS_MSG_TYPE_PARAMETER => {
268 let mut parsed = parse_return_parameters(&mut reader)?;
269 response.session_data.append(&mut parsed.session_data);
270 if parsed.verifier_type.is_some() {
271 response.verifier_type = parsed.verifier_type;
272 }
273 }
274 TNS_MSG_TYPE_STATUS => {
275 let _call_status = reader.read_ub4()?;
276 let _seq = reader.read_ub2()?;
277 }
278 TNS_MSG_TYPE_SERVER_SIDE_PIGGYBACK => {
279 let _ = skip_server_side_piggyback(&mut reader)?;
280 }
281 TNS_MSG_TYPE_END_OF_RESPONSE => break,
282 TNS_MSG_TYPE_ERROR => {
283 if let Some(message) = parse_server_error(&mut reader, 13)? {
284 return Err(ProtocolError::ServerError(message));
285 }
286 }
287 _ => {
288 return Err(ProtocolError::UnknownMessageType {
289 message_type,
290 position: reader.position().saturating_sub(1),
291 })
292 }
293 }
294 }
295 Ok(response)
296}
297
298pub(crate) fn write_auth_header(
299 writer: &mut TtcWriter,
300 user: &str,
301 auth_mode: u32,
302 num_pairs: u32,
303) -> Result<()> {
304 let user_bytes = user.as_bytes();
305 writer.write_u8(u8::from(!user_bytes.is_empty()));
306 writer.write_ub4(u32::try_from(user_bytes.len()).map_err(|_| {
307 ProtocolError::InvalidPacketLength {
308 length: user_bytes.len(),
309 minimum: 0,
310 }
311 })?);
312 writer.write_ub4(auth_mode);
313 writer.write_u8(1);
314 writer.write_ub4(num_pairs);
315 writer.write_u8(1);
316 writer.write_u8(1);
317 if !user_bytes.is_empty() {
318 writer.write_bytes_with_length(user_bytes)?;
319 }
320 Ok(())
321}
322
323pub(crate) fn write_key_value(
324 writer: &mut TtcWriter,
325 key: &str,
326 value: &str,
327 flags: u32,
328) -> Result<()> {
329 writer.write_str_two_lengths(key)?;
330 writer.write_str_two_lengths(value)?;
331 writer.write_ub4(flags);
332 Ok(())
333}
334
335pub(crate) fn parse_return_parameters(reader: &mut TtcReader<'_>) -> Result<AuthResponse> {
336 let num_params = reader.read_ub2()?;
337 let mut response = AuthResponse::default();
338 for _ in 0..num_params {
339 let key = reader
340 .read_string_with_length()?
341 .ok_or(ProtocolError::TtcDecode("missing auth response key"))?;
342 let value = reader.read_string_with_length()?.unwrap_or_default();
343 if key == "AUTH_VFR_DATA" {
344 response.verifier_type = Some(reader.read_ub4()?);
345 } else {
346 let _flags = reader.read_ub4()?;
347 }
348 response.session_data.insert(key, value);
349 }
350 Ok(response)
351}
352
353#[cfg(test)]
354mod token_auth_tests {
355 use super::*;
356
357 fn read_ub4(bytes: &[u8], pos: &mut usize) -> u32 {
359 let len = bytes[*pos] as usize;
360 *pos += 1;
361 let mut value = 0u32;
362 for _ in 0..len {
363 value = (value << 8) | u32::from(bytes[*pos]);
364 *pos += 1;
365 }
366 value
367 }
368
369 fn contains(haystack: &[u8], needle: &[u8]) -> bool {
370 haystack.windows(needle.len()).any(|w| w == needle)
371 }
372
373 #[test]
378 fn token_message_carries_auth_token_not_password() {
379 let mut out = Vec::new();
380 append_auth_phase_two_token(
381 &mut out,
382 "scott",
383 "HEADER.PAYLOAD.SIG",
384 "drv",
385 300_000_000,
386 "cs",
387 None,
388 )
389 .unwrap();
390
391 assert_eq!(out[0], TNS_MSG_TYPE_FUNCTION);
393 assert_eq!(out[1], TNS_FUNC_AUTH_PHASE_TWO);
394 assert_eq!(out[3], 1, "user is present");
396 let mut pos = 4;
397 assert_eq!(read_ub4(&out, &mut pos), 5, "user length = len(\"scott\")");
398 assert_eq!(
399 read_ub4(&out, &mut pos),
400 TNS_AUTH_MODE_LOGON,
401 "token auth uses LOGON only — never the WITH_PASSWORD bit"
402 );
403 assert_eq!(out[pos], 1); pos += 1;
405 assert_eq!(
406 read_ub4(&out, &mut pos),
407 6,
408 "AUTH_TOKEN + 4 session pairs + AUTH_CONNECT_STRING"
409 );
410
411 assert!(contains(&out, b"AUTH_TOKEN"));
412 assert!(
413 contains(&out, b"HEADER.PAYLOAD.SIG"),
414 "the token value is sent"
415 );
416 assert!(contains(&out, b"AUTH_CONNECT_STRING"));
417 assert!(
418 !contains(&out, b"AUTH_PASSWORD") && !contains(&out, b"AUTH_SESSKEY"),
419 "token auth must not send any password material"
420 );
421 }
422
423 #[test]
426 fn token_message_pair_count_without_connect_string() {
427 let mut out = Vec::new();
428 append_auth_phase_two_token(&mut out, "u", "tok", "drv", 1, "", None).unwrap();
429 let mut pos = 4;
430 let _user_len = read_ub4(&out, &mut pos);
431 let _auth_mode = read_ub4(&out, &mut pos);
432 pos += 1; assert_eq!(read_ub4(&out, &mut pos), 5, "AUTH_TOKEN + 4 session pairs");
434 assert!(!contains(&out, b"AUTH_CONNECT_STRING"));
435 }
436
437 #[test]
441 fn token_message_carries_edition() {
442 let mut out = Vec::new();
443 append_auth_phase_two_token(&mut out, "u", "tok", "drv", 1, "", Some("E_TEST")).unwrap();
444 let mut pos = 4;
445 let _user_len = read_ub4(&out, &mut pos);
446 let _auth_mode = read_ub4(&out, &mut pos);
447 pos += 1; assert_eq!(
449 read_ub4(&out, &mut pos),
450 6,
451 "AUTH_TOKEN + 4 session pairs + AUTH_ORA_EDITION"
452 );
453 assert!(contains(&out, b"AUTH_ORA_EDITION"));
454 assert!(contains(&out, b"E_TEST"), "the edition value is sent");
455
456 let mut out2 = Vec::new();
458 append_auth_phase_two_token(&mut out2, "u", "tok", "drv", 1, "cs", Some("E_TEST")).unwrap();
459 let mut p = 4;
460 let _ = read_ub4(&out2, &mut p);
461 let _ = read_ub4(&out2, &mut p);
462 p += 1;
463 assert_eq!(read_ub4(&out2, &mut p), 7, "+ AUTH_CONNECT_STRING");
464 }
465}