Safe outlk_autodiscover

This commit is contained in:
Alexander Krotov
2019-10-06 03:22:11 +03:00
parent 0252969f7e
commit b4851187ba
2 changed files with 92 additions and 154 deletions

View File

@@ -1,55 +1,42 @@
use std::ptr;
use libc::free;
use quick_xml; use quick_xml;
use quick_xml::events::{BytesEnd, BytesStart, BytesText}; use quick_xml::events::BytesEnd;
use crate::constants::*; use crate::constants::*;
use crate::context::Context; use crate::context::Context;
use crate::dc_tools::*;
use crate::login_param::LoginParam; use crate::login_param::LoginParam;
use super::read_autoconf_file; use super::read_autoconf_file;
/* ******************************************************************************
* Outlook's Autodiscover /// Outlook's Autodiscover
******************************************************************************/ struct OutlookAutodiscover {
#[repr(C)]
struct outlk_autodiscover_t {
pub out: LoginParam, pub out: LoginParam,
pub out_imap_set: libc::c_int, pub out_imap_set: bool,
pub out_smtp_set: libc::c_int, pub out_smtp_set: bool,
pub tag_config: libc::c_int, pub config_type: Option<String>,
pub config: [*mut libc::c_char; 6], pub config_server: String,
pub config_port: i32,
pub config_ssl: String,
pub config_redirecturl: Option<String>,
} }
pub unsafe fn outlk_autodiscover( pub fn outlk_autodiscover(
context: &Context, context: &Context,
url__: &str, url: &str,
_param_in: &LoginParam, _param_in: &LoginParam,
) -> Option<LoginParam> { ) -> Option<LoginParam> {
let mut url = url__.to_string(); let mut url = url.to_string();
let mut outlk_ad = outlk_autodiscover_t { /* Follow up to 10 xml-redirects (http-redirects are followed in read_autoconf_file() */
out: LoginParam::new(), for _i in 0..10 {
out_imap_set: 0, let mut outlk_ad = OutlookAutodiscover {
out_smtp_set: 0, out: LoginParam::new(),
tag_config: 0, out_imap_set: false,
config: [ptr::null_mut(); 6], out_smtp_set: false,
}; config_type: None,
let mut out_null = true; config_server: String::new(),
let ok_to_continue; config_port: 0,
let mut i = 0; config_ssl: String::new(),
loop { config_redirecturl: None,
/* Follow up to 10 xml-redirects (http-redirects are followed in read_autoconf_file() */ };
if i >= 10 {
ok_to_continue = true;
break;
}
libc::memset(
&mut outlk_ad as *mut outlk_autodiscover_t as *mut libc::c_void,
0,
::std::mem::size_of::<outlk_autodiscover_t>(),
);
if let Some(xml_raw) = read_autoconf_file(context, &url) { if let Some(xml_raw) = read_autoconf_file(context, &url) {
let mut reader = quick_xml::Reader::from_str(&xml_raw); let mut reader = quick_xml::Reader::from_str(&xml_raw);
@@ -57,16 +44,46 @@ pub unsafe fn outlk_autodiscover(
let mut buf = Vec::new(); let mut buf = Vec::new();
let mut current_tag: Option<String> = None;
loop { loop {
match reader.read_event(&mut buf) { match reader.read_event(&mut buf) {
Ok(quick_xml::events::Event::Start(ref e)) => { Ok(quick_xml::events::Event::Start(ref e)) => {
outlk_autodiscover_starttag_cb(e, &mut outlk_ad) let tag = String::from_utf8_lossy(e.name()).trim().to_lowercase();
if tag == "protocol" {
outlk_ad.config_type = None;
outlk_ad.config_server = String::new();
outlk_ad.config_port = 0;
outlk_ad.config_ssl = String::new();
outlk_ad.config_redirecturl = None;
current_tag = None;
} else {
current_tag = Some(tag);
}
} }
Ok(quick_xml::events::Event::End(ref e)) => { Ok(quick_xml::events::Event::End(ref e)) => {
outlk_autodiscover_endtag_cb(e, &mut outlk_ad) outlk_autodiscover_endtag_cb(e, &mut outlk_ad);
current_tag = None;
} }
Ok(quick_xml::events::Event::Text(ref e)) => { Ok(quick_xml::events::Event::Text(ref e)) => {
outlk_autodiscover_text_cb(e, &mut outlk_ad, &reader) let val = e.unescape_and_decode(&reader).unwrap_or_default();
if let Some(ref tag) = current_tag {
match tag.as_str() {
"type" => outlk_ad.config_type = Some(val.trim().to_string()),
"server" => outlk_ad.config_server = val.trim().to_string(),
"port" => {
outlk_ad.config_port = val.trim().parse().unwrap_or_default()
}
"ssl" => outlk_ad.config_ssl = val.trim().to_string(),
"redirecturl" => {
outlk_ad.config_redirecturl = Some(val.trim().to_string())
}
_ => {}
};
}
} }
Err(e) => { Err(e) => {
error!( error!(
@@ -83,129 +100,58 @@ pub unsafe fn outlk_autodiscover(
} }
// XML redirect via redirecturl // XML redirect via redirecturl
if !(!outlk_ad.config[5].is_null() if outlk_ad.config_redirecturl.is_none()
&& 0 != *outlk_ad.config[5usize].offset(0isize) as libc::c_int) || outlk_ad.config_redirecturl.as_ref().unwrap().is_empty()
{ {
out_null = false; if outlk_ad.out.mail_server.is_empty()
ok_to_continue = true; || outlk_ad.out.mail_port == 0
break; || outlk_ad.out.send_server.is_empty()
|| outlk_ad.out.send_port == 0
{
let r = outlk_ad.out.to_string();
warn!(context, "Bad or incomplete autoconfig: {}", r,);
return None;
}
return Some(outlk_ad.out);
} else {
url = outlk_ad.config_redirecturl.unwrap();
} }
url = as_str(outlk_ad.config[5usize]).to_string();
outlk_clean_config(&mut outlk_ad);
i += 1;
} else { } else {
ok_to_continue = false;
break;
}
}
if ok_to_continue {
if outlk_ad.out.mail_server.is_empty()
|| outlk_ad.out.mail_port == 0
|| outlk_ad.out.send_server.is_empty()
|| outlk_ad.out.send_port == 0
{
let r = outlk_ad.out.to_string();
warn!(context, "Bad or incomplete autoconfig: {}", r,);
outlk_clean_config(&mut outlk_ad);
return None; return None;
} }
} }
outlk_clean_config(&mut outlk_ad); None
if out_null {
None
} else {
Some(outlk_ad.out)
}
} }
unsafe fn outlk_clean_config(mut outlk_ad: *mut outlk_autodiscover_t) { fn outlk_autodiscover_endtag_cb(event: &BytesEnd, outlk_ad: &mut OutlookAutodiscover) {
for i in 0..6 {
free((*outlk_ad).config[i] as *mut libc::c_void);
(*outlk_ad).config[i] = ptr::null_mut();
}
}
fn outlk_autodiscover_text_cb<B: std::io::BufRead>(
event: &BytesText,
outlk_ad: &mut outlk_autodiscover_t,
reader: &quick_xml::Reader<B>,
) {
let val = event.unescape_and_decode(reader).unwrap_or_default();
unsafe {
free(outlk_ad.config[outlk_ad.tag_config as usize].cast());
outlk_ad.config[outlk_ad.tag_config as usize] = val.trim().strdup();
}
}
unsafe fn outlk_autodiscover_endtag_cb(event: &BytesEnd, outlk_ad: &mut outlk_autodiscover_t) {
let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase(); let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase();
if tag == "protocol" { if tag == "protocol" {
if !outlk_ad.config[1].is_null() { if let Some(type_) = &outlk_ad.config_type {
let port = dc_atoi_null_is_0(outlk_ad.config[3]); let port = outlk_ad.config_port;
let ssl_on = (!outlk_ad.config[4].is_null() let ssl_on = outlk_ad.config_ssl == "on";
&& strcasecmp( let ssl_off = outlk_ad.config_ssl == "off";
outlk_ad.config[4], if type_ == "imap" && !outlk_ad.out_imap_set {
b"on\x00" as *const u8 as *const libc::c_char, outlk_ad.out.mail_server =
) == 0) as libc::c_int; std::mem::replace(&mut outlk_ad.config_server, String::new());
let ssl_off = (!outlk_ad.config[4].is_null()
&& strcasecmp(
outlk_ad.config[4],
b"off\x00" as *const u8 as *const libc::c_char,
) == 0) as libc::c_int;
if strcasecmp(
outlk_ad.config[1],
b"imap\x00" as *const u8 as *const libc::c_char,
) == 0
&& outlk_ad.out_imap_set == 0
{
outlk_ad.out.mail_server = to_string_lossy(outlk_ad.config[2]);
outlk_ad.out.mail_port = port; outlk_ad.out.mail_port = port;
if 0 != ssl_on { if ssl_on {
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32 outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32
} else if 0 != ssl_off { } else if ssl_off {
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_PLAIN as i32 outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_PLAIN as i32
} }
outlk_ad.out_imap_set = 1 outlk_ad.out_imap_set = true
} else if strcasecmp( } else if type_ == "smtp" && !outlk_ad.out_smtp_set {
outlk_ad.config[1usize], outlk_ad.out.send_server =
b"smtp\x00" as *const u8 as *const libc::c_char, std::mem::replace(&mut outlk_ad.config_server, String::new());
) == 0 outlk_ad.out.send_port = outlk_ad.config_port;
&& outlk_ad.out_smtp_set == 0 if ssl_on {
{
outlk_ad.out.send_server = to_string_lossy(outlk_ad.config[2]);
outlk_ad.out.send_port = port;
if 0 != ssl_on {
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32 outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32
} else if 0 != ssl_off { } else if ssl_off {
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_PLAIN as i32 outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_PLAIN as i32
} }
outlk_ad.out_smtp_set = 1 outlk_ad.out_smtp_set = true
} }
} }
outlk_clean_config(outlk_ad);
} }
outlk_ad.tag_config = 0;
}
fn outlk_autodiscover_starttag_cb(event: &BytesStart, outlk_ad: &mut outlk_autodiscover_t) {
let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase();
if tag == "protocol" {
unsafe { outlk_clean_config(outlk_ad) };
} else if tag == "type" {
outlk_ad.tag_config = 1
} else if tag == "server" {
outlk_ad.tag_config = 2
} else if tag == "port" {
outlk_ad.tag_config = 3
} else if tag == "ssl" {
outlk_ad.tag_config = 4
} else if tag == "redirecturl" {
outlk_ad.tag_config = 5
};
} }

View File

@@ -51,14 +51,6 @@ pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
ret ret
} }
pub(crate) fn dc_atoi_null_is_0(s: *const libc::c_char) -> libc::c_int {
if !s.is_null() {
as_str(s).parse().unwrap_or_default()
} else {
0
}
}
unsafe fn dc_ltrim(buf: *mut libc::c_char) { unsafe fn dc_ltrim(buf: *mut libc::c_char) {
let mut len: libc::size_t; let mut len: libc::size_t;
let mut cur: *const libc::c_uchar; let mut cur: *const libc::c_uchar;