mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-05 19:18:25 +00:00
install-service.ps1 created C:\ProgramData\fips without setting an ACL, so it inherited C:\ProgramData's access: any local user could read the node's identity key there, and could create a fips.yaml, fips.key, hosts, peers.allow or peers.deny in the directory before one existed, for the service, running as LocalSystem, to read. The service log is written there too. The installer now builds an ACL that grants only SYSTEM and Administrators and does not inherit, and creates a new directory with that ACL already applied, using the .NET call each PowerShell edition provides. Created first and restricted afterwards, the empty directory would carry C:\ProgramData's access in between, and any local user could turn it into a junction in that time with no privilege and without changing its owner. An existing directory is refused if it is a link or junction or is owned by an account other than SYSTEM, Administrators or the installing administrator, since a user who created it could swap it for a link to another directory. Otherwise the installer makes Administrators the owner, refuses the directory if it has since become a link and any link or folder inside it, applies the ACL, and resets the owner and ACL of each existing file. That check runs before the ACL is applied, because applying it rewrites the inherited entries of everything below the directory, and runs again after it and after the reset. Every icacls call acts on a link rather than its target and has its exit code checked. Files created in the directory later, by the service or fipsctl keygen, take the same ACL. Well-known SIDs are used so the step works on non-English Windows. A user who created the directory keeps full control of it through the entry C:\ProgramData's CREATOR OWNER grant leaves for their account, and taking ownership changes only the owner. So each refusal tells the operator to copy out anything needed and delete the directory, taking ownership only if that is what it takes to delete it, and an icacls failure says to delete the directory or the file, or simply retry if the file has gone. Packaging tests check the order of these steps and that they come before any path inside the directory is touched; that the ACL is built with both SIDs and both inheritance flags and passed to the directory's creation; the refusal conditions themselves (the owner test, the directory link test at the start and in each recheck, and a link or folder entry each refused on its own); that every icacls call acts on links and is checked; and that takeown is never offered as the recovery. The README and the fips reference say that reading the directory now needs an elevated prompt (an unelevated foreground run may skip the config there or fail with an access error), that the installer should run before fipsctl keygen, and that it should run again after files are moved into the directory, since a moved file keeps its old permissions.
103 lines
4.5 KiB
Markdown
103 lines
4.5 KiB
Markdown
# `fips`
|
|
|
|
The FIPS mesh network daemon.
|
|
|
|
## Synopsis
|
|
|
|
```text
|
|
fips [-c FILE]
|
|
```
|
|
|
|
On Windows the same binary additionally accepts `--install-service`,
|
|
`--uninstall-service`, and (used internally by the service control
|
|
manager) `--service`.
|
|
|
|
## Description
|
|
|
|
`fips` is the FIPS daemon. It loads a YAML configuration, resolves an
|
|
identity, brings up the TUN adapter, listens on configured transports,
|
|
authenticates peers, maintains the spanning tree, and forwards mesh
|
|
traffic. There is one daemon per node.
|
|
|
|
The daemon stays in the foreground, logging to stderr, until it
|
|
receives `SIGINT` or `SIGTERM`. On Windows, the service variant is
|
|
controlled through the standard service control manager.
|
|
|
|
## Options
|
|
|
|
| Flag | Argument | Description |
|
|
| ---- | -------- | ----------- |
|
|
| `-c`, `--config` | `FILE` | Use `FILE` as the configuration. Skips the default search paths. |
|
|
| `-V` | — | Print the short version, `<version> (rev <git-hash>)`. The `rev` part is omitted when the build could not read a git revision, as in a package built from a git worktree. |
|
|
| `--version` | — | Print the long version: short version plus build target triple. |
|
|
| `-h`, `--help` | — | Print usage and exit. |
|
|
| `--install-service` | — | (Windows only) Install `fips` as a Windows service. Requires Administrator. |
|
|
| `--uninstall-service` | — | (Windows only) Uninstall the Windows service. Requires Administrator. |
|
|
| `--service` | — | (Windows only, internal) Run as a Windows service. Invoked by the service control manager — not for direct use. |
|
|
|
|
There are no other CLI flags; all daemon behaviour is governed by the
|
|
YAML configuration. See [configuration.md](configuration.md).
|
|
|
|
## Exit Codes
|
|
|
|
| Code | Meaning |
|
|
| ---- | ------- |
|
|
| `0` | Clean shutdown after `SIGINT` / `SIGTERM`. |
|
|
| `1` | Failed to load configuration, resolve identity, construct the node, or start the node. The reason is printed to stderr before exit. |
|
|
|
|
## Environment
|
|
|
|
| Variable | Description |
|
|
| -------- | ----------- |
|
|
| `RUST_LOG` | Tracing filter directive. Overrides `node.log_level` from the config. Examples: `info`, `debug`, `fips=trace,fips::node::handlers::mmp=debug`. |
|
|
| `XDG_RUNTIME_DIR` | Used to derive the default control-socket path when `/run/fips` does not exist. See [control-socket.md](control-socket.md). |
|
|
| `FIPS_CONFIG` | (Windows service mode only) Path to the configuration file when the daemon runs under the service control manager. |
|
|
|
|
The daemon also clamps the `nostr_relay_pool`, `nostr_sdk`, and `nostr`
|
|
log targets to `info` whenever the effective log level is below
|
|
`trace`, so that `RUST_LOG=debug` does not flood the journal with raw
|
|
relay frames. To see those frames, set the level to `trace`.
|
|
|
|
## Files
|
|
|
|
`fips` looks for `fips.yaml` in the following locations, lowest to
|
|
highest priority. All present files are merged in priority order; the
|
|
highest-priority value wins.
|
|
|
|
| Priority | Path | Purpose |
|
|
| -------- | ---- | ------- |
|
|
| 1 | `/usr/local/etc/fips/fips.yaml` (macOS, FreeBSD), `C:\ProgramData\fips\fips.yaml` (Windows), `/etc/fips/fips.yaml` (other Unix) | System-wide defaults |
|
|
| 2 | `~/.config/fips/fips.yaml` (`%APPDATA%\fips\fips.yaml` on Windows) | User preferences |
|
|
| 3 | `~/.fips.yaml` | Legacy user config |
|
|
| 4 | `./fips.yaml` | Deployment-specific overrides |
|
|
|
|
On macOS and FreeBSD both system directories are probed: `/etc/fips`
|
|
first, then `/usr/local/etc/fips`, so the packaged file wins over a
|
|
leftover `/etc/fips` copy from an earlier install. Windows likewise
|
|
probes `\etc\fips` on the current drive, then `C:\ProgramData\fips`.
|
|
|
|
Adjacent to the highest-priority config file the daemon reads (or
|
|
writes, on first start) the identity files:
|
|
|
|
| File | Mode | Purpose |
|
|
| ---- | ---- | ------- |
|
|
| `fips.key` | `0600` | Bech32 nsec for the persistent identity (Unix; on Windows the file takes its directory's ACL, which `install-service.ps1` restricts to SYSTEM and Administrators). |
|
|
| `fips.pub` | `0644` | Bech32 npub corresponding to `fips.key`. |
|
|
|
|
When `node.identity.persistent` is `false` (the default), a fresh
|
|
keypair is written to these files on every start.
|
|
|
|
On Windows the service writes its log to `C:\ProgramData\fips\fips.log`,
|
|
rolled at 10 MiB with four old files kept; a foreground run logs to the
|
|
console.
|
|
|
|
The control socket path is derived per
|
|
[control-socket.md](control-socket.md).
|
|
|
|
## See also
|
|
|
|
- [`fipsctl`](cli-fipsctl.md) — control-socket client.
|
|
- [`fipstop`](cli-fipstop.md) — live-status TUI.
|
|
- [configuration.md](configuration.md) — YAML reference.
|
|
- [control-socket.md](control-socket.md) — control-socket protocol.
|