Skip to content

Commit

Permalink
connection.rs: implement DBUS_COOKIE_SHA1 auth
Browse files Browse the repository at this point in the history
All transports will attempt the same authentication methods, first
EXTERNAL, then COOKIE, then ANONYMOUS.
  • Loading branch information
srwalter committed Jul 2, 2015
1 parent 350762e commit eec3595
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 9 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ unix_socket = "0.4.3"
rustc-serialize = "0.3"
libc = "0.1"
dbus-serialize = "0.1"
rand = "0.3"
rust-crypto = "0.2.31"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
[![Build Status](https://travis-ci.org/srwalter/dbus-bytestream.svg?branch=master)](https://travis-ci.org/srwalter/dbus-bytestream)

Rust-native implementation of the D-Bus wire protocol. Supports TCP and
UNIX socket transports, as well as EXTERNAL an ANONYMOUS authentication.
Uses dbus-serialize for the client facing D-Bus types.
UNIX socket transports, as well as EXTERNAL, COOKIE and ANONYMOUS
authentication. Uses dbus-serialize for the client facing D-Bus types.
125 changes: 118 additions & 7 deletions src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,26 @@
//! let reply = conn.call_sync(&mut msg);
//! println!("{:?}", reply);
//! ```
//!
use std::env;
use std::net::{TcpStream,ToSocketAddrs};
use std::io;
use std::io::{Read,Write};
use std::fs::File;
use std::ops::Deref;
use std::path::Path;
use std::str::FromStr;
use std::string;
use std::num::ParseIntError;
use rand::Rand;
use rand;
use libc;
use crypto::digest::Digest;
use crypto;

use unix_socket::UnixStream;
use rustc_serialize::hex::ToHex;
use rustc_serialize::hex::{ToHex,FromHex,FromHexError};
use dbus_serialize::types::Value;
use dbus_serialize::decoder::DBusDecoder;

Expand Down Expand Up @@ -81,6 +89,24 @@ impl From<address::ServerAddressError> for Error {
}
}

impl From<FromHexError> for Error {
fn from(_x: FromHexError) -> Self {
Error::AuthFailed
}
}

impl From<string::FromUtf8Error> for Error {
fn from(_x: string::FromUtf8Error) -> Self {
Error::AuthFailed
}
}

impl From<ParseIntError> for Error {
fn from(_x: ParseIntError) -> Self {
Error::AuthFailed
}
}

fn read_exactly(sock: &mut StreamSocket, buf: &mut Vec<u8>, len: usize) -> Result<(),Error> {
buf.truncate(0);
buf.reserve(len);
Expand Down Expand Up @@ -110,6 +136,30 @@ fn read_line(sock: &mut StreamSocket) -> Result<String,Error> {
Ok(line)
}

fn get_cookie(context: &str, cookie_id: &str) -> Result<String,Error> {
let hd = match env::home_dir() {
Some(x) => x,
None => return Err(Error::AuthFailed)
};
let filename = hd.join(".dbus-keyrings").join(context);
let mut f = try!(File::open(filename));
let mut contents = String::new();
try!(f.read_to_string(&mut contents));
let lines : Vec<&str> = contents.split('\n').collect();
for line in lines {
if !line.starts_with(cookie_id) {
continue;
}
let words : Vec<&str> = line.split(' ').collect();
if words.len() != 3 {
break;
}
return Ok(words[2].to_string());
}

Err(Error::AuthFailed)
}

impl Connection {
fn get_sock(&mut self) -> &mut StreamSocket {
match self.sock {
Expand Down Expand Up @@ -164,6 +214,71 @@ impl Connection {
Ok(())
}

fn auth_cookie(&mut self) -> Result<(),Error> {
let sock = self.get_sock();

let uid = unsafe {
libc::funcs::posix88::unistd::getuid()
};
let uid_str = uid.to_string();
let uid_hex = uid_str.into_bytes().to_hex();
let cmd = "AUTH DBUS_COOKIE_SHA1 ".to_string() + &uid_hex + "\r\n";
try!(sock.write_all(&cmd.into_bytes()));

// Read response
let resp = try!(read_line(sock));
let words : Vec<&str> = resp.split(' ').collect();
if words.len() != 2 {
return Err(Error::AuthFailed);
}
if words[0] != "DATA" {
return Err(Error::AuthFailed);
}

let bytes = try!(words[1].from_hex());
let challenge = try!(String::from_utf8(bytes));
let words : Vec<&str> = challenge.split(' ').collect();
if words.len() != 3 {
return Err(Error::AuthFailed);
}

let cookie = try!(get_cookie(words[0], words[1]));

let mut my_challenge = Vec::new();
for _ in 0..16 {
my_challenge.push(u8::rand(&mut rand::thread_rng()));
}
let hex_challenge = my_challenge.to_hex();

let my_cookie = words[2].to_string() + ":" + &hex_challenge + ":" + &cookie;
let mut hasher = crypto::sha1::Sha1::new();
hasher.input_str(&my_cookie);
let hash = hasher.result_str();

let my_resp = hex_challenge + " " + &hash;
let hex_resp = my_resp.into_bytes().to_hex();
let buf = "DATA ".to_string() + &hex_resp + "\r\n";
try!(sock.write_all(&buf.into_bytes()));

// Read response
let resp = try!(read_line(sock));
if !resp.starts_with("OK ") {
return Err(Error::AuthFailed);
}

// Ready for action
try!(sock.write_all(b"BEGIN\r\n"));
Ok(())
}

fn authenticate(&mut self) -> Result<(),Error> {
try!(self.send_nul_byte());
try!(self.auth_external()
.or_else(|_x| { self.auth_cookie() })
.or_else(|_x| { self.auth_anonymous() }));
self.say_hello()
}

fn say_hello(&mut self) -> Result<(),Error> {
let mut msg = message::create_method_call("org.freedesktop.DBus",
"/org/freedesktop/DBus",
Expand Down Expand Up @@ -220,9 +335,7 @@ impl Connection {
next_serial: 1
};

try!(conn.send_nul_byte());
try!(conn.auth_external());
try!(conn.say_hello());
try!(conn.authenticate());
Ok(conn)
}

Expand All @@ -236,9 +349,7 @@ impl Connection {
next_serial: 1
};

try!(conn.send_nul_byte());
try!(conn.auth_anonymous());
try!(conn.say_hello());
try!(conn.authenticate());
Ok(conn)
}

Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ extern crate dbus_serialize;
extern crate rustc_serialize;
extern crate unix_socket;
extern crate libc;
extern crate rand;
extern crate crypto;

pub mod demarshal;
pub mod marshal;
Expand Down

0 comments on commit eec3595

Please sign in to comment.