Files
dc/sas/sasjs/services/admin/dirlist.sas
T
dc be86000fe0
Build / Build-and-ng-test (pull_request) Successful in 5m17s
Lighthouse Checks / lighthouse (pull_request) Successful in 21m6s
Build / Build-and-test-development (pull_request) Successful in 25m40s
fix: validate request inputs and add admin gates to public services
Security fixes for the input-validation gaps in the public download and
metadata services, plus missing in-code admin gates:

- mpe_accesscheck: validate base_table (LIBDS) and access_level before
  they reach the authorisation query, and escape embedded quotes in the
  SQL literals (defence in depth for direct macro callers)
- getrawdata: validate table (LIBDS / format-catalog form), filter
  (integer) and type before they are used; read all inputs with symget
  in a data step so macro content cannot execute at a resolution boundary
- getdiffs: validate libds, table and stp_diffs_csv before the access
  check and the staging-file stream path
- getcols, getcolvals, validatefilter: read the IWANT inputs with symget
  in a data step and validate (LIBDS / SAS name) before use
- admin dirlist, refreshlibs, refreshcatalog, exportconfig: require
  membership of the DC administrators group (the admin folder prefix is
  not an access control)
- admin dirlist: read parent with symget and reject macro characters

Tests (all proven RED on the vulnerable services first, then GREEN on
the fix): getrawdata.test.1, getdiffs.test, getcols.test,
getcolvals.test.4, validatefilter.test.1, dirlist.test,
refreshcatalog.test.1
2026-09-21 19:04:35 +00:00

62 lines
1.5 KiB
SAS

/**
@file
@brief Fetches directories to facilitate configuration
@details The service can also be invoked using the following URL param:
@li &parent= (parent path)
Requires membership of the DC administrators group.
<h4> SAS Macros </h4>
@li mf_getuser.sas
@li mp_abort.sas
@li mp_dirlist.sas
@li mpe_getgroups.sas
@version 9.2
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
and may not be re-distributed or re-sold without the express permission of
4GL Apps Ltd.
**/
%global parent;
%mpeinit()
/* check user is in admin group */
%let cnt=0;
%mpe_getgroups(user=%mf_getuser(),outds=work.usergroups)
proc sql noprint;
select count(*) into:cnt
from usergroups
where groupname="&mpeadmins";
%mp_abort(iftrue= (&cnt=0)
,mac=&_program
,msg=%str(This service is only available to &mpeadmins members)
)
/* if no parent is specified, default to root - read with symget
* (never re-resolved) so macro content in the param cannot execute */
%let is_bad=0;
data _null_;
length _parent $512;
_parent=coalescec(symget('parent'),'/');
if index(_parent,'%')>0 or index(_parent,'&')>0 then do;
putlog 'ERR' 'OR: Invalid parent:' _parent;
call symputx('is_bad',1,'l');
end;
else call symputx('parent',_parent,'g');
run;
%mp_abort(iftrue=(&is_bad=1)
,mac=&_program..sas
,msg=%str(Invalid parent)
)
%mp_dirlist(path=&parent,outds=dirlist, maxdepth=2)
%webout(OPEN)
%webout(OBJ,dirlist)
%webout(CLOSE)