Skip to content

Fix http_get_userid() returning garbage on CGI-invoked requests#110

Merged
mgrossmann merged 1 commit into
mainfrom
issue-109-userid-decrypt-cachehit
Jul 5, 2026
Merged

Fix http_get_userid() returning garbage on CGI-invoked requests#110
mgrossmann merged 1 commit into
mainfrom
issue-109-userid-decrypt-cachehit

Conversation

@mgrossmann

Copy link
Copy Markdown
Contributor

Fixes #109

Root cause (confirmed live on MVS)

http_get_userid() decrypted httpc->cred->id via credid_dec(), whose
blowfish key (credkey()) lives in per-GRT WSA and is initialized only in
httpd's own GRT by cred_init(). A CGI reached through the HTTPX vector (mvsMF)
runs under its own C runtime / GRT, where that key is still zero — so
credid_dec() decrypted with an all-zero key and returned garbage.

Proven with temporary instrumentation on the live server (encrypt vs decrypt
context):

DBGENC grt=00094CF8 key=00124F98 kb=06C869B67997BE14 flg=80   (httpd worker)
DBGDEC grt=001249C8 key=00204F98 kb=0000000000000000 flg=80   (mvsMF CGI)

Same ciphertext, flag set, but a different, uninitialized key in the CGI's
GRT (the GRT varied per request). This is why http_get_acee() (raw pointer)
and httpd's own credid_dec() callers (SMF, console, login WTO — all in httpd's
GRT) were unaffected, and why an in-module unit test could not reproduce it.

Fix

Read the userid straight from the RACF ACEE (aceeuser, length-prefixed) —
the RACF-canonical identity, no key needed, correct from any execution
context, and the same field http_get_acee() consumers already read. The
CREDID encryption (which protects the password held in the in-memory credential
cache) is untouched.

Verification

  • curl -u ibmuser:sys1 .../zosmf/test?fn=useridIBMUSER (fresh and
    cache-hit); wrong password still 401.
  • make test-mvs: TSTGUID (real http_get_userid() over a fabricated-ACEE
    CRED + a real cred_login()+cache-hit path) and TSTCRED (credid
    encrypt/decrypt round-trip + flag invariant) both pass.

Note

http_get_userid() stays in the HTTPX vector (append-only ABI; already consumed
by mvsMF jobsapi.c) — it is now a thin, layout-independent wrapper over the
ACEE userid. The per-GRT credkey() limitation is inherent to the credentials
package and only ever affected this one CGI-context decrypt path, which this
change removes.

http_get_userid() decrypted httpc->cred->id via credid_dec(), whose blowfish
key (credkey()) lives in per-GRT WSA and is initialized only in httpd's own GRT
by cred_init(). A CGI reached through the HTTPX vector (e.g. mvsMF) runs under
its own C runtime / GRT, where that key is still zero, so credid_dec() decrypted
with an all-zero key and returned garbage -- but only for CGI-invoked requests.
httpd's own credid_dec() callers run in httpd's GRT and were unaffected, which
is why http_get_acee() and the SMF/console userid stayed correct.

Read the userid straight from the RACF ACEE (aceeuser is length-prefixed) --
the RACF-canonical identity, no key needed, correct from any execution context,
and the same field http_get_acee() consumers already read. The CREDID
encryption (which protects the password held in the in-memory credential cache)
is untouched.

Verified on MVS: the mvsMF /zosmf/test?fn=userid probe now returns IBMUSER
(fresh and cache-hit); a wrong password still gets 401.

Tests (MVS-only): TSTGUID drives the real http_get_userid() over a
fabricated-ACEE CRED and a real cred_login()+cache-hit path; TSTCRED covers the
credid_enc()/credid_dec() round-trip and the CREDID_USER_ENCRYPT flag invariant.

Fixes #109
@mgrossmann
mgrossmann merged commit 77d5598 into main Jul 5, 2026
1 check passed
@mgrossmann
mgrossmann deleted the issue-109-userid-decrypt-cachehit branch July 5, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

http_get_userid() returns undecrypted CREDID bytes on a cached (token-hit) CRED

1 participant