# HG changeset patch # User Yuya Nishihara # Date 1537781626 -32400 # Node ID 44840bcc411ab5d0466d63cbbacb366b837d3950 # Parent 571d8eb39095aa6b646e32d72a355cfdeb4839a8 rust-chg: port basic socket path handling from cHg of C This is basically modeled after setcmdserveropts() of chg.c. diff -r 571d8eb39095 -r 44840bcc411a rust/chg/src/lib.rs --- a/rust/chg/src/lib.rs Mon Sep 24 18:21:10 2018 +0900 +++ b/rust/chg/src/lib.rs Mon Sep 24 18:33:46 2018 +0900 @@ -12,6 +12,7 @@ extern crate tokio_process; pub mod attachio; +pub mod locator; pub mod message; pub mod procutil; pub mod runcommand; diff -r 571d8eb39095 -r 44840bcc411a rust/chg/src/locator.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/chg/src/locator.rs Mon Sep 24 18:33:46 2018 +0900 @@ -0,0 +1,74 @@ +// Copyright 2011, 2018 Yuya Nishihara +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. + +//! Utility for locating command-server process. + +use std::env; +use std::fs::{self, DirBuilder}; +use std::io; +use std::os::unix::fs::{DirBuilderExt, MetadataExt}; +use std::path::{Path, PathBuf}; + +use super::procutil; + +/// Determines the server socket to connect to. +/// +/// If no `$CHGSOCKNAME` is specified, the socket directory will be created +/// as necessary. +pub fn prepare_server_socket_path() -> io::Result { + if let Some(s) = env::var_os("CHGSOCKNAME") { + Ok(PathBuf::from(s)) + } else { + let mut path = default_server_socket_dir(); + create_secure_dir(&path)?; + path.push("server"); + Ok(path) + } +} + +/// Determines the default server socket path as follows. +/// +/// 1. `$XDG_RUNTIME_DIR/chg` +/// 2. `$TMPDIR/chg$UID` +/// 3. `/tmp/chg$UID` +pub fn default_server_socket_dir() -> PathBuf { + // XDG_RUNTIME_DIR should be ignored if it has an insufficient permission. + // https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + if let Some(Ok(s)) = env::var_os("XDG_RUNTIME_DIR").map(check_secure_dir) { + let mut path = PathBuf::from(s); + path.push("chg"); + path + } else { + let mut path = env::temp_dir(); + path.push(format!("chg{}", procutil::get_effective_uid())); + path + } +} + +/// Creates a directory which the other users cannot access to. +/// +/// If the directory already exists, tests its permission. +fn create_secure_dir

(path: P) -> io::Result<()> + where P: AsRef, +{ + DirBuilder::new().mode(0o700).create(path.as_ref()).or_else(|err| { + if err.kind() == io::ErrorKind::AlreadyExists { + check_secure_dir(path).map(|_| ()) + } else { + Err(err) + } + }) +} + +fn check_secure_dir

(path: P) -> io::Result

+ where P: AsRef, +{ + let a = fs::symlink_metadata(path.as_ref())?; + if a.is_dir() && a.uid() == procutil::get_effective_uid() && (a.mode() & 0o777) == 0o700 { + Ok(path) + } else { + Err(io::Error::new(io::ErrorKind::Other, "insecure directory")) + } +} diff -r 571d8eb39095 -r 44840bcc411a rust/chg/src/procutil.rs --- a/rust/chg/src/procutil.rs Mon Sep 24 18:21:10 2018 +0900 +++ b/rust/chg/src/procutil.rs Mon Sep 24 18:33:46 2018 +0900 @@ -15,6 +15,11 @@ fn sendfds(sockfd: c_int, fds: *const c_int, fdlen: size_t) -> ssize_t; } +/// Returns the effective uid of the current process. +pub fn get_effective_uid() -> u32 { + unsafe { libc::geteuid() } +} + /// Changes the given fd to blocking mode. pub fn set_blocking_fd(fd: RawFd) -> io::Result<()> { let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) };