Skip to content

TOTP DTMF Authentication#1057

Open
SigmaScott wants to merge 23 commits into
AllStarLink:masterfrom
SigmaScott:authcommands
Open

TOTP DTMF Authentication#1057
SigmaScott wants to merge 23 commits into
AllStarLink:masterfrom
SigmaScott:authcommands

Conversation

@SigmaScott
Copy link
Copy Markdown

@SigmaScott SigmaScott commented May 28, 2026

Add TOTP DTMF Authentication for app_rpt

Summary

Adds per-user, per-node TOTP (RFC 6238) authentication to app_rpt, allowing administrators to gate privileged DTMF commands behind a one-time password verified via any standard
authenticator app (Google Authenticator, Authy, FreeOTP, etc.).

Motivation

Previously, every DTMF function in rpt.conf was accessible to anyone who could key the radio — there was no concept of user-level access control. This feature introduces an a
uthentication layer so that sensitive control commands (e.g., system key/unkey, restart scripts) can be restricted to authorized operators.

What It Does

  • Defines an additive, privileged DTMF command set that becomes available only after a user authenticates via a 4-digit user ID + 6-digit TOTP code keyed over DTMF.
  • Sessions are per-node, single-user, sliding-timeout — active use refreshes the session; idle sessions expire automatically.
  • Configurable brute-force lockout (threshold + duration) protects against OTP guessing over the air.
  • Security-conscious on-air feedback: all failure modes (bad code, lockout, disabled) produce identical error tones — distinguishing details only appear in logs and CLI.
  • Two new Asterisk CLI commands: rpt auth show <node> and rpt auth logout <node>.

Configuration

  • rpt.conf: New auth_* keys on the node stanza (auth_users, auth_timeout, auth_lockout_threshold, auth_lockout_duration, auth_otp_step, auth_otp_window), pl
    us function table entries for login/status/logout sub-commands.
  • rpt_auth.conf (new file): Maps 4-digit user IDs to base32 TOTP secrets and privileged function stanzas. Contains shared secrets — file permissions enforced (0640 root: asterisk).

Files Changed

File Change
apps/app_rpt/rpt_totp.{h,c} New — pure TOTP/HMAC-SHA1/base32 implementation.
apps/app_rpt/rpt_auth.{h,c} New — per-node auth session state, user table loader, lockout logic. Opaque state hung off struct rpt.
apps/app_rpt/rpt_functions.{h,c} New function_auth DTMF handler (login/status/logout sub-commands).
apps/app_rpt/app_rpt.h New config fields on struct rpt::p + opaque struct rpt_auth_state *auth pointer.
apps/app_rpt/rpt_config.c Config key registration (auth_*) and reload/free hooks.
apps/app_rpt.c function_table[] registration + collect_function_digits() modified for authed-stanza-first dispatch and sliding timeout touch.
apps/app_rpt/rpt_cli.c New rpt auth show / rpt auth logout CLI commands.
configs/rpt/rpt.conf Documented auth_* keys + example admin stanza.
configs/samples/rpt_auth.conf.sample New — user/secret file template.

Design Decisions

  • Opaque auth state — all auth internals are behind rpt_auth.c; no ABI churn for future extensions.
  • Minimal collect_function_digits surgery — authed-stanza walk is O(1) skip when no session is active; hot path impact is negligible for nodes that don't enable auth.
  • One session per node — simplifies dispatch and avoids per-channel session tracking. Extensible to multiple sessions if needed later.
  • Separate secrets filerpt.conf is widely shared/version-controlled; secrets stay in a permission-protected file with no network attack surface.

Testing

  • rpt_totp.c includes RPT_TOTP_SELFTEST validating against RFC 6238 Appendix B canonical SHA-1 test vectors.
  • End-to-end smoke test recipe provided in documentation (generate secret → configure → reload → DTMF login via CLI → verify session → privileged command → logout).

Summary by CodeRabbit

  • New Features

    • Per-user TOTP DTMF login (4-digit ID + 6-digit OTP), RFC-compliant verification with replay protection, configurable step/window, lockout controls, single active sliding session, session-refresh on successful dispatch, and auth-aware command routing with privileged command sets. OTP digits are never logged.
    • CLI commands to show node auth status and force logout.
  • Documentation

    • Admin/developer guide, config templates, and a sample users file with setup, permissions guidance, and an end-to-end test recipe.

Adds an optional RFC 6238 TOTP authentication mechanism that lets a user
unlock an additional, privileged DTMF command-set stanza for a sliding
session timeout, then drop back to the default command set on logout or
expiry.

