feat(auth): finish protocol 10 method 2 and 3

This commit is contained in:
DJMrTV 2025-02-02 20:25:22 +01:00
commit d18ba43aed
24 changed files with 490 additions and 43 deletions

View file

@ -1,17 +1,18 @@
use std::io::Cursor;
use log::error;
use crate::nex::account::Account;
use crate::protocols::auth::method_login_ex::login_ex;
use crate::protocols::auth::AuthProtocolConfig;
use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult};
use crate::rmc::structures::any::Any;
use crate::rmc::structures::RmcSerialize;
pub async fn login(rmcmessage: &RMCMessage, name: &str) -> RMCResponseResult{
pub async fn login(rmcmessage: &RMCMessage, _name: &str) -> RMCResponseResult{
rmcmessage.error_result_with_code(ErrorCode::Core_NotImplemented)
}
pub async fn login_raw_params(rmcmessage: &RMCMessage, data: (&Account)) -> RMCResponseResult{
pub async fn login_raw_params(rmcmessage: &RMCMessage, data: AuthProtocolConfig) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(str) = String::deserialize(&mut reader) else {

View file

@ -1,13 +1,20 @@
use std::io::Cursor;
use log::{error, info};
use std::io::{Cursor, Write};
use bytemuck::bytes_of;
use hex::encode;
use log::{error};
use crate::grpc::account;
use crate::kerberos::KerberosDateTime;
use crate::nex::account::Account;
use crate::protocols::auth::AuthProtocolConfig;
use crate::protocols::auth::ticket_generation::generate_ticket;
use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult};
use crate::rmc::structures::{RmcSerialize};
use crate::rmc::structures::any::Any;
use crate::rmc::structures::connection_data::ConnectionData;
use crate::rmc::structures::qresult::QResult;
pub async fn login_ex(rmcmessage: &RMCMessage, secure_server_account: &Account , pid: u32) -> RMCResponseResult{
pub async fn login_ex(rmcmessage: &RMCMessage, proto_data: AuthProtocolConfig, pid: u32) -> RMCResponseResult{
// todo: figure out how the AuthenticationInfo struct works, parse it and validate login info
let Ok(mut client) = account::Client::new().await else {
@ -18,15 +25,35 @@ pub async fn login_ex(rmcmessage: &RMCMessage, secure_server_account: &Account ,
return rmcmessage.error_result_with_code(ErrorCode::Core_Exception);
};
let source_login_data = (pid, passwd);
let destination_login_data = proto_data.secure_server_account.get_login_data();
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
let ticket = generate_ticket(source_login_data, destination_login_data);
let result = QResult::success(ErrorCode::Core_Unknown);
let connection_data = ConnectionData{
station_url: proto_data.station_url,
special_station_url: "",
date_time: KerberosDateTime::now(),
special_protocols: Vec::new()
};
let mut response: Vec<u8> = Vec::new();
result.serialize(&mut response).expect("failed serializing result");
response.write_all(bytes_of(&source_login_data.0)).expect("failed writing pid");
ticket.serialize(&mut response).expect("failed serializing ticket");
connection_data.serialize(&mut response).expect("failed writing connection data");
proto_data.build_name.serialize(&mut response).expect("failed writing build name");
return rmcmessage.success_with_data(response);
}
pub async fn login_ex_raw_params(rmcmessage: &RMCMessage, (secure_server_account): (&Account)) -> RMCResponseResult{
pub async fn login_ex_raw_params(rmcmessage: &RMCMessage, data: AuthProtocolConfig) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(_str) = String::deserialize(&mut reader) else {
let Ok(str) = String::deserialize(&mut reader) else {
error!("error reading packet");
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
};
@ -50,5 +77,5 @@ pub async fn login_ex_raw_params(rmcmessage: &RMCMessage, (secure_server_account
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
};
login_ex(rmcmessage, secure_server_account, pid).await
login_ex(rmcmessage, data, pid).await
}

View file

@ -0,0 +1,53 @@
use std::io::Cursor;
use log::error;
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
use crate::grpc::account;
use crate::protocols::auth::{AuthProtocolConfig, get_login_data_by_pid};
use crate::protocols::auth::method_login_ex::login_ex;
use crate::protocols::auth::ticket_generation::generate_ticket;
use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult};
use crate::rmc::response::ErrorCode::Core_Unknown;
use crate::rmc::structures::any::Any;
use crate::rmc::structures::qresult::QResult;
use crate::rmc::structures::RmcSerialize;
pub async fn request_ticket(rmcmessage: &RMCMessage, data: AuthProtocolConfig, source_pid: u32, destination_pid: u32) -> RMCResponseResult{
let Some(source_login_data) = get_login_data_by_pid(source_pid).await else {
return rmcmessage.error_result_with_code(ErrorCode::Core_Exception);
};
let desgination_login_data = if destination_pid == data.secure_server_account.pid{
data.secure_server_account.get_login_data()
} else {
let Some(login) = get_login_data_by_pid(destination_pid).await else {
return rmcmessage.error_result_with_code(ErrorCode::Core_Exception);
};
login
};
let result = QResult::success(Core_Unknown);
let ticket = generate_ticket(source_login_data, desgination_login_data);
let mut response: Vec<u8> = Vec::new();
result.serialize(&mut response).expect("failed serializing result");
ticket.serialize(&mut response).expect("failed serializing ticket");
rmcmessage.success_with_data(response)
}
pub async fn request_ticket_raw_params(rmcmessage: &RMCMessage, data: AuthProtocolConfig) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(source_pid) = reader.read_struct(IS_BIG_ENDIAN) else {
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
};
let Ok(destination_pid) = reader.read_struct(IS_BIG_ENDIAN) else {
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
};
request_ticket(rmcmessage, data, source_pid, destination_pid).await
}

View file

@ -1,18 +1,42 @@
mod method_login_ex;
mod method_login;
mod ticket_generation;
mod method_request_ticket;
use std::sync::Arc;
use log::{error};
use crate::define_protocol;
use crate::grpc::account;
use crate::nex::account::Account;
use crate::protocols::auth::method_login::login_raw_params;
use crate::protocols::auth::method_login_ex::{login_ex, login_ex_raw_params};
use crate::protocols::auth::method_login_ex::login_ex_raw_params;
use crate::protocols::auth::method_request_ticket::request_ticket_raw_params;
use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponse};
#[derive(Copy, Clone)]
pub struct AuthProtocolConfig {
pub secure_server_account: &'static Account,
pub build_name: &'static str,
pub station_url: &'static str
}
define_protocol!{
10(secure_server_account: &'static Account) => {
10(proto_data: AuthProtocolConfig) => {
0x01 => login_raw_params,
0x02 => login_ex_raw_params
0x02 => login_ex_raw_params,
0x03 => request_ticket_raw_params
}
}
async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> {
let Ok(mut client) = account::Client::new().await else {
return None
};
let Ok(passwd) = client.get_nex_password(pid).await else{
return None
};
Some((pid, passwd))
}

View file

@ -0,0 +1,19 @@
use crate::kerberos;
use crate::kerberos::{derive_key, Ticket};
pub fn generate_ticket(source_act_login_data: (u32, [u8;16]), dest_act_login_data: (u32, [u8;16])) -> Box<[u8]>{
let source_key = derive_key(source_act_login_data.0, source_act_login_data.1);
let dest_key = derive_key(dest_act_login_data.0, dest_act_login_data.1);
let internal_data = kerberos::TicketInternalData::new(source_act_login_data.0);
let encrypted_inner = internal_data.encrypt(dest_key);
let encrypted_session_ticket = Ticket{
pid: dest_act_login_data.0,
session_key: internal_data.session_key,
}.encrypt(source_key, &encrypted_inner);
encrypted_session_ticket
}

View file

@ -3,6 +3,7 @@ pub mod server;
#[macro_export]
macro_rules! define_protocol {
($id:literal ($($varname:ident : $ty:ty),*) => {$($func_id:literal => $func:path),*} ) => {
#[allow(unused_parens)]
async fn protocol (rmcmessage: &RMCMessage, $($varname : $ty),*) -> Option<RMCResponse>{
if rmcmessage.protocol_id != $id{
return None;
@ -30,7 +31,7 @@ macro_rules! define_protocol {
response_result
})
}
#[allow(unused_parens)]
pub fn bound_protocol($($varname : $ty,)*) -> Box<dyn for<'message_lifetime> Fn(&'message_lifetime RMCMessage) -> ::std::pin::Pin<Box<dyn ::std::future::Future<Output = Option<RMCResponse>> + Send + 'message_lifetime>> + Send + Sync>{
Box::new(
move |v| {