pub struct ControlToken(/* private fields */);Expand description
A shared secret that proves a control-channel caller is this same user.
§Why this exists
On Unix the daemon asks the kernel which uid is on the other end of the
socket and refuses anything that is not its own - see the peer check in the
unix module. Windows offers an equivalent, but reaching it means calling
ImpersonateNamedPipeClient and comparing security identifiers through raw
FFI, and this workspace is unsafe_code = "forbid" from top to bottom. So
the Windows control channel served every connection it accepted: anyone who
could reach the pipe could spawn a tool-executing agent and answer its
approval prompts.
A token closes that without any of the FFI. The daemon writes a fresh random
secret into its own directory, readable only by the owner, and refuses any
connection that cannot quote it. A caller who can read the file is a caller
who can already read config.toml - so the token grants nothing that was not
already reachable, which is exactly the property wanted.
It is required on every platform, not only Windows. One protocol is easier to reason about than two, the extra round trip on a local socket is unmeasurable, and on Unix it is defence in depth behind the uid check rather than a replacement for it.
Implementations§
Source§impl ControlToken
impl ControlToken
Sourcepub fn pid_path(dir: &Path) -> PathBuf
pub fn pid_path(dir: &Path) -> PathBuf
Where the daemon records its own process id.
So lev daemon stop has a way through when the control channel does not
answer - a wedged daemon, or a token file that went missing. Without it
the only recovery was pkill, and the advice to “restart it” was advice
that could not work: restart stops before it starts, and the stop was
the part that failed.
Sourcepub fn read_pid(dir: &Path) -> Option<u32>
pub fn read_pid(dir: &Path) -> Option<u32>
The recorded daemon pid, if one was written and still parses.
Sourcepub fn create(dir: &Path) -> Result<Self>
pub fn create(dir: &Path) -> Result<Self>
Generate a fresh token and write it owner-only.
Called at bind, so a restarted daemon invalidates every previous token - a stale one cannot be replayed against the new process.
Trait Implementations§
Source§impl Clone for ControlToken
impl Clone for ControlToken
Source§fn clone(&self) -> ControlToken
fn clone(&self) -> ControlToken
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for ControlToken
impl RefUnwindSafe for ControlToken
impl Send for ControlToken
impl Sync for ControlToken
impl Unpin for ControlToken
impl UnsafeUnpin for ControlToken
impl UnwindSafe for ControlToken
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> ConditionalSend for Twhere
T: Send,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.