Home / Alt manpages / sudo_logsrv.proto(5)

  • sudo_logsrv.proto(5)
  • File format
  • linux

Trace Sudo Remote Logging from sudoers to the Wire

You will finish with a checked mental model and a small configuration path for Sudo remote logging: point sudo at a log server, understand which connection is TLS, and recognise the messages exchanged for one command. This is useful when you are implementing a compatible server or diagnosing why a remote log session stops. The examples match Sudo 1.9.15p5, installed here as package version 1.9.15p5-3ubuntu5.24.04.3.

Allow about 20 minutes. You need root access to edit the Sudo policy and log-server configuration, a running sudo_logsrvd, and a test command whose output is safe to record. The protocol document is not a configuration file: it describes Protocol Buffers messages and their wire framing. Do not paste its message definitions into sudoers.

1. Confirm the installed contract

Start with read-only checks. No elevated privilege is needed for these commands:

$ sudo -V | head -n 3
Sudo version 1.9.15p5
Sudoers policy plugin version 1.9.15p5
Sudoers file grammar version 50
$ sudo_logsrvd -V
sudo_logsrvd version 1.9.15p5

The local sudo_logsrv.proto(5) page is dated for Sudo 1.9.15p5 and says remote logging has been supported since Sudo 1.9.0. Keep the version beside your implementation notes. Message fields and optional behaviour can change between releases.

Checkpoint

If sudo_logsrvd is missing, stop here and install or build the matching Sudo log-server component through your normal package process. Do not substitute an arbitrary TCP listener; a compatible listener must understand the protocol.

2. Choose a log-server endpoint

The client-side log_servers setting contains one or more whitespace-separated addresses. The form is host[:port][(tls)]. Without a port, plaintext uses 30343 and TLS uses 30344. An IPv6 address must be enclosed in square brackets.

Defaults log_servers = logs.example.test:30344(tls)
Defaults log_server_timeout = 30

This is a policy change, so edit it with elevated privilege and use the normal syntax-checking workflow for your distribution. A safer deployment is a file under /etc/sudoers.d/, with a restricted mode and a name that sorts predictably. The exact include policy is controlled by your existing sudoers file.

On the server, the corresponding [server] section can listen on a TLS address:

[server]
listen_address = 0.0.0.0:30344(tls)
tls_cert = /etc/ssl/sudo/certs/logsrvd_cert.pem
tls_key = /etc/ssl/sudo/private/logsrvd_key.pem

Do not expose a wildcard listener casually. The documented default listens on all configured interfaces for both plaintext and TLS, and a TLS listener must have a certificate and private key that match your deployment. If the server validates client certificates, the client also needs its configured certificate and private key, and the server needs the relevant CA bundle.

Safety stop: changing log_servers can affect whether users can run commands. If no server is available, Sudo denies the command unless the relevant ignore_iolog_errors or ignore_log_errors policy allows continuation. Stage the change with a maintenance window and retain a console or root session for recovery.

3. Read the first half of the exchange

For a new connection, the client may begin with ClientHello, carrying a free-form client_id. The server then sends ServerHello. Its required server_id identifies the implementation; optional redirect tells the client to connect to another host and port, while servers can advertise known peers.

The client next sends exactly one of the messages that describes the command's initial state:

  • AcceptMessage means policy allowed the command. It includes the submission time, event information, and expect_iobufs, which tells the server whether I/O records will follow.
  • RejectMessage means policy denied it. It includes the submission time, a reason, and event information.
  • RestartMessage resumes an interrupted I/O log using the server's log_id and a previously acknowledged elapsed-time point.

These are alternatives. After an accept, the client must not send reject or restart; after a reject, it must not send accept or restart. This is a common implementation trap when reconnect logic is bolted onto the normal command path.

4. Validate the event fields you store

The event data is a repeated list of key-value InfoMessage entries. Values can be a 64-bit integer, a string, a list of strings, or a list of 64-bit integers. The protocol requires these keys: command, runuser, submithost, and submituser.

Useful optional keys include runargv, runcwd, runuid, submitcwd, submituid, ttyname, lines, and columns. Treat unknown keys as forward-compatible input. The server must accept them, although it may ignore them.

Do not confuse wall-clock and elapsed times. Submission and alert times are wall-clock values. I/O delays, command run time, and restart points are elapsed times from a monotonic clock where possible. A TimeSpec uses signed 64-bit seconds and 32-bit nanoseconds, so it can represent dates beyond 2038 when used as a wall-clock value.

5. Frame and finish I/O logging

Protocol Buffers supplies fields, not message boundaries. Each encoded message is therefore preceded by its wire size as a 32-bit unsigned integer in network byte order. Read exactly that prefix, convert it from network order, reject or report a message over two megabytes, then read exactly the declared payload before decoding it.

When expect_iobufs is true, the server creates an I/O log and replies with a log_id. The client can then send terminal input and output, standard input, standard output, standard error, window-size changes, and suspend or resume events. Each IoBuffer contains a delay since the previous record and binary data. Do not decode the data as text by default.

The server periodically sends a commit_point, which is an elapsed-time marker for records committed to storage. After the client sends ExitMessage, the server sends the final pending commit point before closing. A client resuming a session must use a commit point the server has previously seen. An unknown resume point is an error and the connection is dropped.

ClientHello -> ServerHello -> AcceptMessage
AcceptMessage with I/O -> log_id
zero or more I/O messages <- commit_point
ExitMessage <- final commit_point
connection closes

At any point the server can send error and close, or send abort, close, and instruct the client to terminate the running command. A server implementation must treat abort as a control decision, not merely as a log message.

6. Verify without losing the recovery path

Check the policy before testing a real command, then run a harmless command that produces no sensitive output:

$ sudo -l
$ sudo /usr/bin/true
$ printf 'exit status: %s\n' "$?"
exit status: 0

Inspect the log server's configured event and I/O destinations and look for the accepted event, its required fields, and the matching session identifier. A successful sudo exit alone does not prove that I/O data reached durable storage.

If the test fails, restore the previous sudoers fragment or comment out the new log_servers line, validate the policy, and retest locally. Do not delete existing logs while troubleshooting. If a live command is terminated by an abort or a broken connection, record the server error and correct availability or TLS configuration before retrying.

Done means

  • The installed Sudo and sudo_logsrvd versions are recorded.
  • The client endpoint, TLS choice, certificate paths, and timeout agree on both sides.
  • The policy was checked before a harmless test command was run.
  • Your implementation reads network-order length prefixes and enforces the two-megabyte message limit.
  • Accept, reject, restart, commit, error, and abort transitions are handled distinctly.
  • The test event and, when enabled, its I/O log can be found in the configured destinations.