Add a local unix socket for root on the server

jarld also listens on /run/jarl/jarl.sock (socket in jarl.yaml). Requests
on it from root or jarld's own user need no token and act as an
administrator; the kernel's SO_PEERCRED says who is connecting, and
anyone else must send a token. The jarl CLI uses the socket when no server
is configured, or with -s local, so 'sudo jarl status' works on the server
with nothing set up and a lost token or password never locks root out.
Changes are audited under the system user's name via "socket".

The systemd unit creates /run/jarl (0750). Socket paths over 107 bytes
are refused with a clear message. The docs explain the socket and what
happens when a token is revoked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-08 15:10:57 +00:00
1 parent f528c2aa9c
commit cf49df0346
22 files changed
+570 -26

No files matched your search

+8
View File
@@ -110,6 +110,14 @@ var errUnauthenticated = &httpError{http.StatusUnauthorized, "unauthenticated",
// cookie. For sessions, state-changing requests must carry the CSRF token.
func (s *Server) authenticate(r *http.Request) (*auth.Principal, *model.Session, error) {
ip := s.clientIP(r)
// On the local socket, root and jarld's own user need no token
// (socket.go). A token, if sent, is used as anywhere else.
if pr := peerOf(r.Context()); pr != nil && r.Header.Get("Authorization") == "" {
if trustedUID(pr.UID) {
return socketPrincipal(pr, r.UserAgent()), nil, nil
}
return nil, nil, socketDenied(pr)
}
if h := r.Header.Get("Authorization"); h != "" {
scheme, tok, _ := strings.Cut(h, " ")
if !strings.EqualFold(scheme, "Bearer") {