Five defects from review, all mine. ACTION is no longer defaulted. `%let action=MAKEDATA;` meant a caller with no input table at all ran the seeding body - so a URL that never mentioned ACTION would create the control library. The default is MISSING, which is refused, and a URL parameter is whitelisted through the same check with symget() so it is never resolved as macro text. The write probe no longer has a predictable name. fopen with 'O' truncates, so a probe called .dcprobe_<pid> destroyed any pre-existing file of that name in the folder being tested. It now carries the pid and a random suffix, checks fileexist before use, and gives up rather than reuse a name. DIRLIST returns folders and locked entries only. The old filter dropped 'file' and passed every other value - blanks and unknown types - to the picker as a folder. The filter is now an explicit whitelist, and the header describes what is actually emitted. A request with no input table is refused, covered by a test: that is the case the default used to swallow. ngOnDestroy is gone from the client component - it reset a flag on a component being torn down. The deploy-window exposure is recorded in .agents/docs/, with why the admin group cannot be checked there: %mpeinit() reads &mpeadmins from the control library that makedata creates, so before it runs there is no group to check - which is also why the previous dirlist could never serve this screen.
2.7 KiB
The deploy window: who can browse the filesystem before Data Controller is configured
The deploy screens ask two questions about the physical filesystem - what folders sit below this parent, and can the deployment user write to this one. Both are answered by makedata (ACTION=DIRLIST and ACTION=WRITECHECK), through mpe_adminsetup.sas.
This note records the exposure that comes with that, so it is a decision rather than an oversight.
The window
makedata exists from the moment the service pack is deployed until it runs successfully, at which point it deletes itself (and, on SASjs Server, the configurator). Those two actions are therefore reachable in that window by any caller who can reach the STPs at all.
What that caller can do:
DIRLIST- enumerate the folders below any absolute path the SAS process can open. Folder names only; no file contents, no file listing.WRITECHECK- ask whether a path exists, is a folder, and whether the deployment user can create and delete a file in it. It creates a uniquely named probe file and removes it again.
Both refuse a value carrying a macro trigger, a quote or a statement separator, and shape check it with mp_validatecol(ISPATH) before use.
Why there is no group check
Every other admin service gates on &mpeadmins, which comes from MPE_CONFIG in the control library - and that library is what makedata creates. Before it runs there is no group to check: %mpeinit() reads &DC_LIBREF..mpe_config and has nothing to read. That is also why the previous dirlist service could never serve the deploy screen it was written for.
The window is not narrower than the configurator's own: on SASjs Server the configurator page, in the same window, lets the caller pick any group they belong to and create the control library - which is full Data Controller admin. DIRLIST and WRITECHECK are strictly less powerful than that.
What bounds it
makedata self-destructs after a successful run, so a configured deployment has no service that can enumerate a directory or write a probe file. The exposure exists only between deploying the pack and running makedata.
Two things follow for an operator:
- run
makedataas part of the same session as the deploy rather than leaving a deployed but unconfigured pack in place; - if a deployment is abandoned mid-flight, remove the service pack, which removes
makedatawith it.
If it needs to be tighter
The remaining option is a deployment-time gate that does not depend on the control library - for example an allowlist of callers supplied in the service (or an OS/metadata group named before deployment). That is a change to how the deploy screens authenticate, not a change to this service, and it is deliberately not part of it.