Skip to content

Instantly share code, notes, and snippets.

@polachok
Created December 21, 2014 18:08
Show Gist options
  • Save polachok/d042a4bdee0dc2615f71 to your computer and use it in GitHub Desktop.
Save polachok/d042a4bdee0dc2615f71 to your computer and use it in GitHub Desktop.
rust nss
#![no_main]
extern crate libc;
use std::ptr;
use std::io::File;
use std::io::fs;
use std::io::BufferedReader;
use std::c_str::CString;
use libc::funcs::posix88::unistd::getuid;
enum NssStatus {
TryAgain,
Unavail,
NotFound,
Success,
Return,
}
impl NssStatus {
fn to_c(&self) -> int {
match *self {
NssStatus::TryAgain => -2,
NssStatus::Unavail => -1,
NssStatus::NotFound => 0,
NssStatus::Success => 1,
NssStatus::Return => 2,
}
}
}
#[deriving(Show)]
struct Passwd {
name: String,
passwd: String,
uid: libc::uid_t,
gid: libc::gid_t,
gecos: String,
dir: String,
shell: String,
}
#[repr(C)]
pub struct CPasswd {
name: *mut libc::c_char,
passwd: *mut libc::c_char,
uid: libc::uid_t,
gid: libc::gid_t,
gecos: *mut libc::c_char,
dir: *mut libc::c_char,
shell: *mut libc::c_char,
}
impl Passwd {
unsafe fn to_c_passwd(self, pwbuf: *mut CPasswd, buf: &mut CBuffer) {
(*pwbuf).name = buf.write_str(self.name);
(*pwbuf).passwd = buf.write_str(self.passwd);
(*pwbuf).uid = self.uid;
(*pwbuf).gid = self.gid;
(*pwbuf).gecos = buf.write_str(self.gecos);
(*pwbuf).dir = buf.write_str(self.dir);
(*pwbuf).shell = buf.write_str(self.shell);
}
}
struct PasswdFile {
buf: BufferedReader<File>,
}
impl PasswdFile {
fn new(path: &Path) -> Result<PasswdFile, std::io::IoError> {
match File::open(path) {
Ok(file) => Ok(PasswdFile { buf: BufferedReader::new(file) }),
Err(e) => Err(e)
}
}
/* XXX: unsafe shit */
fn parse_line(line: String) -> Option<Passwd> {
let v: Vec<&str> = line.split(':').collect();
let p = Passwd {
name: v[0].to_string(),
passwd: v[1].to_string(),
uid: from_str::<libc::uid_t>(v[2]).unwrap(),
gid: from_str::<libc::gid_t>(v[3]).unwrap(),
gecos: v[4].to_string(),
dir: v[5].to_string(),
shell: v[6].trim().to_string(),
};
return Some(p)
}
}
impl Iterator<Passwd> for PasswdFile {
fn next(&mut self) -> Option<Passwd> {
if let Some(r) = self.buf.lines().next() {
if let Ok(line) = r {
PasswdFile::parse_line(line)
} else {
None
}
} else {
None
}
}
}
struct CBuffer {
pos: *mut libc::c_char,
free: libc::size_t,
}
impl CBuffer {
fn new(ptr: *mut libc::c_char, len: libc::size_t) -> CBuffer {
CBuffer { pos: ptr, free: len }
}
/* XXX: check free */
fn write<T>(&mut self, data: *const T, len: uint) -> *mut libc::c_char {
let t = self.pos;
unsafe {
ptr::copy_memory(self.pos, data as *const i8 , len);
self.pos = self.pos.offset(len as int);
self.free -= len as libc::size_t;
}
t
}
fn write_str<S: ToCStr>(&mut self, string: S) -> *mut libc::c_char {
let s = string.to_c_str();
self.write(s.as_ptr(), s.len() + 1)
}
}
unsafe fn get_passwd_files() -> Vec<Path> {
let mut paths = match getuid() {
0 => fs::readdir(&Path::new("/etc/passwd.d")).unwrap_or(Vec::new()),
uid => vec![Path::new(format!("/etc/passwd.d/{}", uid))],
};
paths
}
#[no_mangle]
pub extern fn _nss_rust_setpwent() -> int { 1 }
#[no_mangle]
pub extern fn _nss_rust_endpwent() -> int { 1 }
#[no_mangle]
pub extern fn _nss_rust_getpwent_r() -> int { -1 }
#[no_mangle]
pub unsafe extern "C" fn _nss_rust_getpwuid_r(uid: libc::uid_t, pwbuf: *mut CPasswd, buf: *mut libc::c_char,
buflen: libc::size_t, errnop: *mut int) -> int {
for path in get_passwd_files().iter() {
if let Ok(mut file) = PasswdFile::new(path) {
if let Some(entry) = file.find(|entry| entry.uid == uid) {
entry.to_c_passwd(pwbuf, &mut CBuffer::new(buf, buflen));
return NssStatus::Success.to_c();
}
}
}
NssStatus::NotFound.to_c()
}
#[no_mangle]
pub unsafe extern "C" fn _nss_rust_getpwnam_r(name_: *const libc::c_char, pwbuf: *mut CPasswd,
buf: *mut libc::c_char, buflen: libc::size_t, errnop: *mut int) -> int {
if let Some(name) = std::c_str::CString::new(name_, false).as_str() {
for path in get_passwd_files().iter() {
if let Ok(mut file) = PasswdFile::new(path) {
if let Some(entry) = file.find(|entry| entry.name == name) {
entry.to_c_passwd(pwbuf, &mut CBuffer::new(buf, buflen));
return NssStatus::Success.to_c();
}
}
}
}
NssStatus::NotFound.to_c()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment