BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
ThaoLinh
Calcite | Level 5

Hi SAS Users,

 

I read a lot differently on the topic "how to hide SAS macro source code". Examples can be found here, or here. Every article recommends using the SECURE clause. However, I can still show the source code by doing the following:

 

 

%MACRO COMPMAC1(PARAMETER) / STORE SECURE;
	DATA TEST;
		VAR="&PARAMETER ";
	RUN;
	PROC PRINT DATA=TEST;
	RUN;
%MEND;

OPTIONS MPRINT ;

DATA _NULL_;
	MACRO='%COMPMAC1(AMADEUS);';
	CALL EXECUTE(MACRO);
RUN;

 

 

I checked the log and found it:

 

Screenshot 2021-10-08 233246.png

So my question is how to effectively hide SAS macro source code?

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Ksharp
Super User

Great Idea. Use PROC PRINTTO to suppress print code.

 

%macro secure(val)/secure;
 filename x DUMMY;
 proc printto log=x new;run;


  data T;
    X="&val";
    putlog "This data step was generated from a secure macro with value &val..";
  run;      
proc print data=sashelp.class;run;

proc printto;run; 
%mend secure;

options MPRINT MLOGIC SYMBOLGEN SOURCE SOURCE2;
data _null_;
  call execute('%secure(Q)');
run;

View solution in original post

42 REPLIES 42
Tom
Super User Tom
Super User

What your log is showing is NOT the macro code. It is the SAS code that the macro generated.  Two different things.

 

To stop SAS from showing the code that a macro is generating turn off the MPRINT option.

 

But the real question is WHY would you want to hide your source code?  What problem does that solve?  I cannot think of any.  But it does introduce a lot of potential problems because now no one can tell if what the macro is doing is what they actually need or want to happen.

ThaoLinh
Calcite | Level 5

Simple, You can find the answer here:

There are, however, a number of macros that are unique to the company, which required many hours to create and perfect so that they can run either
for a number of situations/studies or are built for a very specific process. These macros are held close to the chest and generally are not shared with all clients

SASKiwi
PROC Star

Have you considered using compiled macros and just distributing the compiled version? You can distribute the compiled macro without source code.

 

I suspect you will need to be very careful to ensure your macro only contains dynamic macro variable values that get resolved only at run time and not at compile time.

ballardw
Super User

@ThaoLinh wrote:

Simple, You can find the answer here:

There are, however, a number of macros that are unique to the company, which required many hours to create and perfect so that they can run either
for a number of situations/studies or are built for a very specific process. These macros are held close to the chest and generally are not shared with all clients


I would make sure you run any process you apply this idea to with your CONTRACTS people for each client. The wording of your contract with the client might very well prohibit such obfuscation.

yabwon
Onyx | Level 15

Catalogs are "host specific", your catalog created under Windows OS won't run under Lunux.

 

 

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



ChrisNZ
Tourmaline | Level 20

To hide SAS code, add

options nomprint;  as the first line.

Don't forget to restore to option to its previous status at the end.

 

Patrick
Opal | Level 21

Compiling macros into the mstore as secure will prevent anyone to access your macro source code or get any macro execution information written to the SAS log (mprint, symbolgen, mlogic). It doesn't prevent users from seeing the SAS code the macro generates.

 

Option NOSOURCE would prevent SAS to write the generated SAS code to the SAS Log BUT.... when using the macro with call execute() then the SAS code first gets generated and only executed when the data step ended - and for this reason option nosource set within the macro executes too late (timing).

 

I could think about ways to obfuscate things a bit further (adding complexity though) but I can't think about a real solution.

 

It's may-be worth to contact SAS Tech Support asking if there is a way (I doubt it but who knows). 

ChrisNZ
Tourmaline | Level 20

Also, I changed your thread title as your misunderstanding what option SECURE does is not the same as the option being useless.

Sajid01
Meteorite | Level 14

Hello @ThaoLinh 
If your code involves data steps only you can consider using compiled data step programs. Further details can be had here  https://documentation.sas.com/doc/en/pgmsascdc/v_014/engsas7bdat/n1h8ok8rj6uzqkn18tpnp1lb4lp9.htm 

 

Ksharp
Super User
options nosource nosource2 nomprint nomlogic nosymbolgen;


%macro x;
data x;
set sashelp.class;
run;
%mend;

%x
Patrick
Opal | Level 21

@Ksharp The challenge is that the the OP would provide your macro X precompiled and doesn't want the user to be able to see the SAS code it generates. 

The OP has no control over option settings outside of the macro ....and if the user uses the macro via call execute() then any option set within the macro come "too late". 

ChrisNZ
Tourmaline | Level 20

The OP doesn't mention call execute, but good call @Patrick .

Here's a (not very satisfactory) few lines to add at the top of the secure macro to avoid anything being shown in the log.

%macro secure(val)/secure;
  %local opt;
  %let opt=%sysfunc(getoption(mprint)) %sysfunc(getoption(mlogic)) %sysfunc(getoption(symbolgen)) %sysfunc(getoption(source)) %sysfunc(getoption(source2));
  %if &opt ne NOMPRINT NOMLOGIC NOSYMBOLGEN NOSOURCE NOSOURCE2 %then %do;
    options nomprint nomlogic nosymbolgen nosource nosource2;   
    %secure(&val)
    %return;
  %end;
  data T;
    X="&val";
    putlog "This data step was generated from a secure macro with value &val..";
  run;      
  options &opt. ; 
%mend secure;

options mprint mlogic symbolgen source source2;
%secure(A)

options mprint mlogic symbolgen source source2;
data _null_;
  call execute('%nrstr(%secure(B))');
run;

with this displayed in the log:

44         %secure(A)

This data step was generated from a secure macro with value A.
NOTE: The data set WORK.T has 1 observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      user cpu time       0.00 seconds

47         data _null_;
48           call execute('%nrstr(%secure(B))');
49         run;

NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      user cpu time       0.00 seconds
     

NOTE: CALL EXECUTE generated line.
1         + %secure(B)

This data step was generated from a secure macro with value B.
NOTE: The data set WORK.T has 1 observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      user cpu time       0.00 seconds

I am sure there is a lot of room to improve this.

 

Ksharp
Super User
Chris,
Once I used

data _null_;
call execute('%secure(B)');
run;

SAS runs into endless .
Whether I have to use "%nrstr(%secure(B))" to invoke a macro or not .
Whether is that too clumsy ?

I agree with @Patrick . Hope SAS could offer a simple solution .
Quentin
Super User

I've never been in the business of hiding macro code (or SAS code), but depending on what the macro is doing, I guess DOSUBL might help.

 

Within a DOSUBL block, you can use PROC PRINTTO to turn off the log in the side session, and that should prevent any code or messages from being shown.

 

Not advocating this, as I'm a big fan of automated log scanning so the idea of turning off the log chills me to the core of my bones.

 

But it's a helpful benefit of DOSUBL that the timing works out, even when called by CALL EXECUTE.  Depending on the level of code hiding needed, you might not need to completely turn off the log.

 

%macro secure(val)/secure;
  %let rc=%sysfunc(dosubl(%nrstr(
  proc printto log="NUL" ;
  run ;

  data T;
    X="&val";
    putlog "This data step was generated from a secure macro with value &val..";
  run;      
  ))) ;
%mend secure;

data _null_;
  call execute('%secure(Q)');
run;

 

BASUG is hosting free webinars Next up: Don Henderson presenting on using hash functions (not hash tables!) to segment data on June 12. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 42 replies
  • 3059 views
  • 32 likes
  • 10 in conversation