From 5d5d1dbf688fd449c430254a85a4086e75cf7758 Mon Sep 17 00:00:00 2001 From: moznion Date: Wed, 25 Nov 2020 01:04:05 +0900 Subject: [PATCH] Support to generate user-password attribute --- Makefile | 1 + src/bin/code_gen.rs | 58 +++++++++++++++++++++++++++++++++++++++------ src/packet.rs | 5 +++- src/rfc2865.rs | 6 +++-- 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 993e50c..02abed5 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ gen: + cat /dev/null > $(PWD)/src/rfc2865.rs cargo run --bin code_gen $(PWD)/dicts/dictionary.rfc2865 $(PWD)/src/rfc2865.rs cargo fmt diff --git a/src/bin/code_gen.rs b/src/bin/code_gen.rs index dfcf7cc..b05d7fe 100644 --- a/src/bin/code_gen.rs +++ b/src/bin/code_gen.rs @@ -26,9 +26,10 @@ struct RadiusValue { typ: u16, } -#[derive(Debug)] +#[derive(Debug, PartialEq)] enum RadiusAttributeValueType { STRING, + USER_PASSWORD, OCTETS, IPADDR, INTEGER, @@ -40,6 +41,7 @@ impl FromStr for RadiusAttributeValueType { fn from_str(s: &str) -> Result { match s.to_uppercase().as_str() { "STRING" => Ok(RadiusAttributeValueType::STRING), + "USER_PASSWORD" => Ok(RadiusAttributeValueType::USER_PASSWORD), "OCTETS" => Ok(RadiusAttributeValueType::OCTETS), "IPADDR" => Ok(RadiusAttributeValueType::IPADDR), "INTEGER" => Ok(RadiusAttributeValueType::INTEGER), @@ -120,6 +122,7 @@ fn generate_attributes_code(w: &mut BufWriter, attrs: &[RadiusAttribute]) fn generate_attribute_code(w: &mut BufWriter, attr: &RadiusAttribute) { match attr.value_type { RadiusAttributeValueType::STRING => generate_string_attribute_code(w, attr), + RadiusAttributeValueType::USER_PASSWORD => generate_user_password_attribute_code(w, attr), RadiusAttributeValueType::OCTETS => generate_octets_attribute_code(w, attr), RadiusAttributeValueType::IPADDR => generate_ipaddr_attribute_code(w, attr), RadiusAttributeValueType::INTEGER => generate_integer_attribute_code(w, attr), @@ -159,6 +162,39 @@ pub fn lookup_all_{method_identifier}(packet: &Packet) -> Vec<&Attribute> {{ w.write_all(code.as_bytes()).unwrap(); } +fn generate_user_password_attribute_code(w: &mut BufWriter, attr: &RadiusAttribute) { + let attr_name = attr.name.clone(); + + let type_identifier = format!("{}_TYPE", attr_name.to_screaming_snake_case()); + let type_calling = format!("Self::{}", type_identifier); + + let code = format!( + "pub const {type_identifier}: AVPType = {type_value}; +pub fn add_{method_identifier}(packet: &mut Packet, value: &[u8]) -> Result<(), String> {{ + let attr = Attribute::from_user_password(value, packet.get_secret(), packet.get_authenticator())?; + packet.add({type_calling}, &attr); + Ok(()) +}} +pub fn delete_{method_identifier}(packet: &mut Packet) {{ + packet.delete({type_calling}); +}} +pub fn lookup_{method_identifier}(packet: &Packet) -> Option<&Attribute> {{ + packet.lookup({type_calling}) +}} +pub fn lookup_all_{method_identifier}(packet: &Packet) -> Vec<&Attribute> {{ + packet.lookup_all({type_calling}) +}} + +", + method_identifier = attr_name.to_snake_case(), + type_identifier = type_identifier, + type_calling = type_calling, + type_value = attr.typ, + ); + + w.write_all(code.as_bytes()).unwrap(); +} + fn generate_octets_attribute_code(w: &mut BufWriter, attr: &RadiusAttribute) {} fn generate_ipaddr_attribute_code(w: &mut BufWriter, attr: &RadiusAttribute) {} @@ -194,19 +230,27 @@ fn parse_dict_file(dict_file_path: &Path) -> Result { match kind { ATTRIBUTE_KIND => { let type_descriptions = items[3].split(' ').collect::>(); + + let is_encrypt = if type_descriptions.len() >= 2 { + type_descriptions[1] == "encrypt=1" // FIXME: ad-hoc!!! + } else { + false + }; + let typ = match RadiusAttributeValueType::from_str(type_descriptions[0]) { - Ok(t) => t, + Ok(t) => { + if t == RadiusAttributeValueType::STRING && is_encrypt { + RadiusAttributeValueType::USER_PASSWORD + } else { + t + } + } Err(_) => { return Err( format!("invalid type has come => {}", type_descriptions[0]).to_owned() ); } }; - let is_encrypt = if type_descriptions.len() >= 2 { - type_descriptions[1] == "encrypt=1" // FIXME: ad-hoc!!! - } else { - false - }; radius_attributes.push(RadiusAttribute { name: items[1].to_string(), diff --git a/src/packet.rs b/src/packet.rs index 44cdd9f..807168a 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -35,10 +35,13 @@ impl Packet { } pub fn get_secret(&self) -> &Vec { - // TODO &self.secret } + pub fn get_authenticator(&self) -> &Vec { + &self.get_authenticator() + } + pub fn parse(bs: &[u8], secret: &[u8]) -> Result { if bs.len() < 20 { return Err("radius packet doesn't have enough length of bytes; that has to be at least 20 bytes".to_owned()); diff --git a/src/rfc2865.rs b/src/rfc2865.rs index ab314c3..64985bc 100644 --- a/src/rfc2865.rs +++ b/src/rfc2865.rs @@ -22,9 +22,11 @@ impl RFC2865 { } pub const USER_PASSWORD_TYPE: AVPType = 2; - pub fn add_user_password(packet: &mut Packet, value: &str) { - let attr = Attribute::from_string(value); + pub fn add_user_password(packet: &mut Packet, value: &[u8]) -> Result<(), String> { + let attr = + Attribute::from_user_password(value, packet.get_secret(), packet.get_authenticator())?; packet.add(Self::USER_PASSWORD_TYPE, &attr); + Ok(()) } pub fn delete_user_password(packet: &mut Packet) { packet.delete(Self::USER_PASSWORD_TYPE);