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 crate::interop::{CBuffer, Response, ToC}; pub struct Passwd { pub name: String, pub passwd: String, pub uid: libc::uid_t, pub gid: libc::gid_t, pub gecos: String, pub dir: String, pub shell: String, } impl ToC<CPasswd> for Passwd { unsafe fn to_c(&self, result: *mut CPasswd, buffer: &mut CBuffer) -> std::io::Result<()> { (*result).name = buffer.write_str(&self.name)?; (*result).passwd = buffer.write_str(&self.passwd)?; (*result).uid = self.uid; (*result).gid = self.gid; (*result).gecos = buffer.write_str(&self.gecos)?; (*result).dir = buffer.write_str(&self.dir)?; (*result).shell = buffer.write_str(&self.shell)?; Ok(()) } } pub trait PasswdHooks { fn get_all_entries() -> Response<Vec<Passwd>>; fn get_entry_by_uid(uid: libc::uid_t) -> Response<Passwd>; fn get_entry_by_name(name: String) -> Response<Passwd>; } #[repr(C)] #[allow(missing_copy_implementations)] pub struct CPasswd { pub name: *mut libc::c_char, pub passwd: *mut libc::c_char, pub uid: libc::uid_t, pub gid: libc::gid_t, pub gecos: *mut libc::c_char, pub dir: *mut libc::c_char, pub shell: *mut libc::c_char, } #[macro_export] macro_rules! libnss_passwd_hooks { ($mod_ident:ident, $hooks_ident:ident) => ( paste::item! { pub use self::[<libnss_passwd_ $mod_ident _hooks_impl>]::*; mod [<libnss_passwd_ $mod_ident _hooks_impl>] { #![allow(non_upper_case_globals)] use libc::c_int; use std::ffi::CStr; use std::str; use std::sync::{Mutex, MutexGuard}; use $crate::interop::{CBuffer, Iterator, Response}; use $crate::passwd::{CPasswd, Passwd, PasswdHooks}; lazy_static! { static ref [<PASSWD_ $mod_ident _ITERATOR>]: Mutex<Iterator<Passwd>> = Mutex::new(Iterator::<Passwd>::new()); } #[no_mangle] extern "C" fn [<_nss_ $mod_ident _setpwent>]() -> c_int { let mut iter: MutexGuard<Iterator<Passwd>> = [<PASSWD_ $mod_ident _ITERATOR>].lock().unwrap(); let status = match(super::$hooks_ident::get_all_entries()) { Response::Success(entries) => iter.open(entries), response => response.to_status() }; status as c_int } #[no_mangle] extern "C" fn [<_nss_ $mod_ident _endpwent>]() -> c_int { let mut iter: MutexGuard<Iterator<Passwd>> = [<PASSWD_ $mod_ident _ITERATOR>].lock().unwrap(); iter.close() as c_int } #[no_mangle] unsafe extern "C" fn [<_nss_ $mod_ident _getpwent_r>]( result: *mut CPasswd, buf: *mut libc::c_char, buflen: libc::size_t, errnop: *mut c_int ) -> c_int { let mut iter: MutexGuard<Iterator<Passwd>> = [<PASSWD_ $mod_ident _ITERATOR>].lock().unwrap(); iter.next().to_c(result, buf, buflen, errnop) as c_int } #[no_mangle] unsafe extern "C" fn [<_nss_ $mod_ident _getpwuid_r>]( uid: libc::uid_t, result: *mut CPasswd, buf: *mut libc::c_char, buflen: libc::size_t, errnop: *mut c_int ) -> c_int { super::$hooks_ident::get_entry_by_uid(uid).to_c(result, buf, buflen, errnop) as c_int } #[no_mangle] unsafe extern "C" fn [<_nss_ $mod_ident _getpwnam_r>]( name_: *const libc::c_char, result: *mut CPasswd, buf: *mut libc::c_char, buflen: libc::size_t, errnop: *mut c_int ) -> c_int { let cstr = CStr::from_ptr(name_); let response = match str::from_utf8(cstr.to_bytes()) { Ok(name) => super::$hooks_ident::get_entry_by_name(name.to_string()), Err(_) => Response::NotFound }; response.to_c(result, buf, buflen, errnop) as c_int } } } ) }