Why
---
Until now every DTMF function in rpt.conf was reachable by anyone who
could key the radio. There was no way to gate privileged actions
(cop subcommands, shell-out cmd entries, link control) behind any kind
of per-user credential. This change introduces a minimal, self-contained
auth layer that uses a standard smartphone TOTP app (Google
Authenticator, Authy, FreeOTP, etc.) as the second factor, with no new
external dependencies (uses Asterisk's built-in SHA1 primitive).

Wire format
-----------
Admin picks a DTMF prefix and binds it to the new 'auth' function:

  *A<id4><otp6>   login   (4-digit user-id + 6-digit TOTP, no separator)
  *A*             logout
  *A              status  (courtesy tone only; details via CLI)

Behaviour
---------
- Per-node single session slot; second login displaces the first.
- Sliding timeout refreshed on every successful authed function dispatch.
- Authed-stanza walk runs FIRST in collect_function_digits(); on prefix
  collision the authed entry wins (admin's responsibility to avoid).
- All four failure modes (bad OTP / locked out / feature disabled /
  malformed input) return identical DC_ERROR so a caller cannot
  enumerate user state by listening to courtesy/error tones. Detail
  appears only in the Asterisk log and via the new CLI commands.
- Configurable lockout threshold and duration; threshold=0 disables.
- TOTP step and skew window are runtime-configurable per node so admins
  can tune for clock drift on field-deployed repeaters.

Security model
--------------
Shared secrets live in a separate file (path set per-node via
'auth_users') so they do not leak through the widely-shared rpt.conf.
The file is plain base32 protected by filesystem permissions
(0640 root:asterisk recommended). OTP digits are never logged; only
user-id, result code, and reason are. Constant-time OTP comparison was
considered and deliberately not added: the DTMF channel makes the
timing side-channel non-exploitable in practice (documented inline).

New files
---------
  apps/app_rpt/rpt_totp.{c,h}          RFC 6238 + HMAC-SHA1 + base32
  apps/app_rpt/rpt_auth.{c,h}          session/lockout/file-load layer
  configs/samples/rpt_auth.conf.sample documented user-secret file
  adminauth.md                         admin & developer guide

Modified files
--------------
  apps/app_rpt/app_rpt.h               6 config fields + opaque auth
                                       state pointer on struct rpt
  apps/app_rpt/rpt_config.c            register auth_* keys; reload/free
                                       hooks at lock-release / teardown
  apps/app_rpt/rpt_functions.{h,c}     new function_auth top-level DTMF
                                       handler (Option A: not a cop
                                       sub-action, for discoverability
                                       and clean future growth)
  apps/app_rpt.c                       function_table[] registration;
                                       collect_function_digits() now
                                       walks authed stanza first,
                                       extends the longestfunc gate by
                                       the authed stanza length, and
                                       calls rpt_auth_touch() on every
                                       successful dispatch (sliding
                                       timeout)
  apps/app_rpt/rpt_cli.c               'rpt auth show <node>' and
                                       'rpt auth logout <node>' with
                                       node-name tab completion
  configs/rpt/rpt.conf                 documented auth_* keys + worked
                                       example showing prefix wiring
                                       and a [functions-admin] stanza

Build
-----
The existing apps/Makefile.diff uses $(wildcard app_rpt/rpt_*.c) so
the two new compilation units are picked up automatically; no Makefile
change required.

Verification
------------
See adminauth.md for an end-to-end smoke-test recipe (generate a
secret, render a QR code with qrencode, enrol on a phone authenticator,
drive logins via 'rpt fun <node> ...' and inspect via 'rpt auth show
<node>'). RFC 6238 Appendix B test vectors are validated by the
RPT_TOTP_SELFTEST block in rpt_totp.c (build with -DRPT_TOTP_SELFTEST
to enable).
app_rpt.h uses AST_MAX_EXTENSION (declared in asterisk/channel.h) in
struct rpt. rpt_auth.c was the only new translation unit that included
app_rpt.h without first pulling in channel.h, so it failed to build
against asterisk-22.x:

    app_rpt/app_rpt.h:1004:20: error: 'AST_MAX_EXTENSION' undeclared
        char exten[AST_MAX_EXTENSION];

Other rpt_*.c files that consume app_rpt.h (e.g. rpt_config.c) already
include asterisk/channel.h. Match that pattern.
The asterisk/sha1.h API is no longer exported by modern Asterisk,
causing an undefined symbol error (SHA1Result) at module load time.
Switch to OpenSSL's SHA1 API which Asterisk already depends on and
link app_rpt against -lcrypto.
…mpletes

When digits arrive one-at-a-time through the macro buffer, function_auth
matched on the bare 'A' prefix and returned DC_COMPLETEQUIET with an
empty digit buffer, treating it as a status query. The remaining 10
digits were then orphaned.

Return DC_INDETERMINATE for partial input (len 0 and 1-9) so the
framework keeps collecting until the full 10-digit login payload
(4-digit user-id + 6-digit OTP) or the single '*' logout arrives.
Replace the single A=auth prefix with three config entries using the
param field to select the sub-command:
  A1 = auth,a   (login — collects 10 trailing digits)
  A2 = auth,s   (status — fires immediately)
  A3 = auth,l   (logout — fires immediately)

This avoids the single-character prefix matching problem where the
framework fired function_auth on the first digit before the full
login payload arrived. Each sub-command now has a distinct multi-char
prefix so collect_function_digits waits for the complete prefix.

Update adminauth.md to reflect the new wire format, config, usage
examples, and developer documentation.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dd49268b-9f6c-461a-aa8c-260258d1c108

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Adds per-user TOTP authentication over DTMF with RFC‑6238 verification, per-node single-session lifecycle (touch/expiry/lockout/reload), authed-first privileged-stanza dispatch, DTMF login/logout/status handler, CLI controls, config and build wiring, and documentation/sample configs.

Changes

Per-user TOTP authentication

Layer / File(s) Summary
TOTP cryptographic foundation
apps/app_rpt/rpt_totp.h, apps/app_rpt/rpt_totp.c
RFC 6238 TOTP-SHA1 implementation with Base32 decoding, HMAC-SHA1, RFC4226 truncation, windowed counter scanning, replay detection, and optional self-test.
Authentication state and session management
apps/app_rpt/rpt_auth.h, apps/app_rpt/rpt_auth.c
Per-node single active session, user-table loading from rpt_auth.conf, per-user last-counter and failure/lockout tracking, login/logout/status/touch/reload/free APIs, and cached longest-function length for authed dispatch.
App struct and configuration integration
apps/app_rpt/app_rpt.h, apps/app_rpt/rpt_config.c
Adds struct rpt *auth and auth_* config fields; parses/clamps auth parameters from rpt.conf; calls rpt_auth_reload after reload; frees auth state on teardown.
Dispatch integration and app_rpt wiring
apps/app_rpt.c
Includes rpt_auth.h, registers auth function, prefers active authenticated stanza in collect_function_digits() via case-insensitive prefix scan, extends minimum-digit gate with auth longest-func, and calls rpt_auth_touch() on successful dispatch.
DTMF handler for login/logout/status
apps/app_rpt/rpt_functions.h, apps/app_rpt/rpt_functions.c
Adds function_auth() implementing login (4-digit user ID + 6-digit OTP), logout, and status subcommands; enforces input widths and returns DC_INDETERMINATE while collecting.
CLI commands
apps/app_rpt/rpt_cli.c
Adds rpt auth show <node> and rpt auth logout <node> handlers and registers them in the CLI table.
Documentation, build, and sample configuration
adminauth.md, apps/Makefile, configs/rpt/rpt.conf, configs/samples/rpt_auth.conf.sample, .gitignore
Admin/developer guide and test recipe, sample rpt_auth.conf, rpt.conf template examples, Makefile change to link -lcrypto, and .gitignore additions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • mkmer
  • ve7fet
  • okcrum
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'TOTP DTMF Authentication' clearly and concisely describes the primary feature added: per-user TOTP authentication for DTMF command dispatch, which is the main objective of the entire changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/app_rpt.c (1)

1651-1715: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Make auth resolution and privileged dispatch atomic.

This authorizes the command by selecting the authenticated stanza, then executes the resolved handler later with no lock held. A concurrent rpt auth logout <node> can clear the session after the stanza match and before Line 1715, so one privileged command can still slip through after logout/expiry. Please move the auth decision into an API that also guards dispatch, or revalidate against an auth generation/token immediately before invoking the handler.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app_rpt.c` around lines 1651 - 1715, The code currently selects
authed_stanza via rpt_auth_active_set(myrpt) and later calls the resolved
handler (*function_table[i].function) without holding the auth lock, allowing a
concurrent rpt auth logout to invalidate the session between match and dispatch;
fix by making auth resolution and dispatch atomic: either add or use an API that
both resolves the correct stanza and invokes the handler under the same auth
guard (e.g. create rpt_auth_validate_and_dispatch(myrpt, vp->name, handler,
param, functiondigits, command_source, mylink) or extend rpt_auth_active_set to
return a token/generation and then revalidate that token immediately before
calling rpt_function_lookup()/function_table[i].function), ensuring you
reference authed_stanza/rpt_auth_active_set, vp->name, rpt_function_lookup,
function_table[i].function and rpt_auth_longestfunc when implementing the
guarded dispatch or token revalidation.
🧹 Nitpick comments (1)
apps/app_rpt/rpt_totp.h (1)

4-5: ⚡ Quick win

Update the dependency contract in this header.

These lines still say the implementation uses asterisk/sha1.h and has no OpenSSL dependency, but rpt_totp.c now includes <openssl/sha.h> and this feature links -lcrypto. Leaving this stale will mislead maintainers and packagers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app_rpt/rpt_totp.h` around lines 4 - 5, Update the header comment in
rpt_totp.h to reflect the current dependency contract: replace the claim that
the implementation only depends on Asterisk's <asterisk/sha1.h> and standard C
with a statement that rpt_totp.c now includes <openssl/sha.h> and the feature
requires linking against OpenSSL libcrypto (e.g., -lcrypto); ensure the comment
mentions both the OpenSSL header and the link-time dependency so packagers and
maintainers are not misled.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@adminauth.md`:
- Around line 293-296: Update the documentation in the rpt_totp.c section to
reflect the current implementation: replace the paragraph that claims Asterisk's
asterisk/sha1.h was used and OpenSSL avoided with a clear statement that
OpenSSL/libcrypto is used (per Makefile and commits) because Asterisk no longer
exports asterisk/sha1.h; mention rpt_totp.c and the Makefile as the sources of
truth and remove the outdated rationale about avoiding external deps.
- Line 276: Update the stale documentation in adminauth.md for "Design goal `#9`"
to remove the claim "No OpenSSL, no libcrypt" and explicitly state that the
project depends on OpenSSL's libcrypto for SHA1 (reference the Makefile linking
against -lcrypto and the change from asterisk/sha1.h to OpenSSL SHA1 in the
commit history); mention that asterisk/sha1.h is no longer exported so the
implementation uses OpenSSL SHA1 and ensure the rationale and current dependency
are clearly documented.

In `@apps/app_rpt.c`:
- Around line 1718-1721: The code currently calls rpt_auth_touch(myrpt) for any
successful dispatch (rv == DC_COMPLETE || rv == DC_COMPLETEQUIET || rv ==
DC_DOKEY) which extends auth sessions for public commands; change the condition
so rpt_auth_touch(myrpt) is only invoked when the dispatch came from an
authenticated/privileged source (i.e., the match was from the auth-specific
stanza or an authenticated session) rather than the normal source stanza—keep
the rv checks (DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY) but add a guard that
verifies the dispatch context indicates an authenticated/privileged match (e.g.,
check the dispatch/source/auth-session flag used in your dispatch code) before
calling rpt_auth_touch(myrpt).

In `@apps/app_rpt/rpt_auth.c`:
- Around line 449-452: The log reads u->command_set after calling
rpt_mutex_unlock(&myrpt->lock), which can race with
rpt_auth_reload()/rpt_auth_free() and dereference freed memory; fix by capturing
the command_set string while still holding the lock (e.g., strdup/copy into a
local buffer) or move the ast_log call to before rpt_mutex_unlock, then use that
local copy (and free it after unlocking) when calling ast_log so you never
access u->command_set after releasing myrpt->lock.
- Around line 334-352: rpt_auth_active_set() currently returns a raw pointer
into st->session_command_set after releasing myrpt->lock, creating a
use-after-free risk when rpt_auth_logout()/rpt_auth_reload() free it; change
rpt_auth_active_set() to return a caller-owned copy (e.g., strdup of
st->session_command_set) or accept a caller-provided buffer to copy into, and
update callers such as collect_function_digits() to free the returned string (or
supply a buffer) accordingly; keep the locking and expiry checks (use
clear_session_locked()) but ensure any pointer returned is heap-allocated and
documented as caller-owned so no dereference occurs after the lock is released.

In `@apps/app_rpt/rpt_config.c`:
- Line 680: The code currently frees the live authentication state (myrpt->auth)
during reload (via rpt_free_config_vars()/rpt_auth_free()) then recreates it
with rpt_auth_reload(), which logs out the active operator and clears lockout
data; instead, change load_rpt_vars() so it does NOT call rpt_auth_free() or let
rpt_free_config_vars() free myrpt->auth during a normal reload—instead update
the existing auth state in place by calling rpt_auth_reload() against
myrpt->auth (or add a flag to rpt_free_config_vars() to preserve auth on
reload); keep rpt_auth_free() only for final teardown. Target symbols:
load_rpt_vars, rpt_free_config_vars, rpt_auth_reload, rpt_auth_free,
myrpt->auth.

In `@apps/app_rpt/rpt_functions.c`:
- Around line 2037-2040: The status subcommand currently always reports COMPLETE
and returns DC_COMPLETEQUIET without checking authentication; update the branch
handling subcmd "s" to consult the auth layer before emitting telemetry and
returning. Specifically, call the appropriate auth check (e.g.,
auth_session_is_authenticated(command_source) or rpt_auth_get_status(myrpt,
command_source)) and if authenticated invoke rpt_telem_select(...) and
rpt_telemetry(...) with the success status and return DC_COMPLETEQUIET,
otherwise emit a telemetry status for auth failure (e.g., rpt_telemetry(myrpt,
AUTH_REQUIRED, NULL) or similar) and return the correct error code (e.g.,
DC_DENIED or DC_AUTHFAIL). Ensure you reference and use the existing symbols
rpt_telem_select, rpt_telemetry, myrpt, and command_source when inserting the
auth check and conditional behavior.
- Around line 2031-2033: The current check uses myrpt->remote to reject auth,
which is incorrect because non-local command sources (link/phone/EchoLink/TLB)
still arrive here; change the gate to reject based on the actual command source
instead: replace the myrpt->remote check with a condition that inspects
command_source (and mylink where appropriate) so only truly local sources are
allowed to authenticate; adjust the logic in the login/logout/status handlers in
rpt_functions.c to use command_source (and test mylink for linked callers)
before returning DC_ERROR for non-local auth attempts.

In `@apps/app_rpt/rpt_totp.c`:
- Around line 75-81: In rpt_base32_decode, stop accepting input at the first '='
only if the rest of the input contains nothing but padding; currently the loop
breaks on '=' and returns success even when trailing garbage follows (e.g.,
"JBSWY3DP=garbage"). Change the logic inside the loop (the for over p and the
branch that checks c == '=') so that when you hit '=', you scan the remainder of
in from p to the terminator and if any character other than '=' is found you
return failure (use the function's existing error return path), otherwise treat
the trailing '='s as valid padding and proceed; ensure you reference and update
the same control flow used around p/in in rpt_base32_decode so callers keep the
same semantics on valid input.

In `@configs/rpt/rpt.conf`:
- Around line 519-550: The example in configs/rpt/rpt.conf is inconsistent with
function_auth() behavior: change the single wildcard entry "*A = auth," into
three explicit function-table entries (e.g., "A1 = auth,a", "A2 = auth,s", "A3 =
auth,l") and update the wire-format examples to match adminauth.md and
apps/app_rpt/rpt_functions.c (i.e., "*A1<id4><otp6>" for login, "*A2" for
status, "*A3" for logout) so that function_auth() correctly dispatches login
(param "a"), status (param "s"), and logout (param "l").

---

Outside diff comments:
In `@apps/app_rpt.c`:
- Around line 1651-1715: The code currently selects authed_stanza via
rpt_auth_active_set(myrpt) and later calls the resolved handler
(*function_table[i].function) without holding the auth lock, allowing a
concurrent rpt auth logout to invalidate the session between match and dispatch;
fix by making auth resolution and dispatch atomic: either add or use an API that
both resolves the correct stanza and invokes the handler under the same auth
guard (e.g. create rpt_auth_validate_and_dispatch(myrpt, vp->name, handler,
param, functiondigits, command_source, mylink) or extend rpt_auth_active_set to
return a token/generation and then revalidate that token immediately before
calling rpt_function_lookup()/function_table[i].function), ensuring you
reference authed_stanza/rpt_auth_active_set, vp->name, rpt_function_lookup,
function_table[i].function and rpt_auth_longestfunc when implementing the
guarded dispatch or token revalidation.

---

Nitpick comments:
In `@apps/app_rpt/rpt_totp.h`:
- Around line 4-5: Update the header comment in rpt_totp.h to reflect the
current dependency contract: replace the claim that the implementation only
depends on Asterisk's <asterisk/sha1.h> and standard C with a statement that
rpt_totp.c now includes <openssl/sha.h> and the feature requires linking against
OpenSSL libcrypto (e.g., -lcrypto); ensure the comment mentions both the OpenSSL
header and the link-time dependency so packagers and maintainers are not misled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 84e2bcec-8a0c-4598-a977-80156dfb8f08

📥 Commits

Reviewing files that changed from the base of the PR and between 0d593ef and 0e27dd5.

📒 Files selected for processing (14)
  • adminauth.md
  • apps/Makefile.diff
  • apps/app_rpt.c
  • apps/app_rpt/app_rpt.h
  • apps/app_rpt/rpt_auth.c
  • apps/app_rpt/rpt_auth.h
  • apps/app_rpt/rpt_cli.c
  • apps/app_rpt/rpt_config.c
  • apps/app_rpt/rpt_functions.c
  • apps/app_rpt/rpt_functions.h
  • apps/app_rpt/rpt_totp.c
  • apps/app_rpt/rpt_totp.h
  • configs/rpt/rpt.conf
  • configs/samples/rpt_auth.conf.sample

Comment thread adminauth.md
Comment thread adminauth.md
Comment thread apps/app_rpt.c
Comment thread apps/app_rpt/rpt_auth.c Outdated
Comment thread apps/app_rpt/rpt_auth.c Outdated
Comment thread apps/app_rpt/rpt_config.c
myrpt->p.ldisc_buf = NULL;
}

rpt_auth_free(myrpt);
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot May 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Don't tear down live auth state on every reload.

load_rpt_vars() now frees myrpt->auth through rpt_free_config_vars() and then recreates it with rpt_auth_reload(). That logs out the active operator and clears any in-flight lockout whenever rpt.conf is reloaded, which undermines the new session and brute-force protections during normal reloads. Keep rpt_auth_free() for final teardown, and let reload update the existing auth state in place.

Also applies to: 1331-1331

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app_rpt/rpt_config.c` at line 680, The code currently frees the live
authentication state (myrpt->auth) during reload (via
rpt_free_config_vars()/rpt_auth_free()) then recreates it with
rpt_auth_reload(), which logs out the active operator and clears lockout data;
instead, change load_rpt_vars() so it does NOT call rpt_auth_free() or let
rpt_free_config_vars() free myrpt->auth during a normal reload—instead update
the existing auth state in place by calling rpt_auth_reload() against
myrpt->auth (or add a flag to rpt_free_config_vars() to preserve auth on
reload); keep rpt_auth_free() only for final teardown. Target symbols:
load_rpt_vars, rpt_free_config_vars, rpt_auth_reload, rpt_auth_free,
myrpt->auth.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes a user would be de-authenticated if the app_rpt was reloaded. Reloading apt_rpt is an infrequent activity on a stable system and this behavior was design decision to require a user to re-auth if this did happen.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SigmaScott, understood — that's a reasonable design choice. Clearing the session on reload provides a clean slate and avoids stale session state after a configuration change, at the cost of requiring the operator to re-authenticate. Acknowledged.


✏️ Learnings added
Learnt from: SigmaScott
Repo: AllStarLink/app_rpt PR: 1057
File: apps/app_rpt/rpt_config.c:680-680
Timestamp: 2026-05-28T19:43:49.756Z
Learning: In AllStarLink/app_rpt PR `#1057`, de-authenticating the active TOTP session (and clearing lockout state) on `app_rpt` reload via `rpt_free_config_vars()` → `rpt_auth_free()` is an **intentional design decision**. The rationale is that `app_rpt` reloads are infrequent on stable systems, and requiring a user to re-authenticate after a reload is acceptable and preferred to carrying over stale session state. Do not flag this as a bug or suggest preserving auth state across reloads.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: mkmer
Repo: AllStarLink/app_rpt PR: 929
File: res/res_rpt_http_registrations.c:219-240
Timestamp: 2026-02-05T14:40:39.509Z
Learning: In the AllStarLink/app_rpt codebase, ensure return values from ast_str_set and ast_str_append are checked and errors are handled or propagated. Do not assume success; handle failures to avoid silent partial strings. Apply this guidance broadly across all C files in the repository (e.g., res/**/*.c) where these functions are used.

Learnt from: mkmer
Repo: AllStarLink/app_rpt PR: 964
File: apps/app_rpt/rpt_bridging.c:229-229
Timestamp: 2026-03-04T15:24:06.975Z
Learning: Guideline: In the AllStarLink/app_rpt codebase, preserve blank CallerID (empty string "") for internal repeater Rx/Tx infrastructure calls, specifically in rpt_bridging.c's __rpt_request when passing the node argument. Only outbound link call sites (e.g., in rpt_link.c and rpt_link_connect) should supply a meaningful CallerID (such as l->name) to identify the remote node. This helps distinguish internal channels from external links. When auditing or modifying bridging and link code, ensure internal calls continue to pass "" for node, and validate that only outbound link paths populate CallerID. This pattern should apply to all relevant .c files within apps/app_rpt. 

Comment thread apps/app_rpt/rpt_functions.c
Comment thread apps/app_rpt/rpt_functions.c
Comment thread apps/app_rpt/rpt_totp.c
Comment thread configs/rpt/rpt.conf Outdated
SigmaScott and others added 2 commits May 28, 2026 16:59
… example)

- rpt_auth.c: move ast_log before unlock in rpt_auth_login() to prevent
  use-after-free of u->command_set on concurrent reload
- rpt_totp.h: update header comment to reflect OpenSSL dependency
- adminauth.md: update design goal AllStarLink#9 and §2.3 to reflect OpenSSL/libcrypto
  usage (asterisk/sha1.h is no longer exported)
- rpt.conf: fix auth example to use three explicit function table entries
  (A1=auth,a / A2=auth,s / A3=auth,l) matching function_auth() dispatch

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@Allan-N Allan-N added the enhancement New feature or request label May 28, 2026
Comment thread apps/app_rpt/rpt_totp.c Outdated
Comment thread apps/app_rpt/rpt_totp.c
…ecode

When '=' is encountered, validate that only '=' characters follow.
Previously, input like "JBSWY3DP=garbage" would silently succeed;
now it returns -1 (error) for strict RFC 4648 conformance.
rpt_auth_active_set() previously returned a raw pointer into auth state
after releasing myrpt->lock. The CLI 'rpt auth logout' handler runs on a
separate thread and could free session_command_set between the unlock and
the caller's ast_variable_browse() dereference.

Change the API to copy the stanza name into a caller-provided buffer while
still holding the lock, matching the existing function_table_name pattern
in collect_function_digits().
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

Comment thread apps/app_rpt/rpt_auth.h Outdated
Comment thread apps/app_rpt/rpt_auth.c Outdated
Comment thread apps/app_rpt/rpt_auth.c
Comment thread apps/app_rpt/rpt_auth.c Outdated
Also simplify parse_user_value() using strsep/ast_strip/ast_strdup
instead of manual pointer arithmetic. Same semantics, 21 fewer lines.
Copy link
Copy Markdown
Collaborator

@mkmer mkmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very well done!

Comment thread apps/app_rpt/rpt_config.c
@mkmer
Copy link
Copy Markdown
Collaborator

mkmer commented May 29, 2026

Most of these errors can be "fixed" locally by running the pre-commit hook scripts (and activating them while working). Instructions are in the readme.

…AC API

Replaces manual ipad/opad HMAC construction using deprecated
SHA1_Init/SHA1_Update/SHA1_Final with the modern EVP_MAC interface.
OpenSSL handles HMAC internals; no deprecation warnings on OpenSSL 3.x.
…list

The user table is now allocated to exactly the number of entries in
rpt_auth.conf, eliminating the hard RPT_AUTH_MAX_USERS cap and avoiding
unused memory allocation for typical deployments with few users.
- adminauth.md: replace stale references to openssl/sha.h and manual
  HMAC construction with accurate EVP_MAC API description
- rpt_auth.conf.sample: remove 64-user cap note (now dynamic)
Comment thread configs/rpt/rpt.conf Outdated
;
;auth_users = /etc/asterisk/rpt_auth.conf ; Path to user/secret file. Unset = feature disabled.
;auth_timeout = 300 ; Sliding session timeout, seconds. Range 30..86400, default 300.
;auth_lockout_threshold = 5 ; Failed-login attempts before lockout. 0 disables lockout. Range 0..1000.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the default value?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 is the default. I will update this.

Comment thread configs/rpt/rpt.conf Outdated

[functions](functions-main)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking that this block may be a bit too much documentation for the rpt.conf file. Seems like the ASL Manual would be a better place for the details. Should we limit the rpt.conf content to just :

; Enable/disable functions requiring authentication
; A1 = auth,a        ; login:  *A1<id4><otp6>  e.g. *A11234849203
; A2 = auth,s        ; status: *A2             (courtesy tone only; details via "rpt auth show <node>")
; A3 = auth,l        ; logout: *A3

Also, do these function definitions belong a few lines up (in [node-main](!))?

Comment thread apps/app_rpt.c Outdated
int i, rv;
char *stringp, *action, *param, *functiondigits;
char function_table_name[30] = "";
char authed_stanza_buf[30] = "";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authed_table_name ?

Comment thread apps/app_rpt/rpt_functions.c Outdated
return DC_ERROR;
}
for (i = 0; i < 10; i++) {
if (digits[i] < '0' || digits[i] > '9') {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be :

		if (!isdigit(digits[i])) {

Comment thread apps/app_rpt/rpt_auth.c Outdated
return 0;
}
for (i = 0; i < RPT_AUTH_USER_ID_LEN; i++) {
if (name[i] < '0' || name[i] > '9') {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use isdigit() ?

- Replace manual '0'-'9' range checks with isdigit() in rpt_totp.c,
  rpt_auth.c, and rpt_functions.c for consistency with rest of codebase
- Add #include <ctype.h> to files using isdigit()
- Rename authed_stanza_buf to authed_function_table_name in
  collect_function_digits() for consistency with function_table_name
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
apps/app_rpt/rpt_totp.c (3)

235-254: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

The window self-test is generating the current-step OTP, not the previous-step one.

At now = 59 with a 30-second step, the active counter is 1, so totp_at(..., 1) should pass even with window=0. This assertion only makes sense if you generate counter 0 here.

Suggested fix
-		prev_step_otp = (keylen > 0) ? totp_at(key, (size_t) keylen, 1) : -1;
+		prev_step_otp = (keylen > 0) ? totp_at(key, (size_t) keylen, 0) : -1;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app_rpt/rpt_totp.c` around lines 235 - 254, The self-test is generating
the current-step OTP (using totp_at(..., 1)) but then expects behavior for the
previous-step OTP; change the counter passed to totp_at to 0 so prev_step_otp
represents the prior time-step, i.e. replace totp_at(key, (size_t) keylen, 1)
with totp_at(key, (size_t) keylen, 0) when computing prev_step_otp used by
rpt_totp_verify(secret, buf, &last, 59, 30, ...).

92-103: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject non-zero trailing bits in the last Base32 quantum.

This decoder still accepts malformed secrets like AB====== by emitting the same bytes as AA====== and ignoring the leftover non-zero bits. For auth secrets, that should fail closed.

Suggested fix
 	}
 
+	if (bits > 0 && (buf & (((size_t)1 << bits) - 1)) != 0) {
+		return -1;
+	}
+
 	return (int) written;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app_rpt/rpt_totp.c` around lines 92 - 103, The decoder currently ignores
leftover non-zero bits in the final Base32 quantum (variables buf and bits),
allowing malformed inputs like "AB======"; modify the end of the decode routine
in rpt_totp.c so that after the loop completes you check if bits > 0 and that
the low (bits) bits of buf are zero, and if not return an error (e.g., -1)
instead of accepting the input; update any callers that rely on the return value
if necessary and keep the existing behavior for perfectly aligned inputs where
bits == 0 (use the variables buf, bits, written, out, outlen, v to locate the
logic).

155-190: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Securely clear decoded TOTP secret (key) on all exit paths in rpt_totp_verify.

rpt_totp_verify returns RPT_TOTP_BAD_SECRET immediately after keylen = rpt_base32_decode(...) when keylen <= 0 (lines ~155-158), without wiping the stack buffer uint8_t key[64]. Since rpt_base32_decode can write partial output to key before encountering an error, this leaves sensitive material uncleared. Unify cleanup so every return zeroizes key, and replace the current plain memset(key, 0, sizeof(key)) usage with a guaranteed zeroization primitive (e.g., memset_s / explicit_bzero / OPENSSL_cleanse) or a local secure-wipe wrapper.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app_rpt/rpt_totp.c` around lines 155 - 190, The function rpt_totp_verify
leaves partially-decoded secret bytes in the local uint8_t key[64] on some early
returns (notably after rpt_base32_decode when keylen <= 0); ensure key is
securely zeroed on every exit: replace direct memset(key, 0, ...) with a
guaranteed zeroization primitive (explicit_bzero / OPENSSL_cleanse / memset_s or
a local secure_wipe wrapper) and either call that secure_wipe before each return
(including the RPT_TOTP_BAD_SECRET return immediately after rpt_base32_decode
and the RPT_TOTP_BAD_PARAM/RPT_TOTP_REPLAY/RPT_TOTP_OK returns inside the loop)
or centralize cleanup via a single exit label (e.g., goto cleanup) that invokes
secure_wipe(key, sizeof key) then returns; reference the local buffer key, the
rpt_base32_decode call, the totp_at call, and the existing memset usages to
locate all return paths to update.
apps/app_rpt/rpt_auth.c (1)

347-357: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Expire stale sessions in every accessor, not just rpt_auth_get_active_stanza().

Right now timeout cleanup only happens in rpt_auth_get_active_stanza(). After the idle window passes, rpt_auth_longestfunc() still returns the cached privileged length and rpt_auth_touch() can extend the same stale slot instead of expiring it first. Per the stack context, collect_function_digits() uses rpt_auth_longestfunc() in its digit gate, so a timed-out auth session can keep affecting command collection after it should be gone.

A small shared expire_session_if_needed_locked() helper used by get_active_stanza, touch, longestfunc, and status would keep the auth state consistent.

🛠️ Possible fix
+static int expire_session_if_needed_locked(struct rpt *myrpt, struct rpt_auth_state *st, time_t now)
+{
+	if (!st || !st->session_active || now < st->session_expires) {
+		return 0;
+	}
+
+	ast_log(LOG_NOTICE, "rpt_auth: session for user %s expired on node %s\n",
+		st->session_user, myrpt->name);
+	clear_session_locked(st);
+	return 1;
+}
+
 int rpt_auth_longestfunc(struct rpt *myrpt)
 {
 	struct rpt_auth_state *st;
 	int ret = 0;
+	time_t now = time(NULL);
 
 	rpt_mutex_lock(&myrpt->lock);
 	st = myrpt->auth;
-	if (st && st->session_active) {
+	if (st && !expire_session_if_needed_locked(myrpt, st, now) && st->session_active) {
 		ret = st->session_longestfunc;
 	}
 	rpt_mutex_unlock(&myrpt->lock);
 	return ret;
 }
 
 void rpt_auth_touch(struct rpt *myrpt)
 {
 	struct rpt_auth_state *st;
 	time_t now = time(NULL);
 
 	rpt_mutex_lock(&myrpt->lock);
 	st = myrpt->auth;
-	if (st && st->session_active) {
+	if (st && !expire_session_if_needed_locked(myrpt, st, now) && st->session_active) {
 		st->session_expires = now + effective_timeout(myrpt);
 	}
 	rpt_mutex_unlock(&myrpt->lock);
 }

Also applies to: 360-370, 463-485

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/app_rpt/rpt_auth.c` around lines 347 - 357, Add a shared helper
expire_session_if_needed_locked(struct rpt *myrpt, struct rpt_auth_state *st)
that must be called while holding myrpt->lock: it should check current time vs
st->session_expires and, if expired, clear/disable the session (set
st->session_active false and reset any cached privileged fields used by
rpt_auth_longestfunc/status). Replace the timeout-checking logic in
rpt_auth_get_active_stanza, rpt_auth_touch, rpt_auth_longestfunc, and the status
path to call expire_session_if_needed_locked(...) while locked before
using/refreshing st so stale sessions are always expired first and cannot be
extended or read. Ensure rpt_auth_touch still updates session_expires only when
session_active remains true after the expire check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@configs/rpt/rpt.conf`:
- Around line 472-481: The stanza names in this template ([totp-admin] and
[totp-operator]) do not match the shipped auth examples (which use
functions-admin / functions-controlop / functions-diag); rename the sections in
this file to use the exact stanza names from rpt_auth.conf (e.g., change
[totp-admin] -> [functions-admin] and [totp-operator] -> [functions-controlop])
so authenticated users map to the correct command-set stanzas, and ensure any
commented command entries (e.g., the cop lines) remain under the updated stanza
names.

---

Outside diff comments:
In `@apps/app_rpt/rpt_auth.c`:
- Around line 347-357: Add a shared helper
expire_session_if_needed_locked(struct rpt *myrpt, struct rpt_auth_state *st)
that must be called while holding myrpt->lock: it should check current time vs
st->session_expires and, if expired, clear/disable the session (set
st->session_active false and reset any cached privileged fields used by
rpt_auth_longestfunc/status). Replace the timeout-checking logic in
rpt_auth_get_active_stanza, rpt_auth_touch, rpt_auth_longestfunc, and the status
path to call expire_session_if_needed_locked(...) while locked before
using/refreshing st so stale sessions are always expired first and cannot be
extended or read. Ensure rpt_auth_touch still updates session_expires only when
session_active remains true after the expire check.

In `@apps/app_rpt/rpt_totp.c`:
- Around line 235-254: The self-test is generating the current-step OTP (using
totp_at(..., 1)) but then expects behavior for the previous-step OTP; change the
counter passed to totp_at to 0 so prev_step_otp represents the prior time-step,
i.e. replace totp_at(key, (size_t) keylen, 1) with totp_at(key, (size_t) keylen,
0) when computing prev_step_otp used by rpt_totp_verify(secret, buf, &last, 59,
30, ...).
- Around line 92-103: The decoder currently ignores leftover non-zero bits in
the final Base32 quantum (variables buf and bits), allowing malformed inputs
like "AB======"; modify the end of the decode routine in rpt_totp.c so that
after the loop completes you check if bits > 0 and that the low (bits) bits of
buf are zero, and if not return an error (e.g., -1) instead of accepting the
input; update any callers that rely on the return value if necessary and keep
the existing behavior for perfectly aligned inputs where bits == 0 (use the
variables buf, bits, written, out, outlen, v to locate the logic).
- Around line 155-190: The function rpt_totp_verify leaves partially-decoded
secret bytes in the local uint8_t key[64] on some early returns (notably after
rpt_base32_decode when keylen <= 0); ensure key is securely zeroed on every
exit: replace direct memset(key, 0, ...) with a guaranteed zeroization primitive
(explicit_bzero / OPENSSL_cleanse / memset_s or a local secure_wipe wrapper) and
either call that secure_wipe before each return (including the
RPT_TOTP_BAD_SECRET return immediately after rpt_base32_decode and the
RPT_TOTP_BAD_PARAM/RPT_TOTP_REPLAY/RPT_TOTP_OK returns inside the loop) or
centralize cleanup via a single exit label (e.g., goto cleanup) that invokes
secure_wipe(key, sizeof key) then returns; reference the local buffer key, the
rpt_base32_decode call, the totp_at call, and the existing memset usages to
locate all return paths to update.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b929b9dd-96ee-42f1-9406-a427a55702ee

📥 Commits

Reviewing files that changed from the base of the PR and between 0e27dd5 and a1791e2.

📒 Files selected for processing (12)
  • .gitignore
  • adminauth.md
  • apps/app_rpt.c
  • apps/app_rpt/app_rpt.h
  • apps/app_rpt/rpt_auth.c
  • apps/app_rpt/rpt_auth.h
  • apps/app_rpt/rpt_functions.c
  • apps/app_rpt/rpt_totp.c
  • apps/app_rpt/rpt_totp.h
  • configs/rpt/rpt.conf
  • configs/rpt/rpt_auth.conf
  • configs/samples/rpt_auth.conf.sample
✅ Files skipped from review due to trivial changes (2)
  • .gitignore
  • adminauth.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/app_rpt/app_rpt.h
  • apps/app_rpt/rpt_totp.h
  • apps/app_rpt.c

Comment thread configs/rpt/rpt.conf
Comment on lines +472 to +481
;[totp-admin]
; Add commands here for users authenticated as admin
;901 = cop,1 ; System warm boot
;902 = cop,2 ; System enable
;903 = cop,3 ; System disable

;[totp-operator]
; Add commands here for users authenticated as operator.
;916 = cop,16 ; Scheduler disable

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the privileged stanza names consistent with the shipped rpt_auth.conf examples.

rpt_auth.conf and rpt_auth.conf.sample map users to functions-admin / functions-controlop / functions-diag, but this template defines [totp-admin] and [totp-operator]. Copying the examples as-is leaves authenticated users pointing at the wrong command-set stanza. Either rename these sections or update the auth-file examples so the names match exactly.

Suggested alignment
-;[totp-admin]
+;[functions-admin]
 ; Add commands here for users authenticated as admin
 ;901 = cop,1                        ; System warm boot
 ;902 = cop,2                        ; System enable
 ;903 = cop,3                        ; System disable
 
-;[totp-operator]
+;[functions-controlop]
 ; Add commands here for users authenticated as operator.
 ;916 = cop,16                       ; Scheduler disable
+
+;[functions-diag]
+; Add commands here for users authenticated as read-only diagnostics.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@configs/rpt/rpt.conf` around lines 472 - 481, The stanza names in this
template ([totp-admin] and [totp-operator]) do not match the shipped auth
examples (which use functions-admin / functions-controlop / functions-diag);
rename the sections in this file to use the exact stanza names from
rpt_auth.conf (e.g., change [totp-admin] -> [functions-admin] and
[totp-operator] -> [functions-controlop]) so authenticated users map to the
correct command-set stanzas, and ensure any commented command entries (e.g., the
cop lines) remain under the updated stanza names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants