SAP BOX

'26/11/08 UPDATE

ABAP / FIELD NOTES

Checking authorizations in Z programs: what slips through if you only test sy-subrc 4 after AUTHORITY-CHECK?

With only IF sy-subrc = 4 after AUTHORITY-CHECK, a user who was never given the authorization object (sy-subrc 12) passes straight through. Using a fictional Z report, this note covers what sy-subrc 0, 4, 12 and 40 mean, four cases where a 0 does not mean this user is authorized for these values, the places with no implicit check that you must guard yourself, and the order to follow in a review.

When you review the authorization checks in a Z report, you may find code with nothing but IF sy-subrc = 4. right after AUTHORITY-CHECK. That IF stops a user who holds some authorizations for the object, but lets a user who was never given the object at all walk straight through. After reading this note you will know what each sy-subrc value means, when a 0 does not mean this user is authorized for these values, and where you have to write AUTHORITY-CHECK yourself. From that you can build a review checklist for Z code.

The example is a fictional report, ZBOX_CARRIER_LIST. Before it shows the flights of the airline entered, it checks the authorization object S_CARRID for the airline (CARRID) and the activity (ACTVT, 03 = Display). S_CARRID is the object used in the examples of SAP's keyword documentation. The code was not run on a real system; the behaviour described follows the AUTHORITY-CHECK page of the ABAP Keyword Documentation 7.58 and related pages.

sy-subrc has five values, and 4 is only one of them

AUTHORITY-CHECK checks whether the current user's user master record holds an authorization for the object, and whether that authorization allows the values given. A failed check raises no exception; the result is only left in sy-subrc, so the IF that follows is what actually blocks anything.

  • 0: the check succeeded, or no check was performed. Success means that at least one authorization for the object contains all the values given, for every field listed. If the airline is in one authorization and activity 03 in another, the check does not succeed.
  • 4: authorizations for the object exist, but they do not contain the values given. A field name that is not part of the object, or too many fields, also gives 4.
  • 12: the user master record has no authorization for the object at all.
  • 24: this value is no longer set.
  • 40: the user name given in FOR USER is invalid. Without FOR USER it cannot occur.

These five values mean the same in the 7.40, 7.50, 7.58 and 8.16 documentation; only the wording differs slightly.

Example SAP GUI ABAP Editor screen. In the AT SELECTION-SCREEN block of the fictional report ZBOX_CARRIER_LIST, AUTHORITY-CHECK OBJECT 'S_CARRID' checks CARRID against the input p_carr and ACTVT against '03', and the IF right below sends an error message only when sy-subrc = 4. Marker 3 sits on the SELECT * FROM spfli in START-OF-SELECTION, showing that a user with sy-subrc 12 reaches the read.
An example editor view of a fictional report that tests only IF sy-subrc = 4 after AUTHORITY-CHECK. ZBOX_CARRIER_LIST and the values are fictional; the code was not run.

In the screen example, marker 1 is the check and marker 2 is the IF that treats only 4 as a failure. A user who has authorizations, but not for this airline, gets 4 and stops at marker 2. A user with no S_CARRID authorization at all gets 12, passes the IF and reaches the read at marker 3. The user with the least access to this object gets through most easily. If the denied case is only tested with a user who holds some of these authorizations, you only ever see 4 and the gap stays hidden.

The fix is to write IF sy-subrc <> 0. and treat every non-zero value as a failure. You can show a different message for 12 or 40, but 0 must be the only value that lets the user through.

SAP NOTES

= 4 lets 12 and 40 through

What each IF does with each sy-subrc after AUTHORITY-CHECK (ABAP Keyword Documentation 7.58)

  • 0 · Success, or no check performed

    sy-subrc = 0

    • One authorization holds every value given
    • = 4: passes · <> 0: passes
  • 4 · Authorizations exist, values do not

    sy-subrc = 4

    • Or wrong fields, or too many fields
    • = 4: stops · <> 0: stops
  • 12 · No authorization for the object at all

    sy-subrc = 12

    • The user with the least access to this object
    • = 4: passes · <> 0: stops
  • 40 · Invalid user name in FOR USER

    sy-subrc = 40

    • Only possible with FOR USER
    • = 4: passes · <> 0: stops

24 is no longer set. The table is the same in the 7.40, 7.50, 7.58 and 8.16 documentation. A 0 also covers 'no check performed'.

IF sy-subrc = 4 stops only one of the four values that still occur (24 is no longer set); IF sy-subrc <> 0 treats every non-zero value as a failure.

Four cases where a 0 does not mean this user is authorized for these values

Even with <> 0, a gap remains on the 0 side. A 0 also comes back when no check ran, when only some fields were checked, or when another user was checked.

The check indicator is set to 'no check'. A check indicator states whether an authorization object is checked in a given context, and transactions are the most important contexts. SAP sets them in SU22, customer systems in SU24. If the object is set to 'no check' in the current context, AUTHORITY-CHECK does not check anything and leaves 0, just as for a success. This is why the same statement can give different results depending on how the program was started. As a rule, check indicators should always be set to check, and objects of the AS ABAP (BC) and human resources (HR) areas cannot be set to 'no check' at all.

During an update. No authorization check is possible inside an update function module run by COMMIT WORK. There, AUTHORITY-CHECK checks nothing and always sets sy-subrc to 0. This applies to local updates as well as update sessions. So check the authorization in the dialog part, before the call is registered with CALL FUNCTION ... IN UPDATE TASK. When the update actually runs is covered in the note on the update task right after COMMIT WORK.

A field is given as DUMMY or left out. Fields that are not listed in the statement, and fields given as DUMMY, are not checked. With ID 'ACTVT' DUMMY, the activity is ignored and only the airline is checked. If every field is DUMMY, the result in 7.58 is either 0 or 12: any authorization for the object gives 0, whatever its values, so this 0 only says that the user has some authorization for the object.

FOR USER checks another user. With FOR USER, the authorizations of the named user are checked. Because someone can name a user with broad authorizations to get around the check, the documentation calls this addition a security risk. Never use a user name passed in from outside; if you must, check that name carefully. Without FOR USER, the check uses the actual user name rather than the content of the system field sy-uname. That makes FOR USER sy-uname redundant, and also risky, because sy-uname can be overwritten, for example in the debugger.

SAP NOTES

A 0 is not always a yes for this user

Four cases where a 0 does not mean this user is authorized for these values

  • Check indicator set to 'no check'

    • No check, and 0 as if it succeeded
    • Set per context
    • Transactions matter most
    • SU24 in customer systems
    • 'No check' not allowed for BC and HR objects
  • During an update

    CALL FUNCTION … IN UPDATE TASK

    • In an update function module run by COMMIT WORK
    • No check, always 0
    • Local updates too
  • DUMMY, or a field left out

    ID 'ACTVT' DUMMY

    • That field is not checked
    • All fields DUMMY: the result is 0 or 12
    • Any authorization for the object gives 0
  • FOR USER

    FOR USER lv_user

    • Checks another user's authorizations
    • Never a name passed in from outside
    • FOR USER sy-uname is redundant
    • sy-uname can be overwritten

Without FOR USER, the check uses the actual user name, not the content of sy-uname. 'All DUMMY gives 0 or 12' was checked in the 7.58 documentation.

A 0 also comes back when no check ran, when only some fields were checked, or when another user was checked.

Where you have to write AUTHORITY-CHECK yourself

Some statements check by themselves, with fixed authorization objects.

  • CALL TRANSACTION ... WITH AUTHORITY-CHECK checks S_TCODE and any authorization object entered in the transaction definition in SE93 before the call. If the authorization is missing, the catchable exception CX_SY_AUTHORIZATION_ERROR is raised; if nothing catches it, the program ends with the runtime error CALL_TRANSACTION_NO_AUTH.
  • LEAVE TO TRANSACTION always checks the same two things (S_TCODE and the object entered in SE93) and sends a termination message (type A) when the authorization is missing.
  • SUBMIT checks the authorization group in the called program's attributes, if there is one, against S_PROGRAM.
  • OPEN DATASET and DELETE DATASET in the ABAP file interface check S_DATASET whenever a file is opened or deleted. Depending on table SPTH, an S_PATH check is added.

On the other side, typical places with no implicit check are CALL TRANSACTION without WITH AUTHORITY-CHECK (by default, when table TCDCOUPLES has no entry with OKFLAG X for the call either), SUBMIT of a program without an authorization group, and SQL reads on database tables. Guard any such place that a user can reach without the right authorizations with AUTHORITY-CHECK, and evaluate the result with care.

CALL TRANSACTION with neither WITH AUTHORITY-CHECK nor WITHOUT AUTHORITY-CHECK is obsolete. Both additions are listed as new in the changes for ABAP 7.40 SP02, and the CALL TRANSACTION syntax in the 7.31 documentation does not have them. The recommended form is WITH AUTHORITY-CHECK, which replaces a separate AUTHORITY-CHECK or AUTHORITY_CHECK_TCODE before the call and any check that relies on TCDCOUPLES. WITHOUT AUTHORITY-CHECK states openly that no check is needed. With it, the security test of the extended program check no longer reports the call as an error, and the content of TCDCOUPLES is ignored. In a review, it is the place to ask why no check is needed.

SAP NOTES

Where an implicit check exists, and where it does not

The statements that decide whether you must write AUTHORITY-CHECK yourself (7.58)

  • Examples: an implicit check runs

    • CALL TRANSACTION … WITH AUTHORITY-CHECK: S_TCODE and the object entered in SE93
    • LEAVE TO TRANSACTION: S_TCODE and the object entered in SE93
    • SUBMIT of a program with an authorization group: S_PROGRAM
    • OPEN DATASET, DELETE DATASET: S_DATASET and others
  • Examples: no implicit check

    AUTHORITY-CHECK OBJECT …

    • CALL TRANSACTION without WITH (by default: no TCDCOUPLES entry with OKFLAG X either)
    • SUBMIT of a program without an authorization group
    • SQL reads on database tables
    • Guard these places yourself and evaluate the result with care
  • Saying explicitly: no check

    WITHOUT AUTHORITY-CHECK

    • The extended program check reports no security error
    • The content of TCDCOUPLES is ignored
    • CALL TRANSACTION with neither addition is obsolete

With WITH AUTHORITY-CHECK, a missing authorization raises CX_SY_AUTHORIZATION_ERROR, and if it is not caught the runtime error is CALL_TRANSACTION_NO_AUTH. The file interface can also check S_PATH, depending on table SPTH.

Statements with an implicit check use fixed objects. Where there is none, AUTHORITY-CHECK has to guard the code, and WITHOUT AUTHORITY-CHECK is a line to ask about in a review.

The order to follow in a review

  1. Look at the test right after each AUTHORITY-CHECK. Change code that treats only one value as a failure, such as = 4 or = 12, to <> 0.
  2. Look for a branch after a failed check that compares sy-uname and lets particular users through. The documentation gives this as an example of a back door and says to repair it by taking out the IF block that queries sy-uname. Only that condition goes; the failure handling (LEAVE PROGRAM or similar) stays.
  3. Where there is FOR USER, find out where the user name comes from. Fix it if the name comes from outside, and remove FOR USER sy-uname.
  4. Look at DUMMY and at fields left out. Without the activity (ACTVT), a user with display authorization only also passes a check meant to guard a change.
  5. Move any AUTHORITY-CHECK inside an update function module to the dialog part, before the call.
  6. For CALL TRANSACTION without WITH AUTHORITY-CHECK, see whether the system's release offers the addition; where it does not, check that there is a check in front of the call. Look for one as well in front of other places with no implicit check, such as SUBMIT of programs without an authorization group and SELECT statements that read sensitive tables.
  7. In SU24, confirm that the object's check indicator is set to check for the transaction that starts the report.
  8. To confirm on a system, the ST01 system trace records each authorization object checked, with its fields and values. If the trace and the traced transaction run on the same application server, checks in other sessions are recorded too. SU53 shows the last failed authorization check and can be opened from any of your own sessions, not only the one where the error occurred.

The first line of the checklist is changing = 4 to <> 0. The second is asking, whenever a 0 comes back, whose authorizations were checked, for which fields, and whether a check really ran. A 0 that cannot answer those questions does not count as a yes.

THE END
RSS feedBack to the library
COMMENTS BOX

Add your perspective.

Share a question, another approach, or something you have tried.

Newest first

Checking sign-in…

Loading comments…