1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::ffi::CString;
use std::marker;
use std::slice;
use std::str;

use {raw, Session, Error};
use util::{Binding, SessionBinding};

/// A structure representing a connection to an SSH agent.
///
/// Agents can be used to authenticate a session.
pub struct Agent<'sess> {
    raw: *mut raw::LIBSSH2_AGENT,
    sess: &'sess Session,
}

/// An iterator over the identities found in an SSH agent.
pub struct Identities<'agent> {
    prev: *mut raw::libssh2_agent_publickey,
    agent: &'agent Agent<'agent>,
}

/// A public key which is extracted from an SSH agent.
pub struct PublicKey<'agent> {
    raw: *mut raw::libssh2_agent_publickey,
    _marker: marker::PhantomData<&'agent [u8]>,
}

impl<'sess> Agent<'sess> {
    /// Connect to an ssh-agent running on the system.
    pub fn connect(&mut self) -> Result<(), Error> {
        unsafe { self.sess.rc(raw::libssh2_agent_connect(self.raw)) }
    }

    /// Close a connection to an ssh-agent.
    pub fn disconnect(&mut self) -> Result<(), Error> {
        unsafe { self.sess.rc(raw::libssh2_agent_disconnect(self.raw)) }
    }

    /// Request an ssh-agent to list of public keys, and stores them in the
    /// internal collection of the handle.
    ///
    /// Call `identities` to get the public keys.
    pub fn list_identities(&mut self) -> Result<(), Error> {
        unsafe { self.sess.rc(raw::libssh2_agent_list_identities(self.raw)) }
    }

    /// Get an iterator over the identities of this agent.
    pub fn identities(&self) -> Identities {
        Identities { prev: 0 as *mut _, agent: self }
    }

    /// Attempt public key authentication with the help of ssh-agent.
    pub fn userauth(&self, username: &str, identity: &PublicKey)
                    -> Result<(), Error>{
        let username = try!(CString::new(username));
        unsafe {
            self.sess.rc(raw::libssh2_agent_userauth(self.raw,
                                                     username.as_ptr(),
                                                     identity.raw))

        }
    }
}

impl<'sess> SessionBinding<'sess> for Agent<'sess> {
    type Raw = raw::LIBSSH2_AGENT;

    unsafe fn from_raw(sess: &'sess Session,
                       raw: *mut raw::LIBSSH2_AGENT) -> Agent<'sess> {
        Agent { raw: raw, sess: sess }
    }
    fn raw(&self) -> *mut raw::LIBSSH2_AGENT { self.raw }
}

impl<'a> Drop for Agent<'a> {
    fn drop(&mut self) {
        unsafe { raw::libssh2_agent_free(self.raw) }
    }
}

impl<'agent> Iterator for Identities<'agent> {
    type Item = Result<PublicKey<'agent>, Error>;
    fn next(&mut self) -> Option<Result<PublicKey<'agent>, Error>> {
        unsafe {
            let mut next = 0 as *mut _;
            match raw::libssh2_agent_get_identity(self.agent.raw,
                                                  &mut next,
                                                  self.prev) {
                0 => { self.prev = next; Some(Ok(Binding::from_raw(next))) }
                1 => None,
                rc => Some(Err(self.agent.sess.rc(rc).err().unwrap())),
            }
        }
    }
}

impl<'agent> PublicKey<'agent> {
    /// Return the data of this public key.
    pub fn blob(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts_mut((*self.raw).blob,
                                      (*self.raw).blob_len as usize)
        }
    }

    /// Returns the comment in a printable format
    pub fn comment(&self) -> &str {
        unsafe {
            str::from_utf8(::opt_bytes(self, (*self.raw).comment).unwrap())
                .unwrap()
        }
    }
}

impl<'agent> Binding for PublicKey<'agent> {
    type Raw = *mut raw::libssh2_agent_publickey;

    unsafe fn from_raw(raw: *mut raw::libssh2_agent_publickey)
                       -> PublicKey<'agent> {
        PublicKey { raw: raw, _marker: marker::PhantomData }
    }

    fn raw(&self) -> *mut raw::libssh2_agent_publickey { self.raw }
}