123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- //! pwd implementation for relibc
- use core::ptr;
- use c_str::CStr;
- use header::{errno, fcntl};
- use platform;
- use platform::types::*;
- use platform::Sys;
- use platform::{Line, RawFile, RawLineBuffer};
- #[repr(C)]
- pub struct passwd {
- pw_name: *mut c_char,
- pw_passwd: *mut c_char,
- pw_uid: uid_t,
- pw_gid: gid_t,
- pw_gecos: *mut c_char,
- pw_dir: *mut c_char,
- pw_shell: *mut c_char,
- }
- static mut PASSWD_BUF: *mut c_char = ptr::null_mut();
- static mut PASSWD: passwd = passwd {
- pw_name: ptr::null_mut(),
- pw_passwd: ptr::null_mut(),
- pw_uid: 0,
- pw_gid: 0,
- pw_gecos: ptr::null_mut(),
- pw_dir: ptr::null_mut(),
- pw_shell: ptr::null_mut(),
- };
- enum OptionPasswd {
- Error,
- NotFound,
- Found(*mut c_char),
- }
- fn pwd_lookup<F>(
- out: *mut passwd,
- alloc: Option<(*mut c_char, size_t)>,
- mut callback: F,
- ) -> OptionPasswd
- where
- // TODO F: FnMut(impl Iterator<Item = &[u8]>) -> bool
- F: FnMut(&[&[u8]]) -> bool,
- {
- let file = match RawFile::open(
- unsafe { CStr::from_bytes_with_nul_unchecked(b"/etc/passwd\0") },
- fcntl::O_RDONLY,
- 0,
- ) {
- Ok(file) => file,
- Err(_) => return OptionPasswd::Error,
- };
- let mut rlb = RawLineBuffer::new(*file);
- loop {
- let line = match rlb.next() {
- Line::Error => return OptionPasswd::Error,
- Line::EOF => return OptionPasswd::NotFound,
- Line::Some(line) => line,
- };
- // Parse into passwd
- let mut parts: [&[u8]; 7] = [&[]; 7];
- for (i, part) in line.splitn(7, |b| *b == b':').enumerate() {
- parts[i] = part;
- }
- if !callback(&parts) {
- // TODO when nll becomes a thing:
- // buf.drain(..newline + 1);
- continue;
- }
- let len = parts
- .iter()
- .enumerate()
- .filter(|(i, _)| *i != 2 && *i != 3)
- .map(|(_, part)| part.len() + 1)
- .sum();
- if alloc.map(|(_, s)| len > s as usize).unwrap_or(false) {
- unsafe {
- platform::errno = errno::ERANGE;
- }
- return OptionPasswd::Error;
- }
- let alloc = match alloc {
- Some((alloc, _)) => alloc,
- None => unsafe { platform::alloc(len) as *mut c_char },
- };
- // _ prefix so it won't complain about the trailing
- // _off += <thing>
- // in the macro that is never read
- let mut _off = 0;
- let mut parts = parts.into_iter();
- macro_rules! copy_into {
- ($entry:expr) => {
- debug_assert!(_off as usize <= len);
- let src = parts.next().unwrap_or(&(&[] as &[u8])); // this is madness
- let dst = unsafe { alloc.offset(_off) };
- for (i, c) in src.iter().enumerate() {
- unsafe {
- *dst.offset(i as isize) = *c as c_char;
- }
- }
- unsafe {
- *dst.offset(src.len() as isize) = 0;
- $entry = dst;
- }
- _off += src.len() as isize + 1;
- };
- ($entry:expr,parse) => {
- unsafe {
- $entry = parts
- .next()
- .and_then(|part| core::str::from_utf8(part).ok())
- .and_then(|part| part.parse().ok())
- .unwrap_or(0);
- }
- };
- }
- copy_into!((*out).pw_name);
- copy_into!((*out).pw_passwd);
- copy_into!((*out).pw_uid, parse);
- copy_into!((*out).pw_gid, parse);
- copy_into!((*out).pw_gecos);
- copy_into!((*out).pw_dir);
- copy_into!((*out).pw_shell);
- return OptionPasswd::Found(alloc);
- }
- }
- #[no_mangle]
- pub extern "C" fn getpwnam_r(
- name: *const c_char,
- out: *mut passwd,
- buf: *mut c_char,
- size: size_t,
- result: *mut *mut passwd,
- ) -> c_int {
- match pwd_lookup(out, Some((buf, size)), |parts| {
- let part = parts.get(0).unwrap_or(&(&[] as &[u8]));
- for (i, c) in part.iter().enumerate() {
- // /etc/passwd should not contain any NUL bytes in the middle
- // of entries, but if this happens, it can't possibly match the
- // search query since it's NUL terminated.
- if *c == 0 || unsafe { *name.offset(i as isize) } != *c as c_char {
- return false;
- }
- }
- true
- }) {
- OptionPasswd::Error => unsafe {
- *result = ptr::null_mut();
- -1
- },
- OptionPasswd::NotFound => unsafe {
- *result = ptr::null_mut();
- 0
- },
- OptionPasswd::Found(_) => unsafe {
- *result = out;
- 0
- },
- }
- }
- #[no_mangle]
- pub extern "C" fn getpwuid_r(
- uid: uid_t,
- out: *mut passwd,
- buf: *mut c_char,
- size: size_t,
- result: *mut *mut passwd,
- ) -> c_int {
- match pwd_lookup(out, Some((buf, size)), |parts| {
- let part = parts
- .get(2)
- .and_then(|part| core::str::from_utf8(part).ok())
- .and_then(|part| part.parse().ok());
- part == Some(uid)
- }) {
- OptionPasswd::Error => unsafe {
- *result = ptr::null_mut();
- -1
- },
- OptionPasswd::NotFound => unsafe {
- *result = ptr::null_mut();
- 0
- },
- OptionPasswd::Found(_) => unsafe {
- *result = out;
- 0
- },
- }
- }
- #[no_mangle]
- pub extern "C" fn getpwnam(name: *const c_char) -> *mut passwd {
- match pwd_lookup(unsafe { &mut PASSWD }, None, |parts| {
- let part = parts.get(0).unwrap_or(&(&[] as &[u8]));
- for (i, c) in part.iter().enumerate() {
- // /etc/passwd should not contain any NUL bytes in the middle
- // of entries, but if this happens, it can't possibly match the
- // search query since it's NUL terminated.
- if *c == 0 || unsafe { *name.offset(i as isize) } != *c as c_char {
- return false;
- }
- }
- true
- }) {
- OptionPasswd::Error => ptr::null_mut(),
- OptionPasswd::NotFound => ptr::null_mut(),
- OptionPasswd::Found(buf) => unsafe {
- PASSWD_BUF = buf;
- &mut PASSWD
- },
- }
- }
- #[no_mangle]
- pub extern "C" fn getpwuid(uid: uid_t) -> *mut passwd {
- match pwd_lookup(unsafe { &mut PASSWD }, None, |parts| {
- let part = parts
- .get(2)
- .and_then(|part| core::str::from_utf8(part).ok())
- .and_then(|part| part.parse().ok());
- part == Some(uid)
- }) {
- OptionPasswd::Error => ptr::null_mut(),
- OptionPasswd::NotFound => ptr::null_mut(),
- OptionPasswd::Found(buf) => unsafe {
- if PASSWD_BUF != ptr::null_mut() {
- platform::free(PASSWD_BUF as *mut c_void);
- }
- PASSWD_BUF = buf;
- &mut PASSWD
- },
- }
- }
|