Summary
The Randnum key-file parsing logic is currently duplicated between:
bin/afppasswd/afppasswd.c
etc/uams/uams_randnum.c
Both files need to parse the same <afppasswd>.key format: exactly 16 hexadecimal characters representing an 8-byte DES key, with one optional trailing newline.
Recent hardening fixed both copies independently, but the duplication makes future drift likely. We should consolidate the shared parsing/validation logic into a common helper.
Background
Randnum uses a companion key file named <afppasswd>.key. The key file is read by both:
afppasswd, when creating/updating Randnum password entries
uams_randnum, when authenticating users or changing passwords at runtime
The logic now needs to enforce the same contract in both places:
- Accept exactly 16 hex characters
- Allow one optional trailing newline
- Reject short, long, non-hex, or otherwise malformed files
- Decode the hex into 8 bytes
- Wipe temporary buffers that may contain key material
- Avoid undefined behavior when using
ctype(3) helpers
Problem
The implementation currently has two near-identical parser paths. This creates a maintenance risk:
- A validation bug may be fixed in one copy but not the other.
- Security cleanup such as
explicit_bzero() on error paths must be remembered twice.
- Small C correctness details, such as casting before
isdigit() / toupper(), can diverge.
- Future format changes would need duplicated edits and duplicated review.
This is especially undesirable because the parser handles secret key material.
Proposed Fix
Add a shared helper in libatalk for fixed-size hex decoding, then use it from both Randnum callers.
A general helper is preferable to exporting a Randnum-specific helper unless we want to encode the key-file newline policy there too.
Possible API shape:
int atalk_hex_decode_fixed(const unsigned char *hex,
size_t hexlen,
uint8_t *out,
size_t outlen);
Summary
The Randnum key-file parsing logic is currently duplicated between:
bin/afppasswd/afppasswd.cetc/uams/uams_randnum.cBoth files need to parse the same
<afppasswd>.keyformat: exactly 16 hexadecimal characters representing an 8-byte DES key, with one optional trailing newline.Recent hardening fixed both copies independently, but the duplication makes future drift likely. We should consolidate the shared parsing/validation logic into a common helper.
Background
Randnum uses a companion key file named
<afppasswd>.key. The key file is read by both:afppasswd, when creating/updating Randnum password entriesuams_randnum, when authenticating users or changing passwords at runtimeThe logic now needs to enforce the same contract in both places:
ctype(3)helpersProblem
The implementation currently has two near-identical parser paths. This creates a maintenance risk:
explicit_bzero()on error paths must be remembered twice.isdigit()/toupper(), can diverge.This is especially undesirable because the parser handles secret key material.
Proposed Fix
Add a shared helper in
libatalkfor fixed-size hex decoding, then use it from both Randnum callers.A general helper is preferable to exporting a Randnum-specific helper unless we want to encode the key-file newline policy there too.
Possible API shape: