changeset 19:d654aa0655e5

Making PamHandle a struct with methods
author Anthony Nowell <anthony@algorithmia.com>
date Mon, 25 Sep 2017 23:42:35 -0600
parents 0f5e9e8963ae
children 734ca62159fb
files pam-http/src/lib.rs pam-sober/src/ffi.rs pam-sober/src/lib.rs pam/src/module.rs
diffstat 4 files changed, 125 insertions(+), 122 deletions(-) [+]
line wrap: on
line diff
--- a/pam-http/src/lib.rs	Sun Sep 24 22:11:05 2017 -0600
+++ b/pam-http/src/lib.rs	Mon Sep 25 23:42:35 2017 -0600
@@ -65,7 +65,7 @@
 }
 
 fn get_url(url: &str, user: &str, password: Option<&str>) -> reqwest::Result<StatusCode> {
-    let client = Client::builder()?.timeout(Duration::from_secs(5)).build()?;
+    let client = Client::builder()?.timeout(Duration::from_secs(15)).build()?;
     client.get(url)?
         .basic_auth(user, password)
         .send()
--- a/pam-sober/src/ffi.rs	Sun Sep 24 22:11:05 2017 -0600
+++ b/pam-sober/src/ffi.rs	Mon Sep 25 23:42:35 2017 -0600
@@ -1,4 +1,4 @@
-use pam::module::{PamHandleT};
+use pam::module::{PamHandle};
 use pam::constants::{PamFlag, PamResultCode, PAM_SILENT};
 use std::ffi::CStr;
 use std::os::raw::{c_char, c_int};
@@ -17,7 +17,7 @@
 
 #[no_mangle]
 pub extern "C" fn pam_sm_acct_mgmt(
-	pamh: &PamHandleT,
+	pamh: &PamHandle,
 	flags: PamFlag,
 	argc: c_int,
 	argv: *const *const c_char,
@@ -29,7 +29,7 @@
 
 #[no_mangle]
 pub extern "C" fn pam_sm_authenticate(
-	pamh: &PamHandleT,
+	pamh: &PamHandle,
 	flags: PamFlag,
 	argc: c_int,
 	argv: *const *const c_char,
@@ -41,7 +41,7 @@
 
 #[no_mangle]
 pub extern "C" fn pam_sm_chauthtok(
-	_: &PamHandleT,
+	_: &PamHandle,
 	_: PamFlag,
 	_: c_int,
 	_: *const *const c_char,
@@ -51,7 +51,7 @@
 
 #[no_mangle]
 pub extern "C" fn pam_sm_close_session(
-	_: &PamHandleT,
+	_: &PamHandle,
 	_: PamFlag,
 	_: c_int,
 	_: *const *const c_char,
@@ -61,7 +61,7 @@
 
 #[no_mangle]
 pub extern "C" fn pam_sm_open_session(
-	_: &PamHandleT,
+	_: &PamHandle,
 	_: PamFlag,
 	_: c_int,
 	_: *const *const c_char,
@@ -71,7 +71,7 @@
 
 #[no_mangle]
 pub extern "C" fn pam_sm_setcred(
-	pamh: &PamHandleT,
+	pamh: &PamHandle,
 	flags: PamFlag,
 	argc: c_int,
 	argv: *const *const c_char,
--- a/pam-sober/src/lib.rs	Sun Sep 24 22:11:05 2017 -0600
+++ b/pam-sober/src/lib.rs	Mon Sep 25 23:42:35 2017 -0600
@@ -3,11 +3,9 @@
 
 pub mod ffi;
 
-use pam::module::{PamHandleT, get_item, get_user};
+use pam::module::PamHandle;
 use pam::constants::{PamResultCode, PAM_PROMPT_ECHO_OFF};
 use pam::conv::PamConv;
-use std::collections::HashMap;
-use std::time::Duration;
 use rand::Rng;
 use std::str::FromStr;
 
@@ -30,7 +28,7 @@
 }
 
 // This function performs the task of authenticating the user.
-pub fn sm_authenticate(pamh: &PamHandleT, args: Vec<String>, silent: bool) -> PamResultCode {
+pub fn sm_authenticate(pamh: &PamHandle, args: Vec<String>, silent: bool) -> PamResultCode {
     println!("Let's auth over HTTP");
 
     /* TODO: use args to change difficulty ;-)
@@ -41,9 +39,9 @@
     */
 
     // TODO: maybe we can change difficulty base on user?
-    // let user = pam_try!(get_user(&pamh, None));
+    // let user = pam_try!(pam.get_user(None));
 
-    let conv = match get_item::<PamConv>(&pamh) {
+    let conv = match pamh.get_item::<PamConv>() {
         Ok(conv) => conv,
         Err(err) => {
             println!("Couldn't get pam_conv");
@@ -74,7 +72,7 @@
 // information about a user than their authentication token. This function is used to make such
 // information available to the application. It should only be called after the user has been
 // authenticated but before a session has been established.
-pub fn sm_setcred(_pamh: &PamHandleT, _args: Vec<String>, _silent: bool) -> PamResultCode {
+pub fn sm_setcred(_pamh: &PamHandle, _args: Vec<String>, _silent: bool) -> PamResultCode {
     println!("set credentials");
     PamResultCode::PAM_SUCCESS
 }
@@ -84,7 +82,7 @@
 // authentication module. This function checks for other things. Such things might be: the time of
 // day or the date, the terminal line, remote hostname, etc. This function may also determine
 // things like the expiration on passwords, and respond that the user change it before continuing.
-pub fn acct_mgmt(_pamh: &PamHandleT, _args: Vec<String>, _silent: bool) -> PamResultCode {
+pub fn acct_mgmt(_pamh: &PamHandle, _args: Vec<String>, _silent: bool) -> PamResultCode {
     println!("account management");
     PamResultCode::PAM_SUCCESS
 }
--- a/pam/src/module.rs	Sun Sep 24 22:11:05 2017 -0600
+++ b/pam/src/module.rs	Mon Sep 25 23:42:35 2017 -0600
@@ -12,7 +12,7 @@
 /// Such a call provides a pam handle pointer.  The same pointer should be given
 /// as an argument when making API calls.
 #[allow(missing_copy_implementations)]
-pub enum PamHandleT {}
+pub enum PamHandle {}
 
 #[allow(missing_copy_implementations)]
 enum PamItemT {}
@@ -22,35 +22,43 @@
 
 #[link(name = "pam")]
 extern "C" {
-    fn pam_get_data(pamh: *const PamHandleT,
+    fn pam_get_data(pamh: *const PamHandle,
                     module_data_name: *const c_char,
                     data: &mut *const PamDataT)
                     -> PamResultCode;
 
-    fn pam_set_data(pamh: *const PamHandleT,
+    fn pam_set_data(pamh: *const PamHandle,
                     module_data_name: *const c_char,
                     data: Box<PamDataT>,
-                    cleanup: extern "C" fn(pamh: *const PamHandleT,
+                    cleanup: extern "C" fn(pamh: *const PamHandle,
                                            data: Box<PamDataT>,
                                            error_status: PamResultCode))
                     -> PamResultCode;
 
-    fn pam_get_item(pamh: *const PamHandleT,
+    fn pam_get_item(pamh: *const PamHandle,
                     item_type: PamItemType,
                     item: &mut *const PamItemT)
                     -> PamResultCode;
 
-    fn pam_set_item(pamh: *mut PamHandleT,
+    fn pam_set_item(pamh: *mut PamHandle,
                     item_type: PamItemType,
                     item: &PamItemT)
                     -> PamResultCode;
 
-    fn pam_get_user(pamh: *const PamHandleT,
+    fn pam_get_user(pamh: *const PamHandle,
                     user: &*mut c_char,
                     prompt: *const c_char)
                     -> PamResultCode;
 }
 
+#[no_mangle]
+pub extern "C" fn cleanup<T>(_: *const PamHandle, c_data: Box<PamDataT>, _: PamResultCode) {
+    unsafe {
+        let data: Box<T> = mem::transmute(c_data);
+        mem::drop(data);
+    }
+}
+
 pub type PamResult<T> = Result<T, PamResultCode>;
 
 /// Type-level mapping for safely retrieving values with `get_item`.
@@ -67,113 +75,110 @@
     fn item_type() -> PamItemType;
 }
 
-/// Gets some value, identified by `key`, that has been set by the module
-/// previously.
-///
-/// See `pam_get_data` in
-/// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
-pub unsafe fn get_data<'a, T>(pamh: &'a PamHandleT, key: &str) -> PamResult<&'a T> {
-    let c_key = CString::new(key).unwrap().as_ptr();
-    let mut ptr: *const PamDataT = ptr::null();
-    let res = pam_get_data(pamh, c_key, &mut ptr);
-    if PamResultCode::PAM_SUCCESS == res && !ptr.is_null() {
-        let typed_ptr: *const T = mem::transmute(ptr);
-        let data: &T = &*typed_ptr;
-        Ok(data)
-    } else {
-        Err(res)
+
+impl PamHandle {
+    /// Gets some value, identified by `key`, that has been set by the module
+    /// previously.
+    ///
+    /// See `pam_get_data` in
+    /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
+    pub unsafe fn get_data<'a, T>(&'a self, key: &str) -> PamResult<&'a T> {
+        let c_key = CString::new(key).unwrap().as_ptr();
+        let mut ptr: *const PamDataT = ptr::null();
+        let res = pam_get_data(self, c_key, &mut ptr);
+        if PamResultCode::PAM_SUCCESS == res && !ptr.is_null() {
+            let typed_ptr: *const T = mem::transmute(ptr);
+            let data: &T = &*typed_ptr;
+            Ok(data)
+        } else {
+            Err(res)
+        }
     }
-}
 
-/// Stores a value that can be retrieved later with `get_data`.  The value lives
-/// as long as the current pam cycle.
-///
-/// See `pam_set_data` in
-/// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
-pub fn set_data<T>(pamh: &PamHandleT, key: &str, data: Box<T>) -> PamResult<()> {
-    let c_key = CString::new(key).unwrap().as_ptr();
-    let res = unsafe {
-        let c_data: Box<PamDataT> = mem::transmute(data);
-        pam_set_data(pamh, c_key, c_data, cleanup::<T>)
-    };
-    if PamResultCode::PAM_SUCCESS == res {
-        Ok(())
-    } else {
-        Err(res)
+    /// Stores a value that can be retrieved later with `get_data`.  The value lives
+    /// as long as the current pam cycle.
+    ///
+    /// See `pam_set_data` in
+    /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
+    pub fn set_data<T>(&self, key: &str, data: Box<T>) -> PamResult<()> {
+        let c_key = CString::new(key).unwrap().as_ptr();
+        let res = unsafe {
+            let c_data: Box<PamDataT> = mem::transmute(data);
+            pam_set_data(self, c_key, c_data, cleanup::<T>)
+        };
+        if PamResultCode::PAM_SUCCESS == res {
+            Ok(())
+        } else {
+            Err(res)
+        }
     }
-}
 
-#[no_mangle]
-pub extern "C" fn cleanup<T>(_: *const PamHandleT, c_data: Box<PamDataT>, _: PamResultCode) {
-    unsafe {
-        let data: Box<T> = mem::transmute(c_data);
-        mem::drop(data);
-    }
-}
+
 
-/// Retrieves a value that has been set, possibly by the pam client.  This is
-/// particularly useful for getting a `PamConv` reference.
-///
-/// See `pam_get_item` in
-/// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
-pub fn get_item<'a, T: PamItem>(pamh: &'a PamHandleT) -> PamResult<&'a T> {
-    let mut ptr: *const PamItemT = ptr::null();
-    let (res, item) = unsafe {
-        let r = pam_get_item(pamh, T::item_type(), &mut ptr);
-        let typed_ptr: *const T = mem::transmute(ptr);
-        let t: &T = &*typed_ptr;
-        (r, t)
-    };
-    if PamResultCode::PAM_SUCCESS == res {
-        Ok(item)
-    } else {
-        Err(res)
+    /// Retrieves a value that has been set, possibly by the pam client.  This is
+    /// particularly useful for getting a `PamConv` reference.
+    ///
+    /// See `pam_get_item` in
+    /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
+    pub fn get_item<'a, T: PamItem>(&self) -> PamResult<&'a T> {
+        let mut ptr: *const PamItemT = ptr::null();
+        let (res, item) = unsafe {
+            let r = pam_get_item(self, T::item_type(), &mut ptr);
+            let typed_ptr: *const T = mem::transmute(ptr);
+            let t: &T = &*typed_ptr;
+            (r, t)
+        };
+        if PamResultCode::PAM_SUCCESS == res {
+            Ok(item)
+        } else {
+            Err(res)
+        }
     }
-}
 
-/// Sets a value in the pam context. The value can be retrieved using
-/// `get_item`.
-///
-/// Note that all items are strings, except `PAM_CONV` and `PAM_FAIL_DELAY`.
-///
-/// See `pam_set_item` in
-/// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
-pub fn set_item_str<'a, T: PamItem>(pamh: &'a mut PamHandleT, item: &str) -> PamResult<()> {
-    let c_item = CString::new(item).unwrap().as_ptr();
+    /// Sets a value in the pam context. The value can be retrieved using
+    /// `get_item`.
+    ///
+    /// Note that all items are strings, except `PAM_CONV` and `PAM_FAIL_DELAY`.
+    ///
+    /// See `pam_set_item` in
+    /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
+    pub fn set_item_str<T: PamItem>(&mut self, item: &str) -> PamResult<()> {
+        let c_item = CString::new(item).unwrap().as_ptr();
+
+        let res = unsafe {
+            pam_set_item(self,
+                        T::item_type(),
 
-    let res = unsafe {
-        pam_set_item(pamh,
-                     T::item_type(),
-
-                     // unwrapping is okay here, as c_item will not be a NULL
-                     // pointer
-                     (c_item as *const PamItemT).as_ref().unwrap())
-    };
-    if PamResultCode::PAM_SUCCESS == res {
-        Ok(())
-    } else {
-        Err(res)
+                        // unwrapping is okay here, as c_item will not be a NULL
+                        // pointer
+                        (c_item as *const PamItemT).as_ref().unwrap())
+        };
+        if PamResultCode::PAM_SUCCESS == res {
+            Ok(())
+        } else {
+            Err(res)
+        }
     }
-}
 
-/// Retrieves the name of the user who is authenticating or logging in.
-///
-/// This is really a specialization of `get_item`.
-///
-/// See `pam_get_user` in
-/// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
-pub fn get_user<'a>(pamh: &'a PamHandleT, prompt: Option<&str>) -> PamResult<String> {
-    let ptr: *mut c_char = ptr::null_mut();
-    let c_prompt = match prompt {
-        Some(p) => CString::new(p).unwrap().as_ptr(),
-        None => ptr::null(),
-    };
-    let res = unsafe { pam_get_user(pamh, &ptr, c_prompt) };
-    if PamResultCode::PAM_SUCCESS == res && !ptr.is_null() {
-        let const_ptr = ptr as *const c_char;
-        let bytes = unsafe { CStr::from_ptr(const_ptr).to_bytes() };
-        String::from_utf8(bytes.to_vec()).map_err(|_| PamResultCode::PAM_CONV_ERR)
-    } else {
-        Err(res)
+    /// Retrieves the name of the user who is authenticating or logging in.
+    ///
+    /// This is really a specialization of `get_item`.
+    ///
+    /// See `pam_get_user` in
+    /// http://www.linux-pam.org/Linux-PAM-html/mwg-expected-by-module-item.html
+    pub fn get_user(&self, prompt: Option<&str>) -> PamResult<String> {
+        let ptr: *mut c_char = ptr::null_mut();
+        let c_prompt = match prompt {
+            Some(p) => CString::new(p).unwrap().as_ptr(),
+            None => ptr::null(),
+        };
+        let res = unsafe { pam_get_user(self, &ptr, c_prompt) };
+        if PamResultCode::PAM_SUCCESS == res && !ptr.is_null() {
+            let const_ptr = ptr as *const c_char;
+            let bytes = unsafe { CStr::from_ptr(const_ptr).to_bytes() };
+            String::from_utf8(bytes.to_vec()).map_err(|_| PamResultCode::PAM_CONV_ERR)
+        } else {
+            Err(res)
+        }
     }
-}
+}
\ No newline at end of file