/* Copyright 2021 Dominik George <dominik.george@teckids.org> 65;6203;1c * Copyright 2021 mirabilos <thorsten.glaser@teckids.org> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ use libc::{ERANGE, getpwnam_r, getpwuid_r, passwd, c_void, uid_t, gid_t, size_t, malloc, free}; use std::ffi::{CStr, CString}; use std::io; use std::mem::uninitialized; use std::ptr::null_mut; pub struct Passwd<'a> { pub pw_name: &'a str, pub pw_passwd: &'a str, pub pw_uid: uid_t, pub pw_gid: gid_t, pub pw_gecos: &'a str, pub pw_dir: &'a str, pub pw_shell: &'a str } const MAX_BUFLEN: size_t = 1024 * 1024; fn getpwxx_fillpw<'a>(c_passwd: passwd) -> Passwd<'a> { unsafe { Passwd { pw_name: CStr::from_ptr(c_passwd.pw_name).to_str().ok().unwrap(), pw_passwd: CStr::from_ptr(c_passwd.pw_passwd).to_str().ok().unwrap(), pw_uid: c_passwd.pw_uid, pw_gid: c_passwd.pw_gid, pw_gecos: CStr::from_ptr(c_passwd.pw_gecos).to_str().ok().unwrap(), pw_dir: CStr::from_ptr(c_passwd.pw_dir).to_str().ok().unwrap(), pw_shell: CStr::from_ptr(c_passwd.pw_shell).to_str().ok().unwrap(), } } } pub fn getpwnam_safe<'a>(name: String) -> Result<Passwd<'a>, io::Error> { let res: Passwd; unsafe { let mut c_passwd: passwd = uninitialized(); let mut c_passwd_ptr: *mut passwd = null_mut(); let mut buf: *mut i8 = uninitialized(); let mut buflen: size_t = 1024; let nam = match CString::new(name.as_str()) { Ok(nam) => nam, Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)) }; while c_passwd_ptr.is_null() { buf = malloc(buflen) as *mut i8; if buf.is_null() { return Err(io::Error::last_os_error()); } let error = getpwnam_r(nam.as_ptr(), &mut c_passwd, buf, buflen, &mut c_passwd_ptr); if c_passwd_ptr.is_null() && (error != ERANGE || buflen >= MAX_BUFLEN) { free(buf as *mut c_void); return Err(io::Error::from_raw_os_error(error)); } buflen += 1024; } res = getpwxx_fillpw(c_passwd); free(buf as *mut c_void); } return Ok(res); } pub fn getpwuid_safe<'a>(uid: uid_t) -> Result<Passwd<'a>, io::Error> { let res: Passwd; unsafe { let mut c_passwd: passwd = uninitialized(); let mut c_passwd_ptr: *mut passwd = null_mut(); let mut buf: *mut i8 = uninitialized(); let mut buflen: size_t = 1024; while c_passwd_ptr.is_null() { buf = malloc(buflen) as *mut i8; if buf.is_null() { return Err(io::Error::last_os_error()); } let error = getpwuid_r(uid, &mut c_passwd, buf, buflen, &mut c_passwd_ptr); if c_passwd_ptr.is_null() && (error != ERANGE || buflen >= MAX_BUFLEN) { free(buf as *mut c_void); return Err(io::Error::from_raw_os_error(error)); } buflen += 1024; } res = getpwxx_fillpw(c_passwd); free(buf as *mut c_void); } return Ok(res); }