/* Copyright 2021 Dominik George <dominik.george@teckids.org> * 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 { pub pw_name: String, pub pw_passwd: String, pub pw_uid: uid_t, pub pw_gid: gid_t, pub pw_gecos: String, pub pw_dir: String, pub pw_shell: String } const MAX_BUFLEN: size_t = 1024 * 1024; fn getpwxx_fillpw(c_passwd: passwd) -> Passwd { unsafe { Passwd { pw_name: CStr::from_ptr(c_passwd.pw_name).to_string_lossy().into_owned(), pw_passwd: CStr::from_ptr(c_passwd.pw_passwd).to_string_lossy().into_owned(), pw_uid: c_passwd.pw_uid, pw_gid: c_passwd.pw_gid, pw_gecos: CStr::from_ptr(c_passwd.pw_gecos).to_string_lossy().into_owned(), pw_dir: CStr::from_ptr(c_passwd.pw_dir).to_string_lossy().into_owned(), pw_shell: CStr::from_ptr(c_passwd.pw_shell).to_string_lossy().into_owned(), } } } pub fn getpwnam_safe(name: String) -> Result<Passwd, 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(uid: uid_t) -> Result<Passwd, 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); }