saf-process.c

Go to the documentation of this file.
00001 /****************************************************************************
00002  *
00003  *      Copyright (C) 2006-2008 Micro Focus (IP) Limited.
00004  *      All rights reserved.
00005  *
00006  * The software and information contained herein are proprietary to, and
00007  * comprise valuable trade secrets of, Micro Focus International Ltd., 
00008  * which intends to preserve as trade secrets such software and 
00009  * information. This software is an unpublished copyright of Micro Focus  
00010  * and may not be used, copied, transmitted, or stored in any manner.  
00011  * This software and information or any other copies thereof may not be
00012  * provided or otherwise made available to any other person.
00013  *
00014  *      Enterprise Server SAF (Security) Manager
00015  *      SAF Request Processing
00016  *
00017  *      @(#)saf-process.c   $Revision: 1.2 $     
00018  *
00019  *      $Date: 2008/07/01 08:32:50 $
00020  *
00021  ****************************************************************************/
00022 
00023 /* Copyright */
00024 static const char *copyright =
00025    "Copyright (C) 2006-2008 Micro Focus (IP) Limited";
00026 static const char *sccsid =
00027    "@(#)saf-process.c  $Revision: 1.2 $ built " __DATE__ " " __TIME__;
00028 
00029 /* Start of source module saf-process.c */
00030 
00031 
00051 /* System Headers */
00052 
00053 /* ANSI/ISO standard headers */
00054 #include <stddef.h>
00055 #include <stdlib.h>
00056 #include <stdio.h>
00057 #include <stdarg.h>
00058 #include <string.h>
00059 #include <time.h>
00060 #include <errno.h>
00061 #include <ctype.h>
00062 
00063 /* UNIX headers */
00064 #if defined(UNIX)
00065 #   include <unistd.h>
00066 #   include <sys/time.h>
00067 #endif
00068 
00069 /* Win32 headers */
00070 #if defined(WIN32)
00071 #   include <windows.h>
00072 #   include <sys/types.h>
00073 #   include <sys/stat.h>
00074 #endif
00075 
00076 
00077 /* External Headers */
00078 #if defined(UNIX)
00079 #  include "gptypes.h"          /* RTS types, req. by CCI */
00080 #elif defined(WIN32)
00081 #  include "pc_rts.h"           /* ditto for Win32 */
00082 #endif
00083 #include "cci.h"                /* CCI API and types */
00084                                 /* (required for mf_os_size typedef) */
00085 #include "mdsa.h"               /* MDSA SAF and ESM configuration */
00086 
00087 
00088 /* SAF Headers */
00089 
00090 #define saf78_SAFADMIN_DATA_AREAS
00091 #include "safapi.h"
00092 #include "safmgr.h"
00093 #include "saf-esm.h"
00094 #include "saf-env.h"
00095 #include "saf-acee.h"
00096 #include "saf-process.h"
00097 #include "saf-audit.h"
00098 #include "mfaudit.h"
00099 
00100 
00101 /***
00102 Structure for cached update area. In a shared-memory multiprocess
00103 environment (ie CAS), each update is only processed by a single ESF-calling
00104 process (ie a SEP). That process handles clearing out any globally-cached
00105 data in shared memory, as well as its own private data.
00106 
00107 But the other processes will still need to clear out their private data.
00108 So we keep, in shared memory, a cached copy of the most recent admin update, 
00109 plus a sequence number for updates. Then, as each process gets activated,
00110 it checks to see if it's missed any updates (by comparing the global
00111 sequence number with its own internal sequence number). If the sequence
00112 numbers are the same, it hasn't missed any. If they're different by one,
00113 it's only missed the cached update, and it needs to process that (for its
00114 private memory only). If they differ by more than one, it's missed multiple
00115 updates, and it needs to flush all private cached data.
00116 
00117 This structure serves as a header for the global cache area. It includes
00118 the sequence number, the cached request, and the indirect data from the
00119 request, such as the entity name and the ACEE.
00120 ***/
00121 
00122 #define SafCACHE_MAX_ENTITY_LEN 1024
00123 
00124 struct UpdateCache
00125 {
00126    mf_uns32              Sequence;  /* global update sequence number */
00127    Safpb_Parameter_Block PBlock;    /* cached request block */
00128    SafACEE               ACEE;      /* ACEE from request */
00129    char                  Entity[SafCACHE_MAX_ENTITY_LEN];
00130                                     /* Entity name from request */
00131 };
00132 
00133 
00134 
00135 static SafRet AuditAdminReq(struct safpb_parameter_block *PBlock,
00136                             int ReqType, SafACEE *AceePtr,
00137                             const char *CmdName, int CmdLen);
00138 static int LockUpdateArea(void);
00139 static int UnlockUpdateArea(void);
00140 static SafRet HandlePendingUpdates(struct UpdateCache *Cache);
00141 static mf_uns32 CheckForPendingSharedUpdate(struct UpdateCache *Cache);
00142 static struct UpdateCache *GetUpdateCache(void);
00143 static const char *UpdateTypeToString(unsigned char Type);
00144 static const char *EsmrcToString(mf_uns32 EsmRet);
00145 
00146 
00147 /* Private Data */
00148 static mf_uns32 NumESMMods = 0;
00149 static int AllowUnknownUsers = 0,
00150            AllowUnknownResources = 0,
00151            VerifyAllESMs = 0;
00152 
00153 
00154 
00155 /*** Management ***/
00156 
00171 mf_uns32 SafProcInit(struct SafInit *Init)
00172 {
00173    /* Store number of configured ESM Modules */
00174    NumESMMods = Init->ESMCnt;
00175 
00176    /* Set processing option flags */
00177    AllowUnknownUsers =
00178       !! (Init->Config->option_flags & SAF_OPTION_ALLOW_UNKNOWN_USERS);
00179    AllowUnknownResources =
00180       !! (Init->Config->option_flags & SAF_OPTION_ALLOW_UNKNOWN_RESOURCES);
00181    VerifyAllESMs =
00182       !! (Init->Config->option_flags & SAF_OPTION_VERIFY_AGAINST_ALL_ESMS);
00183 
00184    return SafINIT_OK;
00185 }
00186 
00187 
00188 
00189 /*** SAF Requests ***/
00190 
00201 int SafVerify(struct safpb_parameter_block *PBlock)
00202 {
00203    int Ret = saf78_SAF_RC_SUCCESS, Resolved = 0, Tentative = 0, Allowed = 0,
00204        IsSysUser = 0;
00205    mf_uns32 CurrEsm, EsmRet, NumCalled = 0;
00206    SafRet SRet;
00207    struct SafACEE *Acee = NULL;
00208    char AUserBuf[16] = "???", *MUserBuf = NULL, *UserBuf = AUserBuf;
00209    char GroupBuf[9] = "", *GrpBufPtr, *GrpPtr;
00210    mf_uns32 UserLen;
00211    extern int SafCasOldAcee;     /* see saf-esm.c */
00212 
00213    /* Passtoken control */
00214    #define SafPT_UNKNOWN     (1u<<7)
00215    #define SafPT_GEN_ALLOWED (1u<<0)
00216    #define SafPT_USE_ALLOWED (1u<<1)
00217    static unsigned TokenPerm = SafPT_UNKNOWN;
00218    
00219 
00220    if (!PBlock)
00221       return 0;
00222 
00223    UserLen = PBlock->REQUESTS.VERIFY.safpb_verify_USERID_len;
00224   
00225 
00226    /* Check state */
00227    if (SafState() != 1)
00228    {
00229       Ret = saf78_SAF_RC_FAILURE;
00230       PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
00231       goto done;
00232    }
00233 
00234    /* Make sure this a function we handle */
00235    if (PBlock->safpb_type == saf78_TYPE_ENVIR_DESTROY)
00236    {
00237       /* TODO: Handle DESTROY */
00238       return 0;
00239    }
00240 
00241    /*AUDITEVENTCALL Check: Verify/create */
00242    SafRaiseAuditEvent
00243    (
00244       AUDIT_EVENT_CHECK_VERIFY
00245     , AUDIT_EVENT_CATEGORY_SEC_API_REQ_CHECK
00246     , 2
00247     , SafEventData
00248       (
00249         AUDIT_RECORD_DATA_TYPE_STRING
00250        ,PBlock->REQUESTS.VERIFY.safpb_verify_USERID_ptr
00251        ,PBlock->REQUESTS.VERIFY.safpb_verify_USERID_len
00252       )
00253     , SafEventData
00254       (
00255         AUDIT_RECORD_DATA_TYPE_STRING
00256        ,PBlock->REQUESTS.VERIFY.safpb_verify_group
00257        ,sizeof(PBlock->REQUESTS.VERIFY.safpb_verify_group)
00258       )
00259    );          
00260 
00261 
00262    /* Make sure we have no pending shared update notices */
00263    HandlePendingUpdates(NULL);
00264 
00265 
00266    /* Extract user name string */
00267    AUserBuf[0] = '\0';              /* to prevent logging issues below */
00268    UserBuf = AUserBuf;
00269 
00270    if (UserLen < sizeof AUserBuf)
00271    {
00272       UserBuf = AUserBuf;
00273    }
00274    else
00275    {
00276       MUserBuf = malloc(UserLen + 1);
00277       if (! MUserBuf)
00278       {
00279          /* TODO: Audit this */
00280          Ret = saf78_SAF_RC_FAILURE;
00281          PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
00282          goto done;
00283       }
00284       UserBuf = MUserBuf;
00285    }
00286 
00287    memcpy(UserBuf, PBlock->REQUESTS.VERIFY.safpb_verify_USERID_ptr, UserLen);
00288    UserBuf[UserLen] = '\0';
00289 
00290 
00291    /* Extract group string */
00292    for (GrpBufPtr = GroupBuf,
00293            GrpPtr = PBlock->REQUESTS.VERIFY.safpb_verify_group;
00294         *GrpPtr > ' '
00295            && GrpPtr < PBlock->REQUESTS.VERIFY.safpb_verify_group + 8;
00296         GrpBufPtr++, GrpPtr++)
00297    {
00298       *GrpBufPtr = *GrpPtr;
00299    }
00300    *GrpBufPtr = '\0';
00301         
00302 
00303    /* Check for special processing */
00304    IsSysUser = PBlock->safpb_flag & saf78_VER_NO_PASSWORD;
00305 
00306 
00307    /***
00308    Passtoken support: if this is a passtoken request (one of Verify-with-
00309    generate-ticket, Generate-token, or Verify-using-token), check to see
00310    if it's allowed by our config; this may require parsing the config for
00311    the first time.
00312    ***/
00313 
00314    if ((PBlock->safpb_flag & saf78_VER_PT_TICKET) ||
00315        (PBlock->safpb_flag & saf78_VER_PASSTOKEN) ||
00316        (PBlock->safpb_flag & saf78_VER_PT_SURROGATE) ||
00317        (PBlock->safpb_type == saf78_TYPE_TOKEN_CREATE))
00318    {
00319       /* Do we need to parse the config setting? */
00320       if (TokenPerm == SafPT_UNKNOWN)
00321       {
00322          char *PTAllow = NULL;
00323          SafQueryCfg("Passtoken", "allow", &PTAllow);
00324          if (! PTAllow) PTAllow = "";
00325          if (SafSTRCMP_CI(PTAllow, ==, "none"))
00326             TokenPerm = 0;
00327          else if (SafSTRCMP_CI(PTAllow, ==, "generate"))
00328             TokenPerm = SafPT_GEN_ALLOWED;
00329          else if (SafSTRCMP_CI(PTAllow, ==, "signon"))
00330             TokenPerm = SafPT_USE_ALLOWED;
00331          else
00332             TokenPerm = SafPT_GEN_ALLOWED | SafPT_USE_ALLOWED;
00333       }
00334 
00335       /* Now check to see if this kind of request is allowed */
00336       if (PBlock->safpb_flag & saf78_VER_PT_TICKET)
00337       {
00338          /***
00339          Request to generate ticket.  If disallowed, or if this is a
00340          no-password or surrogate-token Verify, silently turn off ticket
00341          request flag.
00342          ***/
00343 
00344          if (! (TokenPerm & SafPT_GEN_ALLOWED)
00345              || (PBlock->safpb_flag & saf78_VER_NO_PASSWORD)
00346              || (PBlock->safpb_flag & saf78_VER_PT_SURROGATE))
00347          {
00348             /* Silently disable ticket-generation option */
00349             PBlock->safpb_flag &= ~saf78_VER_PT_TICKET;
00350          }
00351       }
00352 
00353       if (PBlock->safpb_type == saf78_TYPE_TOKEN_CREATE)
00354       {
00355          /* Request to generate token */
00356          if (! (TokenPerm & SafPT_GEN_ALLOWED))
00357          {
00358             /* Reject request */
00359             Ret = saf78_SAF_RC_FAILURE;
00360             PBlock->RETCODES.DISCRETE.safpb_mgr_return =
00361                saf78_RC_TOKEN_REFUSED;
00362             goto done;
00363          }
00364       }
00365 
00366       if ((PBlock->safpb_flag & saf78_VER_PASSTOKEN) ||
00367           (PBlock->safpb_flag & saf78_VER_PT_SURROGATE))
00368       {
00369          /* Request to verify using token */
00370          if (! (TokenPerm & SafPT_USE_ALLOWED))
00371          {
00372             /* Reject request */
00373             Ret = saf78_SAF_RC_FAILURE;
00374             PBlock->RETCODES.DISCRETE.safpb_mgr_return =
00375                saf78_RC_TOKEN_REFUSED;
00376             #if _DEBUG && SafLOG_ALL
00377                SafLog
00378                (
00379                   2002
00380                 , SafMsgINFO
00381                 , "Passtoken Verify refused for user \"%s\""
00382                 , UserBuf
00383                );
00384             #endif
00385             goto done;
00386          }
00387       }
00388    }
00389 
00390 
00391    /* Passtoken-delete requests are handled specially */
00392    if (PBlock->safpb_type == saf78_TYPE_TOKEN_DELETE)
00393    {
00394       /* ESM index must be set in request block */
00395       if (! PBlock->safpb_safesm_index)
00396       {
00397          Ret = saf78_SAF_RC_PARM_ERROR;
00398          PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_SAFESM_INDEX;
00399          PBlock->RETCODES.DISCRETE.safpb_mgr_reason = saf78_RS_BAD_VALUE;
00400          goto done;
00401       }
00402 
00403       /* Assume success */
00404       Ret = 0;
00405       PBlock->RETCODES.DISCRETE.safpb_api_rc     = 0;
00406       PBlock->RETCODES.DISCRETE.safpb_mgr_return = 0;
00407       PBlock->RETCODES.DISCRETE.safpb_mgr_reason = 0;
00408 
00409       /* Call the specified ESM module */
00410       EsmRet = SafEsmCVerify(PBlock->safpb_safesm_index - 1, PBlock);
00411 
00412       if (EsmRet)
00413       {
00414          Ret = saf78_SAF_RC_FAILURE;
00415          if (! PBlock->RETCODES.DISCRETE.safpb_mgr_return)
00416          {
00417             PBlock->RETCODES.DISCRETE.safpb_mgr_return =
00418                saf78_RC_DATABASE_ERROR;
00419          }
00420       }
00421 
00422       goto done;
00423    }
00424 
00425 
00426    /* Call ESM Modules */
00427    PBlock->RETCODES.DISCRETE.safpb_api_rc     = saf78_SAF_RC_NOT_COMPLETE;
00428    PBlock->RETCODES.DISCRETE.safpb_mgr_return = 0;
00429    PBlock->RETCODES.DISCRETE.safpb_mgr_reason = 0;
00430 
00431    for (CurrEsm=0; CurrEsm < NumESMMods && !Resolved; CurrEsm++)
00432    {
00433       const char *ErrType = NULL;
00434 
00435       /* Set ESM index in parameter block */
00436       PBlock->safpb_safesm_index = (unsigned char) CurrEsm + 1;
00437 
00438       /* Call ESM Module */
00439       EsmRet = SafEsmCVerify(CurrEsm, PBlock);
00440 
00441       /* Handle non-zero return codes */
00442       /* TODO: Refactor translation of return codes to text */
00443       switch (EsmRet)
00444       {
00445          case SafESMRC_OK:
00446             /* Did we get a definite response? */
00447             if (PBlock->RETCODES.DISCRETE.safpb_api_rc !=
00448                 saf78_SAF_RC_NOT_COMPLETE)
00449             {
00450                /***
00451                If the request failed, we're done.  If the request is still
00452                indeterminate, continue.  If the request succeeded, then
00453                there are two possibilities:
00454                
00455                - By default, we continue to call other ESMs, but with the
00456                parameter block's safpb_api_rc set to RC_SUCCESS.  ESMs
00457                should recognize this as an opportunity to update the ACEE,
00458                but should not attempt to verify the user again.  We ignore
00459                results from the other ESMs, unless they fail.
00460 
00461                - If VerifyAllESMs is set, we log a tentative success, but
00462                continue to call other ESMs as if the user had not been
00463                verified.  This implements a librum veto - any ESM can
00464                reject a user.
00465 
00466                The first case is actually a bit broken, because ESMs that
00467                have a higher priority than the one that allows the user
00468                don't have a chance to update the ACEE.  We should make
00469                this "update the ACEE" function a separate one - possibly
00470                by calling another ESM function after a successful verify.
00471                ***/
00472 
00473                if (Allowed)
00474                {
00475                   /* User already verified; reset SAF return code */
00476                   PBlock->RETCODES.DISCRETE.safpb_api_rc = saf78_SAF_RC_SUCCESS;
00477                }
00478                else if (PBlock->RETCODES.DISCRETE.safpb_api_rc !=
00479                         saf78_SAF_RC_SUCCESS)
00480                {
00481                   /* Verify failed */
00482                   Resolved = 1;
00483                   Tentative = 0;
00484                }
00485                else if (VerifyAllESMs)
00486                {
00487                   /* If no one else rejects, accept */
00488                   Tentative = 1;
00489                   PBlock->RETCODES.DISCRETE.safpb_api_rc =
00490                      saf78_SAF_RC_NOT_COMPLETE;
00491                }
00492                else
00493                {
00494                   /* Verify succeded; let other ESMs update ACEE */
00495                   Allowed = 1;
00496                }
00497             }
00498 
00499             /* Increment number of ESMs called successfully */
00500             NumCalled++;
00501             break;
00502 
00503          case SafESMRC_NOTIMPL:
00504             /* Not a definite response; keep trying */
00505             break;
00506 
00507          /* All other cases represent an ESM Module failure */
00508          case SafESMRC_PARAM:
00509             ErrType = "parameter error";
00510             break;
00511          case SafESMRC_RESOURCE:
00512             ErrType = "resource unavailable";
00513             break;
00514          case SafESMRC_EXTERNAL:
00515             ErrType = "ESM error";
00516             break;
00517          case SafESMRC_MGRFAIL:
00518             ErrType = "ESF Manager failure";
00519             break;
00520          case SafESMRC_FAIL:
00521             ErrType = "miscellaneous failure";
00522             break;
00523          default:
00524             ErrType = "unknown error";
00525             break;
00526       }
00527 
00528       /* Check for failure */
00529       if (ErrType)
00530       {
00531          mf_uns32 esmnum;
00532          const char* esmname;
00533 
00534          /* Log this */
00535          SafLog
00536          (
00537             110
00538           , SafMsgERR
00539           , "ESM Module %d (%s) returned error code %d (%s) from Verify"
00540           , CurrEsm+1
00541           , SafEsmName(CurrEsm)
00542           , (int)EsmRet
00543           , ErrType
00544          );
00545          
00546          /* TODO: Audit this */
00547           esmnum=CurrEsm+1;
00548           esmname=SafEsmName(CurrEsm);
00549 
00550          /* AUDITEVENTCALL Verify ESM Error*/
00551          SafRaiseAuditEvent
00552          (
00553             AUDIT_EVENT_VERIFY_ESM_ERROR
00554           , AUDIT_EVENT_CATEGORY_SEC_API_RES_ERROR
00555           , 4
00556           , SafEventData
00557             (
00558                AUDIT_RECORD_DATA_TYPE_COMP5
00559              , (void*)&esmnum
00560              , sizeof(esmnum)
00561             )
00562           , SafEventData
00563             (
00564                AUDIT_RECORD_DATA_TYPE_STRING
00565              , (void*)esmname
00566              , (int)strlen(esmname)
00567             )
00568           , SafEventData
00569             (
00570                AUDIT_RECORD_DATA_TYPE_COMP5
00571              , (void*)&EsmRet
00572              , sizeof(EsmRet)
00573             )
00574           , SafEventData
00575             (
00576                AUDIT_RECORD_DATA_TYPE_STRING
00577              , (void*)ErrType
00578              , (int)strlen(ErrType)
00579             ) 
00580 
00581          );   
00582                 
00583 
00584          /* Convert to failure result */
00585          PBlock->RETCODES.DISCRETE.safpb_api_rc = saf78_SAF_RC_FAILURE;
00586          PBlock->RETCODES.DISCRETE.safpb_mgr_return =
00587             saf78_RC_DATABASE_ERROR;
00588          Resolved = 1;
00589       }
00590    }
00591 
00592 
00593    /***
00594    Convert a tentative resolution (used when call-all-ESMs mode is enabled)
00595    to a definite one, now that all ESMs have been called (or we have a
00596    rejection, in which case this is a no-op).
00597    ***/
00598 
00599    if (Tentative || Allowed)
00600    {
00601       Resolved = 1;
00602       if (PBlock->RETCODES.DISCRETE.safpb_api_rc == saf78_SAF_RC_NOT_COMPLETE)
00603       {
00604          /* We were tentatively allowing this user, so make that official */
00605          PBlock->RETCODES.DISCRETE.safpb_api_rc = saf78_SAF_RC_SUCCESS;
00606       }
00607    }
00608 
00609 
00610    /* Handle indefinite response */
00611    if (! Resolved)
00612    {
00613       /* Indicate decision made by SAF Manager */
00614       PBlock->safpb_safesm_index = 0;
00615 
00616       if (NumCalled == 0)
00617       {
00618          /* No enabled ESMs that implement Verify; accept everything */
00619          PBlock->RETCODES.DISCRETE.safpb_api_rc = saf78_SAF_RC_SUCCESS;
00620       }
00621       else
00622       {
00623          /***
00624          Default action based on configuration, except that we always
00625          allow unknown if verify-no-password is set.
00626          ***/
00627 
00628          if (AllowUnknownUsers || IsSysUser)
00629          {
00630             PBlock->RETCODES.DISCRETE.safpb_api_rc = saf78_SAF_RC_SUCCESS;
00631 
00632             /* AUDITEVENTCALL Verify allowed for unknown*/
00633             SafRaiseAuditEvent
00634             (
00635               AUDIT_EVENT_VERIFY_ALLOW_UNKNOWN
00636             , AUDIT_EVENT_CATEGORY_SEC_API_RES_ALLOW
00637             , 1
00638             , SafEventData
00639               (
00640                  AUDIT_RECORD_DATA_TYPE_STRING
00641                , (void*)UserBuf
00642                , (int)strlen(UserBuf)
00643               )
00644             );
00645          }
00646          else
00647          {
00648             /* Note this is audited below */
00649             PBlock->RETCODES.DISCRETE.safpb_api_rc = saf78_SAF_RC_FAILURE;
00650             PBlock->RETCODES.DISCRETE.safpb_mgr_return =
00651                saf78_RC_NO_USER_PROFILE;
00652          }
00653       }
00654    }
00655 
00656 
00657    /* Set Ret from final ESF return code */
00658    Ret = PBlock->RETCODES.DISCRETE.safpb_api_rc;
00659 
00660 
00661    /* If verify failed, we're done */
00662    if (Ret) goto done;
00663 
00664 
00665    /* Create ACEE, if none of the ESMs did */
00666    if (! PBlock->REQUESTS.VERIFY.safpb_verify_ACEE_ptr)
00667    {
00668       /* Allocate ACEE */
00669       /* TODO: Use default name mapping here */
00670       SRet = SafAceeAlloc(UserBuf, *GroupBuf? GroupBuf : NULL, &Acee, NULL);
00671       if (SRet)
00672       {
00673          Ret = saf78_SAF_RC_FAILURE;
00674          PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
00675       }
00676 
00677       if (SafCasOldAcee)
00678       {
00679          unsigned char *TmpPtr;
00680          TmpPtr = (unsigned char *)Acee;
00681          TmpPtr -= 8;                        /* back up to SAA area */
00682          PBlock->REQUESTS.VERIFY.safpb_verify_ACEE_ptr = (void *)TmpPtr;
00683       }
00684       else
00685          PBlock->REQUESTS.VERIFY.safpb_verify_ACEE_ptr = Acee;
00686 
00687       /* TEMPORARY: set access flags to "update" for CICS 1.7 security */
00688       memset(Acee->SecurityKeys, 0xff, sizeof Acee->SecurityKeys);
00689       memset(Acee->ResourceKeys, 0xff, sizeof Acee->ResourceKeys);
00690       memset(Acee->UserResourceKeys, 0xff, sizeof Acee->UserResourceKeys);
00691       memset(Acee->RdAccessFlags, 1, sizeof Acee->RdAccessFlags);
00692 
00693       /* TODO: Finish populating ACEE */
00694 
00695       /* TEMPORARY: Special settings for system users */
00696       if (IsSysUser)
00697       {
00698          if (SafSTRCMP(UserBuf, ==, "mfuser"))
00699          {
00700             Acee->Flag3 |= SafACEE_F3_DUID;        /* default user */
00701             memcpy(Acee->OperId, "mfu", 3);
00702             Acee->OperClass[2] = '\x01';
00703          }
00704          else
00705          {
00706             Acee->Flag3 |= SafACEE_F3_NPWR;        /* special user */
00707          }
00708       }
00709    }
00710 
00711    else
00712    {
00713       /***
00714       If CAS wants old-style ACEEs, and an ESM Module assigned a new-style
00715       ACEE to the parameter block, adjust the pointer.
00716       ***/
00717 
00718       unsigned char *AceePtr;
00719 
00720       AceePtr = (unsigned char *)PBlock->REQUESTS.VERIFY.safpb_verify_ACEE_ptr;
00721 
00722       if (SafCasOldAcee && memcmp(AceePtr, "ACEE", 4) == 0)
00723       {
00724          AceePtr -= 8;
00725          PBlock->REQUESTS.VERIFY.safpb_verify_ACEE_ptr = (void *)AceePtr;
00726       }
00727    }
00728 
00729 
00730 
00731    /* Clean up and return */
00732 done:
00733 
00734    if (PBlock)
00735    {
00736       /* Set return code in parameter block */
00737       PBlock->RETCODES.DISCRETE.safpb_api_rc = Ret;
00738 
00739       /* Raise audit events depending on return value */
00740       if (Ret >= saf78_SAF_RC_FAILURE)
00741       {
00742          switch (PBlock->RETCODES.DISCRETE.safpb_mgr_return)
00743          {
00744             case saf78_RC_PWRD_INVALID:
00745                /* AUDITEVENTCALL Verify Deny - invalid password */
00746                SafRaiseAuditEvent
00747                (
00748                   AUDIT_EVENT_VERIFY_PWD_INVALID
00749                 , AUDIT_EVENT_CATEGORY_SEC_API_RES_DENY
00750                 , 2
00751                 , SafEventData
00752                   (
00753                     AUDIT_RECORD_DATA_TYPE_STRING
00754                    ,PBlock->REQUESTS.VERIFY.safpb_verify_USERID_ptr
00755                    ,PBlock->REQUESTS.VERIFY.safpb_verify_USERID_len
00756                   )
00757                 , SafEventData
00758                   (
00759                     AUDIT_RECORD_DATA_TYPE_STRING
00760                    ,PBlock->REQUESTS.VERIFY.safpb_verify_group
00761                    ,sizeof(PBlock->REQUESTS.VERIFY.safpb_verify_group)
00762                   )
00763                );
00764                break;
00765               
00766             case saf78_RC_PWRD_EXPIRED:
00767                /* AUDITEVENTCALL Verify Deny - password expired */
00768                SafRaiseAuditEvent
00769                (
00770                   AUDIT_EVENT_VERIFY_PWD_EXPIRED
00771                 , AUDIT_EVENT_CATEGORY_SEC_API_RES_DENY
00772                 , 2
00773                 , SafEventData
00774                   (
00775                     AUDIT_RECORD_DATA_TYPE_STRING
00776                    ,PBlock->REQUESTS.VERIFY.safpb_verify_USERID_ptr
00777                    ,PBlock->REQUESTS.VERIFY.safpb_verify_USERID_len
00778                   )
00779                 , SafEventData
00780                   (
00781                     AUDIT_RECORD_DATA_TYPE_STRING
00782                    ,PBlock->REQUESTS.VERIFY.safpb_verify_group
00783                    ,sizeof(PBlock->REQUESTS.VERIFY.safpb_verify_group)
00784                   )
00785                );
00786                break;
00787 
00788             case saf78_RC_PWRD_CHANGE_ERR:
00789                /* AUDITEVENTCALL Verify Deny - password change error */
00790                SafRaiseAuditEvent
00791                (
00792                   AUDIT_EVENT_VERIFY_PWD_CHANGE
00793                 , AUDIT_EVENT_CATEGORY_SEC_API_RES_DENY
00794                 , 2
00795                 , SafEventData
00796                   (
00797                      AUDIT_RECORD_DATA_TYPE_STRING
00798                    , PBlock->REQUESTS.VERIFY.safpb_verify_USERID_ptr
00799                    , PBlock->REQUESTS.VERIFY.safpb_verify_USERID_len
00800                   )
00801                 , SafEventData
00802                   (
00803                      AUDIT_RECORD_DATA_TYPE_STRING
00804                    , PBlock->REQUESTS.VERIFY.safpb_verify_group
00805                    , sizeof(PBlock->REQUESTS.VERIFY.safpb_verify_group)
00806                   )
00807                );
00808                break;
00809 
00810             case saf78_RC_USER_NOT_IN_GROUP:
00811                /* AUDITEVENTCALL Verify Deny - user not in group */
00812                SafRaiseAuditEvent
00813                (
00814                   AUDIT_EVENT_VERIFY_USR_NOT_IN_GROUP
00815                 , AUDIT_EVENT_CATEGORY_SEC_API_RES_DENY
00816                 , 2
00817                 , SafEventData
00818                   (
00819                      AUDIT_RECORD_DATA_TYPE_STRING
00820                    , PBlock->REQUESTS.VERIFY.safpb_verify_USERID_ptr
00821                    , PBlock->REQUESTS.VERIFY.safpb_verify_USERID_len
00822                   )
00823                 , SafEventData
00824                   (
00825                      AUDIT_RECORD_DATA_TYPE_STRING
00826                    , PBlock->REQUESTS.VERIFY.safpb_verify_group
00827                    , sizeof(PBlock->REQUESTS.VERIFY.safpb_verify_group)
00828                   )
00829                );
00830                break;
00831             case saf78_RC_NO_USER_PROFILE:
00832                /* AUDITEVENTCALL Verify denied for unknown*/
00833                SafRaiseAuditEvent
00834                (
00835                  AUDIT_EVENT_VERIFY_DENY_UNKNOWN
00836                , AUDIT_EVENT_CATEGORY_SEC_API_RES_DENY
00837                , 2
00838                , SafEventData
00839                  (
00840                     AUDIT_RECORD_DATA_TYPE_STRING
00841                   , (void*)UserBuf
00842                   , (int)strlen(UserBuf)
00843                  )
00844                , SafEventData
00845                  (
00846                     AUDIT_RECORD_DATA_TYPE_STRING
00847                   , PBlock->REQUESTS.VERIFY.safpb_verify_group
00848                   , sizeof(PBlock->REQUESTS.VERIFY.safpb_verify_group)
00849                  )
00850                );
00851                break;
00852             default:
00853                /* AUDITEVENTCALL Verify Fail - unknown cause */
00854                SafRaiseAuditEvent
00855                (
00856                   AUDIT_EVENT_VERIFY_FAIL_UNKNOWN
00857                 , AUDIT_EVENT_CATEGORY_SEC_API_RES_DENY
00858                 , 2
00859                 , SafEventData
00860                   (
00861                      AUDIT_RECORD_DATA_TYPE_STRING
00862                    , PBlock->REQUESTS.VERIFY.safpb_verify_USERID_ptr
00863                    , PBlock->REQUESTS.VERIFY.safpb_verify_USERID_len
00864                   )
00865                 , SafEventData
00866                   (
00867                      AUDIT_RECORD_DATA_TYPE_STRING
00868                    , PBlock->REQUESTS.VERIFY.safpb_verify_group
00869                    , sizeof(PBlock->REQUESTS.VERIFY.safpb_verify_group)
00870                   )
00871                );
00872             
00873          }
00874       }
00875       else if (Ret == saf78_SAF_RC_SUCCESS)
00876       {
00877          /* AUDITEVENTCALL Verify Success*/
00878          SafRaiseAuditEvent
00879          (
00880             AUDIT_EVENT_VERIFY_SUCCESS
00881           , AUDIT_EVENT_CATEGORY_SEC_API_RES_ALLOW
00882           , 2
00883           , SafEventData
00884             (
00885                AUDIT_RECORD_DATA_TYPE_STRING
00886              , PBlock->REQUESTS.VERIFY.safpb_verify_USERID_ptr
00887              , PBlock->REQUESTS.VERIFY.safpb_verify_USERID_len
00888             )
00889           , SafEventData
00890             (
00891                AUDIT_RECORD_DATA_TYPE_STRING
00892              , PBlock->REQUESTS.VERIFY.safpb_verify_group
00893              , sizeof(PBlock->REQUESTS.VERIFY.safpb_verify_group)
00894             )
00895          );
00896       }
00897    }
00898 
00899    #if _DEBUG && SafLOG_ALL
00900       /* Log result */
00901       if (Ret) SafLog(2001, SafMsgINFO, "Verify failed for \"%s\"", UserBuf);
00902    #endif
00903 
00904    free(MUserBuf);
00905    return Ret;
00906 }
00907 
00925 int SafAuth(struct safpb_parameter_block *PBlock)
00926 {
00927    int Ret;
00928    int Resolved = 0;
00929    mf_uns32 CurrEsm, EsmRet, NumCalled = 0;
00930    unsigned char *AceePtr;
00931    if (!PBlock)
00932      return 0;
00933 
00934    /***
00935    It's possible we'll get called with old-style ACEEs, which had 8 bytes
00936    of other data before the eye-catcher. Actually, this should never happen
00937    in current code (which is why it's not handled for new functions like
00938    Admin), but it was handled for backward compatibility while the
00939    transition was being made, so this code is still here.
00940    ***/
00941 
00942    AceePtr = (unsigned char *)PBlock->REQUESTS.AUTH.safpb_auth_ACEE_ptr;
00943    if (memcmp(AceePtr, SafACEE_NAME, 4) != 0) AceePtr += 8;
00944 
00945    /*AUDITEVENTCALL Check: Auth */
00946    SafRaiseAuditEvent
00947    (
00948      AUDIT_EVENT_CHECK_AUTH
00949    , AUDIT_EVENT_CATEGORY_SEC_API_REQ_CHECK
00950    , 3
00951    , SafEventData
00952      (
00953        AUDIT_RECORD_DATA_TYPE_STRING
00954      ,((SafACEE *)AceePtr)->User
00955      ,((SafACEE *)AceePtr)->UserLen
00956      )
00957    , SafEventData
00958      (
00959        AUDIT_RECORD_DATA_TYPE_STRING
00960       ,PBlock->REQUESTS.AUTH.safpb_auth_class
00961       ,sizeof(PBlock->REQUESTS.AUTH.safpb_auth_class)
00962      )
00963    , SafEventData
00964      (
00965        AUDIT_RECORD_DATA_TYPE_STRING
00966       ,PBlock->REQUESTS.AUTH.safpb_auth_ENTITY_ptr
00967       ,PBlock->REQUESTS.AUTH.safpb_auth_ENTITY_len
00968      )
00969    );
00970    
00971 
00972    /* Check state */
00973    if (SafState() != 1)
00974    {
00975       Ret = saf78_SAF_RC_FAILURE;
00976       PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
00977       goto done;
00978    }
00979 
00980 
00981    /* Make sure we have no pending shared update notices */
00982    HandlePendingUpdates(NULL);
00983 
00984 
00985    /* Call ESM Modules */
00986    PBlock->RETCODES.DISCRETE.safpb_api_rc     = saf78_SAF_RC_NOT_COMPLETE;
00987    PBlock->RETCODES.DISCRETE.safpb_mgr_return = 0;
00988    PBlock->RETCODES.DISCRETE.safpb_mgr_reason = 0;
00989 
00990    Ret = saf78_SAF_RC_NOT_COMPLETE;
00991 
00992    for (CurrEsm=0; CurrEsm < NumESMMods && !Resolved; CurrEsm++)
00993    {
00994       const char *ErrType = NULL;
00995 
00996       /* Set ESM index in parameter block */
00997       PBlock->safpb_safesm_index = (unsigned char) CurrEsm + 1;
00998 
00999       /* Call ESM Module */
01000       EsmRet = SafEsmCAuth(CurrEsm, PBlock);
01001 
01002       /* Handle non-zero return codes */
01003       switch (EsmRet)
01004       {
01005 
01006          case SafESMRC_OK:
01007             /* Did we get a definite response? */
01008             if (PBlock->RETCODES.DISCRETE.safpb_api_rc !=
01009                 saf78_SAF_RC_NOT_COMPLETE)
01010             {
01011                Ret = PBlock->RETCODES.DISCRETE.safpb_api_rc;
01012                Resolved = 1;
01013             }
01014 
01015             /* Increment number of ESMs called successfully */
01016             NumCalled++;
01017             break;
01018 
01019          case SafESMRC_NOTIMPL:
01020             /* Not a definite response; keep trying */
01021             break;
01022 
01023          /* All other cases represent an ESM Module failure */
01024          case SafESMRC_PARAM:
01025             ErrType = "parameter error";
01026             break;
01027          case SafESMRC_RESOURCE:
01028             ErrType = "resource unavailable";
01029             break;
01030          case SafESMRC_EXTERNAL:
01031             ErrType = "ESM error";
01032             break;
01033          case SafESMRC_FAIL:
01034             ErrType = "miscellaneous failure";
01035             break;
01036          case SafESMRC_MGRFAIL:
01037             ErrType = "ESF Manager failure";
01038             break;
01039          default:
01040             ErrType = "unknown error";
01041             break;
01042       }
01043 
01044       /* Check for failure */
01045       if (ErrType)
01046       {
01047          mf_uns32 EsmNum = CurrEsm + 1;
01048          const char *EsmName = SafEsmName(CurrEsm);
01049 
01050          /* Log this */
01051          SafLog
01052          (
01053             111
01054           , SafMsgERR
01055           , "ESM Module %d (%s) returned error code %d (%s) from Auth"
01056           , EsmNum
01057           , EsmName
01058           , (int)EsmRet
01059           , ErrType
01060          );
01061           
01062          /* AUDITEVENTCALL Auth ESM Error*/
01063          SafRaiseAuditEvent
01064          (
01065             AUDIT_EVENT_AUTH_ESM_ERROR
01066           , AUDIT_EVENT_CATEGORY_SEC_API_RES_ERROR
01067           , 4
01068           , SafEventData
01069             (
01070                AUDIT_RECORD_DATA_TYPE_COMP5
01071              , &EsmNum
01072              , sizeof EsmNum
01073             )
01074           , SafEventData
01075             (
01076                AUDIT_RECORD_DATA_TYPE_STRING
01077              , EsmName
01078              , (int)strlen(EsmName)
01079             )
01080           , SafEventData
01081             (
01082                AUDIT_RECORD_DATA_TYPE_COMP5
01083              , &EsmRet
01084              , sizeof EsmRet
01085             )
01086           , SafEventData
01087             (
01088                AUDIT_RECORD_DATA_TYPE_STRING
01089              , ErrType
01090              , (int)strlen(ErrType)
01091             )
01092          );
01093 
01094          /* Convert to failure result */
01095          Ret = saf78_SAF_RC_FAILURE;
01096          PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
01097          Resolved = 1;
01098       }
01099    }
01100 
01101 
01102    /***
01103    Default based on configuration, though always allow if there are no
01104    enabled ESMs that implement Auth.
01105    ***/
01106 
01107    if (! Resolved)
01108    {
01109       /* Indicate decision made by SAF Manager */
01110       PBlock->safpb_safesm_index = 0;
01111 
01112       if (NumCalled == 0 || AllowUnknownResources)
01113       {
01114          Ret = saf78_SAF_RC_SUCCESS;
01115 
01116          /* Answer a permissions query with the highest possible level */
01117          if (PBlock->safpb_type == saf78_TYPE_ATTR_STATUS_ACC)
01118          {
01119             PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_ACCESS_INFO;
01120             PBlock->RETCODES.DISCRETE.safpb_mgr_reason = saf78_RS_ACCESS_ALTER;
01121          }
01122          else
01123          {
01124             /* Just a regular access check */
01125             PBlock->RETCODES.DISCRETE.safpb_mgr_return = 0;
01126             PBlock->RETCODES.DISCRETE.safpb_mgr_reason = 0;
01127          }
01128       }
01129       else
01130       {
01131          /* Is this a permissions query? */
01132          if (PBlock->safpb_type == saf78_TYPE_ATTR_STATUS_ACC)
01133          {
01134             Ret = saf78_SAF_RC_SUCCESS;
01135             PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_ACCESS_INFO;
01136             PBlock->RETCODES.DISCRETE.safpb_mgr_reason = saf78_RS_ACCESS_NONE;
01137          }
01138          else
01139          {
01140             Ret = saf78_SAF_RC_NOT_COMPLETE;
01141             PBlock->RETCODES.DISCRETE.safpb_mgr_return =
01142                saf78_RC_RESOURCE_NOT_PROT;
01143             PBlock->RETCODES.DISCRETE.safpb_mgr_reason =
01144                saf78_RS_NO_RESOURCE_PROF;
01145          }
01146       }
01147    }
01148 
01149    if (Ret)
01150    {
01151       char UserBuf[9], ClassBuf[9], ResourceBuf[32];
01152       SafACEE *Acee;
01153       unsigned char *AceePtr;
01154       size_t Len;
01155 
01156       AceePtr = (unsigned char *)PBlock->REQUESTS.AUTH.safpb_auth_ACEE_ptr;
01157       if (memcmp(AceePtr, SafACEE_NAME, 4) != 0) AceePtr += 8;
01158       Acee = (SafACEE *)AceePtr;
01159       memcpy(UserBuf, Acee->User, 8);
01160       UserBuf[Acee->UserLen] = '\0';
01161 
01162       memcpy(ClassBuf, PBlock->REQUESTS.AUTH.safpb_auth_class, 8);
01163       ClassBuf[8] = '\0';
01164 
01165       Len = PBlock->REQUESTS.AUTH.safpb_auth_ENTITY_len;
01166       if (Len > sizeof ResourceBuf - 1) Len = sizeof ResourceBuf - 1;
01167       memcpy(ResourceBuf, PBlock->REQUESTS.AUTH.safpb_auth_ENTITY_ptr, Len);
01168       ResourceBuf[Len] = '\0';
01169 
01170       /* AUDITEVENTCALL Auth Deny*/
01171       SafRaiseAuditEvent
01172       (
01173           AUDIT_EVENT_AUTH_DENY
01174         , AUDIT_EVENT_CATEGORY_SEC_API_RES_DENY
01175         , 3
01176         , SafEventData
01177           (
01178              AUDIT_RECORD_DATA_TYPE_STRING
01179            , UserBuf
01180            , (int)strlen(UserBuf)
01181           )
01182         , SafEventData
01183           (
01184              AUDIT_RECORD_DATA_TYPE_STRING
01185            , ClassBuf
01186            , (int)strlen(ClassBuf)
01187           )
01188         , SafEventData
01189           (
01190              AUDIT_RECORD_DATA_TYPE_STRING
01191            , ResourceBuf
01192            , (int)strlen(ResourceBuf)
01193           )
01194       );
01195 
01196       #if _DEBUG && SafLOG_ALL
01197          SafLog
01198          (
01199             2003
01200           , SafMsgINFO
01201           , "Auth failed for user \"%s\", class \"%s\", entity \"%s\""
01202           , UserBuf
01203           , ClassBuf
01204           , ResourceBuf
01205          );
01206       #endif
01207    }
01208 
01209 done:
01210    if (PBlock) PBlock->RETCODES.DISCRETE.safpb_api_rc = Ret;
01211    return Ret;
01212 }
01213 
01214 
01215 
01226 int SafXauth(struct safpb_parameter_block *PBlock)
01227 {
01228    int Ret;
01229    int Resolved = 0;
01230    mf_uns32 CurrEsm, EsmRet, NumCalled = 0;
01231 
01232    unsigned char *AceePtr;
01233    if (!PBlock)
01234      return 0;
01235 
01236    AceePtr = (unsigned char *)PBlock->REQUESTS.AUTH.safpb_auth_ACEE_ptr;
01237    if (memcmp(AceePtr, SafACEE_NAME, 4) != 0) AceePtr += 8;
01238 
01239    /*AUDITEVENTCALL Check: XAuth */
01240    SafRaiseAuditEvent
01241    (
01242      AUDIT_EVENT_CHECK_XAUTH
01243    , AUDIT_EVENT_CATEGORY_SEC_API_REQ_CHECK
01244    , 3
01245    , SafEventData
01246      (
01247        AUDIT_RECORD_DATA_TYPE_STRING
01248      ,((SafACEE *)AceePtr)->User
01249      ,((SafACEE *)AceePtr)->UserLen
01250      )
01251    , SafEventData
01252      (
01253        AUDIT_RECORD_DATA_TYPE_STRING
01254       ,PBlock->REQUESTS.AUTH.safpb_auth_class
01255       ,sizeof(PBlock->REQUESTS.AUTH.safpb_auth_class)
01256      )
01257    , SafEventData
01258      (
01259        AUDIT_RECORD_DATA_TYPE_STRING
01260       ,PBlock->REQUESTS.AUTH.safpb_auth_ENTITY_ptr
01261       ,PBlock->REQUESTS.AUTH.safpb_auth_ENTITY_len
01262      )
01263    );
01264 
01265    /* Check state */
01266    if (SafState() != 1)
01267    {
01268       Ret = saf78_SAF_RC_FAILURE;
01269       PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
01270       goto done;
01271    }
01272 
01273 
01274    /* Make sure we have no pending shared update notices */
01275    HandlePendingUpdates(NULL);
01276 
01277 
01278    /* Call ESM Modules */
01279    PBlock->RETCODES.DISCRETE.safpb_api_rc     = saf78_SAF_RC_NOT_COMPLETE;
01280    PBlock->RETCODES.DISCRETE.safpb_mgr_return = 0;
01281    PBlock->RETCODES.DISCRETE.safpb_mgr_reason = 0;
01282 
01283    Ret = saf78_SAF_RC_NOT_COMPLETE;
01284 
01285    for (CurrEsm=0; CurrEsm < NumESMMods && !Resolved; CurrEsm++)
01286    {
01287       const char *ErrType = NULL;
01288 
01289       /* Set ESM index in parameter block */
01290       PBlock->safpb_safesm_index = (unsigned char) CurrEsm + 1;
01291 
01292       /* Call ESM Module */
01293       EsmRet = SafEsmCXAuth(CurrEsm, PBlock);
01294 
01295       /* Handle non-zero return codes */
01296       switch (EsmRet)
01297       {
01298 
01299          case SafESMRC_OK:
01300             /* Did we get a definite response? */
01301             if (PBlock->RETCODES.DISCRETE.safpb_api_rc !=
01302                 saf78_SAF_RC_NOT_COMPLETE)
01303             {
01304                Ret = PBlock->RETCODES.DISCRETE.safpb_api_rc;
01305                Resolved = 1;
01306             }
01307 
01308             /* Increment number of ESMs called successfully */
01309             NumCalled++;
01310             break;
01311 
01312          case SafESMRC_NOTIMPL:
01313             /* Not a definite response; keep trying */
01314             break;
01315 
01316          /* All other cases represent an ESM Module failure */
01317          case SafESMRC_PARAM:
01318             ErrType = "parameter error";
01319             break;
01320          case SafESMRC_RESOURCE:
01321             ErrType = "resource unavailable";
01322             break;
01323          case SafESMRC_EXTERNAL:
01324             ErrType = "ESM error";
01325             break;
01326          case SafESMRC_FAIL:
01327             ErrType = "miscellaneous failure";
01328             break;
01329          case SafESMRC_MGRFAIL:
01330             ErrType = "ESF Manager failure";
01331             break;
01332          default:
01333             ErrType = "unknown error";
01334             break;
01335       }
01336 
01337       /* Check for failure */
01338       if (ErrType)
01339       {
01340          mf_uns32 EsmNum = CurrEsm + 1;
01341          const char *EsmName = SafEsmName(CurrEsm);
01342 
01343          /* Log this */
01344          SafLog
01345          (
01346             112
01347           , SafMsgERR
01348           , "ESM Module %d (%s) returned error code %d (%s) from XAuth"
01349           , EsmNum
01350           , EsmName
01351           , (int)EsmRet
01352           , ErrType
01353          );
01354 
01355          /* AUDITEVENTCALL XAuth ESM Error*/
01356          SafRaiseAuditEvent
01357          (
01358             AUDIT_EVENT_XAUTH_ESM_ERROR
01359           , AUDIT_EVENT_CATEGORY_SEC_API_RES_ERROR
01360           , 4
01361           , SafEventData
01362             (
01363                AUDIT_RECORD_DATA_TYPE_COMP5
01364              , &EsmNum
01365              , sizeof EsmNum
01366             )
01367           , SafEventData
01368             (
01369                AUDIT_RECORD_DATA_TYPE_STRING
01370              , EsmName
01371              , (int)strlen(EsmName)
01372             )
01373           , SafEventData
01374             (
01375                AUDIT_RECORD_DATA_TYPE_COMP5
01376              , &EsmRet
01377              , sizeof EsmRet
01378             )
01379           , SafEventData
01380             (
01381                AUDIT_RECORD_DATA_TYPE_STRING
01382              , ErrType
01383              , (int)strlen(ErrType)
01384             )
01385          );
01386 
01387          /* Convert to failure result */
01388          Ret = saf78_SAF_RC_FAILURE;
01389          PBlock->RETCODES.DISCRETE.safpb_mgr_return =
01390             saf78_RC_DATABASE_ERROR;
01391          Resolved = 1;
01392       }
01393    }
01394 
01395 
01396    /***
01397    Default based on configuration, though always allow if there are no
01398    enabled ESMs that implement Auth.
01399    ***/
01400 
01401    if (! Resolved)
01402    {
01403       /* Indicate decision made by SAF Manager */
01404       PBlock->safpb_safesm_index = 0;
01405 
01406       if (NumCalled == 0 || AllowUnknownResources)
01407       {
01408          Ret = saf78_SAF_RC_SUCCESS;
01409          PBlock->RETCODES.DISCRETE.safpb_mgr_return = 0;
01410          PBlock->RETCODES.DISCRETE.safpb_mgr_reason = 0;
01411 
01412          if (PBlock->safpb_type == saf78_TYPE_ATTR_STATUS_ACC)
01413          {
01414             PBlock->REQUESTS.XAUTH.safpb_xauth_PERMISSIONS =
01415                saf78_PERM_READ
01416              | saf78_PERM_UPDATE
01417              | saf78_PERM_EXECUTE
01418              | saf78_PERM_CONTROL
01419              | saf78_PERM_ALTER;
01420          }
01421       }
01422       else
01423       {
01424          /* Is this a permissions query? */
01425          if (PBlock->safpb_type == saf78_TYPE_ATTR_STATUS_ACC)
01426          {
01427             Ret = saf78_SAF_RC_SUCCESS;
01428             PBlock->RETCODES.DISCRETE.safpb_mgr_return = 0;
01429             PBlock->RETCODES.DISCRETE.safpb_mgr_reason = 0;
01430             PBlock->REQUESTS.XAUTH.safpb_xauth_PERMISSIONS = 0;
01431          }
01432          else
01433          {
01434             Ret = saf78_SAF_RC_NOT_COMPLETE;
01435             PBlock->RETCODES.DISCRETE.safpb_mgr_return =
01436                saf78_RC_RESOURCE_NOT_PROT;
01437             PBlock->RETCODES.DISCRETE.safpb_mgr_reason =
01438                saf78_RS_NO_RESOURCE_PROF;
01439          }
01440       }
01441    }
01442 
01443    if (Ret)
01444    {
01445       char UserBuf[9], ClassBuf[40], ResourceBuf[40];
01446       SafACEE *Acee;
01447       unsigned char *AceePtr;
01448       size_t Len;
01449 
01450       AceePtr = (unsigned char *)PBlock->REQUESTS.XAUTH.safpb_xauth_ACEE_ptr;
01451       if (memcmp(AceePtr, SafACEE_NAME, 4) != 0) AceePtr += 8;
01452       Acee = (SafACEE *)AceePtr;
01453       memcpy(UserBuf, Acee->User, 8);
01454       UserBuf[Acee->UserLen] = '\0';
01455 
01456       Len = PBlock->REQUESTS.XAUTH.safpb_xauth_CLASS_len;
01457       if (Len > sizeof ClassBuf - 1) Len = sizeof ClassBuf - 1;
01458       memcpy(ClassBuf, PBlock->REQUESTS.XAUTH.safpb_xauth_CLASS_ptr, Len);
01459       ClassBuf[Len] = '\0';
01460 
01461       Len = PBlock->REQUESTS.XAUTH.safpb_xauth_ENTITY_len;
01462       if (Len > sizeof ResourceBuf - 1) Len = sizeof ResourceBuf - 1;
01463       memcpy(ResourceBuf, PBlock->REQUESTS.XAUTH.safpb_xauth_ENTITY_ptr, Len);
01464       ResourceBuf[Len] = '\0';
01465 
01466       #if _DEBUG && SafLOG_ALL
01467          SafLog
01468          (
01469             2003
01470           , SafMsgINFO
01471           , "XAuth failed for user \"%s\", class \"%s\", entity \"%s\""
01472           , UserBuf
01473           , ClassBuf
01474           , ResourceBuf
01475          );
01476       #endif
01477 
01478       /* AUDITEVENTCALL XAuth Deny*/
01479       SafRaiseAuditEvent
01480       (
01481           AUDIT_EVENT_XAUTH_DENY
01482         , AUDIT_EVENT_CATEGORY_SEC_API_RES_DENY
01483         , 3
01484         , SafEventData
01485           (
01486              AUDIT_RECORD_DATA_TYPE_STRING
01487            , UserBuf
01488            , (int)strlen(UserBuf)
01489           )
01490         , SafEventData
01491           (
01492              AUDIT_RECORD_DATA_TYPE_STRING
01493            , ClassBuf
01494            , (int)strlen(ClassBuf)
01495           )
01496         , SafEventData
01497           (
01498              AUDIT_RECORD_DATA_TYPE_STRING
01499            , ResourceBuf
01500            , (int)strlen(ResourceBuf)
01501           )
01502       );
01503 
01504    }
01505 
01506 done:
01507    if (PBlock) PBlock->RETCODES.DISCRETE.safpb_api_rc = Ret;
01508    return Ret;
01509 }
01510 
01511 
01512 
01527 int SafStat(struct safpb_parameter_block *PBlock)
01528 {
01529    int Ret = saf78_SAF_RC_NOT_COMPLETE;
01530 
01531    if (PBlock) PBlock->RETCODES.DISCRETE.safpb_api_rc = Ret;
01532    return Ret;
01533 }
01534 
01535 
01536 
01551 int SafAudit(struct safpb_parameter_block *PBlock)
01552 {
01553    int Ret = saf78_SAF_RC_NOT_COMPLETE;
01554 
01555    if (PBlock) PBlock->RETCODES.DISCRETE.safpb_api_rc = Ret;
01556    return Ret;
01557 }
01558 
01559 
01560 
01561 
01575 int SafAdmin(struct safpb_parameter_block *PBlock)
01576 {
01577    int Ret;
01578    mf_uns32 CurrEsm, EsmRet;
01579    const char *ErrType = NULL;
01580    int ReqType = -1, IsList = 0;
01581    SafACEE *AceePtr = NULL;
01582    const char *CmdName = "invalid";
01583    int CmdLen;
01584 
01585 
01586    if (!PBlock)
01587       return 0;
01588 
01589    /* Extract info for messages and audit events */
01590    AceePtr = PBlock->REQUESTS.ADMIN.safpb_admin_ACEE_ptr;
01591 
01592    if (PBlock->safpb_type > 0 &&
01593        PBlock->safpb_type < sizeof sSafCommands / sizeof *sSafCommands)
01594    {
01595       CmdName = sSafCommands[PBlock->safpb_type-1].safadmin_cmdname;
01596       CmdLen  = sSafCommands[PBlock->safpb_type-1].safadmin_cmdlen;
01597    }
01598    else
01599    {
01600       CmdLen = (int)strlen(CmdName);
01601    }
01602 
01603    /* Check state */
01604    if (SafState() != 1)
01605    {
01606       Ret = saf78_SAF_RC_FAILURE;
01607       PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
01608       goto done;
01609    }
01610 
01611    /* Determine request type */
01612    switch (PBlock->safpb_type)
01613    {
01614       case saf78_TYPE_ADMIN_LISTUSER:
01615       case saf78_TYPE_ADMIN_LISTGROUP:
01616       case saf78_TYPE_ADMIN_LISTRES:
01617       case saf78_TYPE_ADMIN_LISTCLASS:
01618          ReqType = AUDIT_EVENT_ADMIN_LIST;
01619          IsList = 1;
01620          break;
01621       case saf78_TYPE_ADMIN_ADDUSER:
01622       case saf78_TYPE_ADMIN_ADDGROUP:
01623       case saf78_TYPE_ADMIN_ADDRES:
01624       case saf78_TYPE_ADMIN_ADDCLASS:
01625          ReqType = AUDIT_EVENT_ADMIN_ADD;
01626          break;
01627       case saf78_TYPE_ADMIN_DELUSER:
01628       case saf78_TYPE_ADMIN_DELGROUP:
01629       case saf78_TYPE_ADMIN_DELRES:
01630       case saf78_TYPE_ADMIN_DELCLASS:
01631          ReqType = AUDIT_EVENT_ADMIN_DELETE;
01632          break;
01633       case saf78_TYPE_ADMIN_ALTUSER:
01634       case saf78_TYPE_ADMIN_ALTGROUP:
01635       case saf78_TYPE_ADMIN_ALTRES:
01636       case saf78_TYPE_ADMIN_ALTCLASS:
01637          ReqType = AUDIT_EVENT_ADMIN_ALTER;
01638          break;
01639       case saf78_TYPE_ADMIN_SETPSWD:
01640          ReqType = AUDIT_EVENT_ADMIN_SETPWD;
01641          break;
01642       case saf78_TYPE_ADMIN_SETOPTS:
01643          ReqType = AUDIT_EVENT_ADMIN_SETOPT;
01644          break;
01645    }
01646 
01647    if (PBlock->safpb_type == saf78_TYPE_ADMIN_FREELIST) IsList = 1;
01648 
01649    /* AUDITEVENTCALL Define */
01650    if (ReqType >= 0) 
01651    {
01652       Ret = AuditAdminReq(PBlock, ReqType, AceePtr, CmdName, CmdLen);
01653 
01654       if (Ret)
01655       {
01656          /* TODO: log this */
01657          goto done;
01658       }
01659    }
01660 
01661    /***
01662    Check ACEE. We don't allow an admin request using an ACEE that was
01663    allocated with no-password-required, unless it's a LIST request and
01664    the [Admin] / allow-list option was specified (RPI 548616). (This
01665    can also be set using the ES_ESF_ALLOW_LIST environment variable, 
01666    but that's undocumented and used only by Testing.)
01667    ***/
01668 
01669    if (AceePtr && (AceePtr->Flag3 & SafACEE_F3_NPWR))
01670    {
01671       static int AllowList = -1;
01672       char *ALVal = NULL;
01673 
01674       if (AllowList < 0)
01675       {
01676          /***
01677          No need to serialize this - the persistent assignment is atomic
01678          and all threads would compute the same value.
01679          ***/
01680 
01681          SafQueryCfg("Admin", "allow-list", &ALVal);
01682          AllowList = (ALVal && tolower((unsigned char)*ALVal) == 'y');
01683       }
01684 
01685       /***
01686       Error if this is a non-list request, or if anonymous list requests
01687       are not allowed.
01688       ***/
01689 
01690       if (!IsList || !AllowList)
01691       {
01692          SafLog
01693          (
01694             106
01695           , SafMsgERR
01696           , "Admin request denied for unauthenticated user"
01697          );
01698          Ret = saf78_SAF_RC_FAILURE;
01699          PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DENIED;
01700          goto done;
01701       }
01702    }
01703 
01704    /***
01705    For LISTx requests, we need to allocate the array of response lists
01706    in the request control block.
01707    ***/
01708 
01709    if (ReqType == AUDIT_EVENT_ADMIN_LIST)
01710    {
01711       PBlock->REQUESTS.ADMIN.safpb_admin_LIST_ptr = malloc
01712       (
01713          SafESM_MAX * sizeof *PBlock->REQUESTS.ADMIN.safpb_admin_LIST_ptr
01714       );
01715 
01716       if (! PBlock->REQUESTS.ADMIN.safpb_admin_LIST_ptr)
01717       {
01718          Ret = saf78_SAF_RC_FAILURE;
01719          PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
01720          goto done;
01721       }
01722    }
01723 
01724 
01725    /* Make sure we have no pending shared update notices */
01726    HandlePendingUpdates(NULL);
01727 
01728 
01729    /* Was a specific module requested? */
01730    if (PBlock->safpb_safesm_index)
01731    {
01732       /***
01733       Set CurrEsm for error-reporting purposes.  Note that it's set to
01734       the ESM's index plus one (ie the value of safpb_safesm_index), to
01735       simulate what would happen if we exited the for-loop below with an
01736       error.
01737       ***/
01738 
01739       CurrEsm = PBlock->safpb_safesm_index;
01740 
01741       /* Call ESM Module */
01742       EsmRet = SafEsmCAdmin(PBlock->safpb_safesm_index - 1, PBlock);
01743       if (! EsmRet)
01744          Ret = PBlock->RETCODES.DISCRETE.safpb_api_rc;
01745    }
01746 
01747    else
01748    {
01749       /* Call all enabled ESM Modules */
01750       PBlock->RETCODES.DISCRETE.safpb_api_rc     = saf78_SAF_RC_NOT_COMPLETE;
01751       PBlock->RETCODES.DISCRETE.safpb_mgr_return = 0;
01752       PBlock->RETCODES.DISCRETE.safpb_mgr_reason = 0;
01753 
01754       Ret = saf78_SAF_RC_NOT_COMPLETE;
01755 
01756       for (CurrEsm=0, EsmRet = 0;
01757            CurrEsm < NumESMMods && Ret <= saf78_SAF_RC_NOT_COMPLETE && !EsmRet;
01758            CurrEsm++)
01759       {
01760 
01761          /* Set ESM index in parameter block */
01762          PBlock->safpb_safesm_index = (unsigned char) CurrEsm + 1;
01763 
01764          /* Call ESM Module */
01765          EsmRet = SafEsmCAdmin(CurrEsm, PBlock);
01766 
01767          /* Handle non-zero return codes */
01768          switch (EsmRet)
01769          {
01770 
01771             case SafESMRC_OK:
01772                /* Check for failure response */
01773                Ret = PBlock->RETCODES.DISCRETE.safpb_api_rc;
01774                break;
01775 
01776             case SafESMRC_NOTIMPL:
01777                /* Not a definite response; keep trying */
01778                EsmRet = 0;
01779                break;
01780 
01781             /* All other cases represent an ESM Module failure */
01782             default:
01783                break;
01784          }
01785       }
01786    }
01787 
01788    /* Check for ESM Module failure */
01789    if (EsmRet > SafESMRC_NOTIMPL) ErrType = EsmrcToString(EsmRet);
01790    if (ErrType)
01791    {
01792       /* Log this */
01793       SafLog
01794       (
01795          113
01796        , SafMsgERR
01797        , "ESM Module %d (%s) returned error code %d (%s) from Admin"
01798        , CurrEsm
01799        , SafEsmName(CurrEsm-1)
01800        , (int)EsmRet
01801        , ErrType
01802       );
01803 
01804       /* Convert to failure result */
01805       Ret = saf78_SAF_RC_FAILURE;
01806       PBlock->RETCODES.DISCRETE.safpb_mgr_return =
01807          saf78_RC_DATABASE_ERROR;
01808    }
01809 
01810 done:
01811    /* Log / audit request failure */
01812    if (Ret && PBlock)
01813    {
01814       SafLog
01815       (
01816          103
01817        , SafMsgWARN
01818        , "Admin %.*s request failed: %d"
01819        , CmdLen
01820        , CmdName
01821        , (int) Ret
01822       );
01823 
01824       /* Audit Admin failure */
01825       if (AceePtr) SafRaiseAuditEvent
01826       (
01827         AUDIT_EVENT_ADMIN_ESM_ERROR
01828       , AUDIT_EVENT_CATEGORY_SEC_API_RES_ERROR
01829       , 3
01830       , SafEventData
01831         (
01832           AUDIT_RECORD_DATA_TYPE_STRING
01833         , CmdName
01834         , CmdLen
01835         )
01836       , SafEventData
01837         (
01838           AUDIT_RECORD_DATA_TYPE_COMP5
01839         , & PBlock->safpb_type
01840         , sizeof PBlock->safpb_type
01841         )
01842       , SafEventData
01843         (
01844           AUDIT_RECORD_DATA_TYPE_STRING
01845         , AceePtr->User
01846         , AceePtr->UserLen
01847         )
01848       );
01849    }
01850 
01851    if (! Ret)
01852    {
01853       /* Audit Admin success */
01854       if (AceePtr) SafRaiseAuditEvent
01855       (
01856         AUDIT_EVENT_ADMIN_SUCCESS
01857       , AUDIT_EVENT_CATEGORY_SEC_API_RES_SUCCESS
01858       , 3
01859       , SafEventData
01860         (
01861           AUDIT_RECORD_DATA_TYPE_STRING
01862         , CmdName
01863         , CmdLen
01864         )
01865       , SafEventData
01866         (
01867           AUDIT_RECORD_DATA_TYPE_COMP5
01868         , & PBlock->safpb_type
01869         , sizeof PBlock->safpb_type
01870         )
01871       , SafEventData
01872         (
01873           AUDIT_RECORD_DATA_TYPE_STRING
01874         , AceePtr->User
01875         , AceePtr->UserLen
01876         )
01877       );
01878    }
01879 
01880    if (PBlock) PBlock->RETCODES.DISCRETE.safpb_api_rc = Ret;
01881    return Ret;
01882 }
01883 
01884 
01885 /***
01886 Helper for auditing admin requests: add an audit parameter.
01887 ***/
01888 
01889 static SafRet AddAuditParam(struct TEventData *AuditParams[],
01890                             unsigned *IdxPtr,
01891                             int Type, const void *Data, int Length)
01892 {
01893    AuditParams[*IdxPtr] = malloc(sizeof **AuditParams);
01894    if (! AuditParams[*IdxPtr]) return SafR_RESOURCE;
01895 
01896    AuditParams[*IdxPtr]->data     = Data;
01897    AuditParams[*IdxPtr]->datalen  = Length;
01898    AuditParams[*IdxPtr]->datatype = Type;
01899 
01900    *IdxPtr += 1;
01901 
01902    return SafR_OK;
01903 }
01904 
01905 
01906 /***
01907 Helper for auditing admin requests: raises an audit event for the admin
01908 request, including all the parameters - except password, if it's supplied.
01909 ***/
01910 
01911 static SafRet AuditAdminReq(struct safpb_parameter_block *PBlock,
01912                             int ReqType, SafACEE *AceePtr,
01913                             const char *CmdName, int CmdLen)
01914 {
01915    SafRet Ret = SafR_OK;
01916    struct TEventData **AuditParams = NULL;
01917    unsigned ParamIdx = 0, KVIdx = 0, TmpIdx;
01918    char **KeyValArray = NULL;
01919 
01920    /***
01921    Allocate audit parameter pointer array: entries for command name, command
01922    code, and username, plus one for each parameter.  Allocate array of
01923    key=val strings, which has one entry for each admin parameter.
01924    ***/
01925 
01926    AuditParams = malloc
01927    (
01928       sizeof *AuditParams
01929       * (3 + PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_count)
01930    );
01931    if (! AuditParams)
01932    {
01933       Ret = SafR_RESOURCE;
01934       goto done;
01935    }
01936 
01937    KeyValArray = malloc
01938    (
01939       sizeof *KeyValArray * PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_count
01940    );
01941    if (! KeyValArray)
01942    {
01943       Ret = SafR_RESOURCE;
01944       goto done;
01945    }
01946 
01947 
01948    /* Create the fixed parameters */
01949    Ret = AddAuditParam
01950    (
01951       AuditParams
01952     , &ParamIdx 
01953     , AUDIT_RECORD_DATA_TYPE_STRING
01954     , CmdName
01955     , CmdLen
01956    );
01957    if (Ret) goto done;
01958 
01959 
01960    Ret = AddAuditParam
01961    (
01962       AuditParams
01963     , &ParamIdx 
01964     , AUDIT_RECORD_DATA_TYPE_COMP5
01965     , & PBlock->safpb_type
01966     , sizeof PBlock->safpb_type
01967    );
01968    if (Ret) goto done;
01969 
01970 
01971    Ret = AddAuditParam
01972    (
01973       AuditParams
01974     , &ParamIdx 
01975     , AUDIT_RECORD_DATA_TYPE_STRING
01976     , AceePtr? AceePtr->User : "(anonymous)"
01977     , AceePtr? AceePtr->UserLen : 11
01978    );
01979    if (Ret) goto done;
01980 
01981 
01982    /* Create the parameters for the admin parameters */
01983    for (KVIdx = 0;
01984         KVIdx < PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_count;
01985         KVIdx++)
01986    {
01987       size_t KVStrLen;
01988       char *KVPtr;
01989 
01990       /* Allocate buffer for key=value string */
01991       KVStrLen =
01992          PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_ptr[KVIdx].KeyLen
01993        + 1
01994        + PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_ptr[KVIdx].ValLen;
01995       KeyValArray[KVIdx] = malloc(KVStrLen);
01996       if (! KeyValArray[KVIdx])
01997       {
01998          Ret = SafR_RESOURCE;
01999          goto done;
02000       }
02001 
02002       /* Create string */
02003       KVPtr = KeyValArray[KVIdx];
02004       memcpy
02005       (
02006          KVPtr
02007        , PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_ptr[KVIdx].KeyPtr
02008        , PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_ptr[KVIdx].KeyLen
02009       );
02010       KVPtr += PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_ptr[KVIdx].KeyLen;
02011       *KVPtr++ = '=';
02012 
02013       /* Special handling for PASSWORD */
02014       if (SafSTRCMP_CIN(KeyValArray[KVIdx], ==, "PASSWORD=", 9))
02015       {
02016          memset
02017          (
02018             KVPtr
02019           , '*'
02020           , PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_ptr[KVIdx].ValLen
02021          );
02022       }
02023       else
02024       {
02025          memcpy
02026          (
02027             KVPtr
02028           , PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_ptr[KVIdx].ValPtr
02029           , PBlock->REQUESTS.ADMIN.safpb_admin_ARGTBL_ptr[KVIdx].ValLen
02030          );
02031       }
02032 
02033       /* Add audit parameter */
02034       Ret = AddAuditParam
02035       (
02036          AuditParams
02037        , &ParamIdx
02038        , AUDIT_RECORD_DATA_TYPE_STRING
02039        , KeyValArray[KVIdx]
02040        , (int)KVStrLen
02041       );
02042       if (Ret) goto done;
02043    }
02044 
02045    /* Raise the event */
02046    Ret = SafRaiseAuditEventA
02047    (
02048       ReqType
02049     , AUDIT_EVENT_CATEGORY_SEC_API_REQ_DEFINE
02050     , ParamIdx
02051     , AuditParams
02052    );
02053 
02054    /* Clean up */
02055 done:
02056    if (AuditParams)
02057    {
02058       for (TmpIdx = 0; TmpIdx < ParamIdx; TmpIdx++)
02059          free(AuditParams[TmpIdx]);
02060       free(AuditParams);
02061    }
02062 
02063    if (KeyValArray)
02064    {
02065       for (TmpIdx = 0; TmpIdx < KVIdx; TmpIdx++)
02066          free(KeyValArray[TmpIdx]);
02067       free(KeyValArray);
02068    }
02069 
02070    return Ret;
02071 }
02072 
02073 
02074 /***
02075 Translate an "other" ESM return code to a string. Note these return codes
02076 apply to eg Admin and Update, but not to eg Verify and Auth; see the ESM
02077 Module Interface documentation for more information.
02078 ***/
02079 
02080 static const char *EsmrcToString(mf_uns32 EsmRet)
02081 {
02082    switch (EsmRet)
02083    {
02084       case SafESMRC_OK:          return "no error";
02085       case SafESMRC_NOTIMPL:     return "function not implemented";
02086       case SafESMRC_PARAM:       return "parameter error";
02087       case SafESMRC_RESOURCE:    return "resource unavailable";
02088       case SafESMRC_EXTERNAL:    return "ESM error";
02089       case SafESMRC_FAIL:        return "miscellaneous failure";
02090       case SafESMRC_MGRFAIL:     return "ESF Manager failure";
02091       default:                   return "unknown error";
02092    }
02093 }
02094 
02095 
02096 
02238 /* The private update sequence number for this process */
02239 static mf_uns32 UpdateSequenceNumber;
02240 
02241 
02242 
02271 int SafUpdate(struct safpb_parameter_block *PBlock)
02272 {
02273    int Ret = saf78_SAF_RC_NOT_COMPLETE;
02274    int Locked = 0;
02275    struct UpdateCache *Cache = NULL;
02276    struct safpb_update *Update;
02277    mf_uns32 CurrEsm, EsmRet = 0;
02278    const char *ErrType = NULL;
02279    SafACEE *Acee;
02280 
02281    /* Sanity check */
02282    if (! PBlock) goto done;
02283 
02284    /* Check state */
02285    if (SafState() != 1)
02286    {
02287       Ret = saf78_SAF_RC_FAILURE;
02288       PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
02289       goto done;
02290    }
02291 
02292    /* Address parts of the request for convenience */
02293    Acee = PBlock->REQUESTS.UPDATE.safpb_update_ACEE_ptr;
02294    Update = &PBlock->REQUESTS.UPDATE;
02295 
02296    /* Is this is a multiprocess shared-memory environment? */
02297    Locked = LockUpdateArea();
02298    if (Locked)
02299    {
02300       size_t Len;
02301 
02302       /* Get the update cache area */
02303       Cache = GetUpdateCache();
02304       if (! Cache) goto done;
02305 
02306       /***
02307       Check for pending requests that we haven't processed, by comparing
02308       our last-update-processed sequence number with the sequence number
02309       of the current saved update:
02310 
02311       - If they're the same, we already processed the saved update.
02312       Continue with the request we were called with.
02313 
02314       - If they're different by one, we have not processed the saved
02315       update yet. Do so, then continue with this request.
02316 
02317       - If they're different by more than one, we missed at least one
02318       update. Flush everything, then continue with this request.
02319       ***/
02320 
02321       HandlePendingUpdates(Cache);
02322 
02323       /* Save this update request for other processes */
02324       Cache->PBlock = *PBlock;
02325       Cache->ACEE = *Acee;
02326       Cache->PBlock.REQUESTS.UPDATE.safpb_update_ACEE_ptr = &Cache->ACEE;
02327       if (Update->safpb_update_ENTITY_len > SafCACHE_MAX_ENTITY_LEN)
02328          Len = SafCACHE_MAX_ENTITY_LEN;
02329       else
02330          Len = Update->safpb_update_ENTITY_len;
02331       memcpy(Cache->Entity, Update->safpb_update_ENTITY_ptr, Len);
02332       Cache->PBlock.REQUESTS.UPDATE.safpb_update_ENTITY_len = Len;
02333 
02334       /* Update the global update-history sequence number */
02335       Cache->Sequence++;
02336    }
02337 
02338 
02339    /* TODO: Once caching is implemented, clear relevant cached data */
02340 
02341    /* Tell ESM module(s) to clear cached data */
02342 
02343    /* Was a specific module requested? */
02344    if (PBlock->safpb_safesm_index)
02345    {
02346       /***
02347       Set CurrEsm for error-reporting purposes.  Note that it's set to
02348       the ESM's index plus one (ie the value of safpb_safesm_index), to
02349       simulate what would happen if we exited the for-loop below with an
02350       error.
02351       ***/
02352 
02353       CurrEsm = PBlock->safpb_safesm_index;
02354 
02355       /* Call ESM Module */
02356       EsmRet = SafEsmCUpdate
02357       (
02358          SafESM_UPDATE
02359        , PBlock->safpb_safesm_index - 1
02360        , PBlock
02361       );
02362 
02363       if (! EsmRet) Ret = PBlock->RETCODES.DISCRETE.safpb_api_rc;
02364    }
02365    else
02366    {
02367       /* Call all enabled ESM Modules */
02368       PBlock->RETCODES.DISCRETE.safpb_api_rc     = saf78_SAF_RC_NOT_COMPLETE;
02369       PBlock->RETCODES.DISCRETE.safpb_mgr_return = 0;
02370       PBlock->RETCODES.DISCRETE.safpb_mgr_reason = 0;
02371 
02372       Ret = 0;
02373 
02374       for (CurrEsm=0, EsmRet = 0;
02375            CurrEsm < NumESMMods && Ret <= saf78_SAF_RC_NOT_COMPLETE && !EsmRet;
02376            CurrEsm++)
02377       {
02378          /* Set ESM index in parameter block */
02379          PBlock->safpb_safesm_index = (unsigned char) CurrEsm + 1;
02380 
02381          /* Call ESM Module */
02382          EsmRet = SafEsmCUpdate(SafESM_UPDATE, CurrEsm, PBlock);
02383 
02384          /* Handle non-zero return codes */
02385          switch (EsmRet)
02386          {
02387             case SafESMRC_OK:
02388                /* Check for failure response */
02389                Ret = PBlock->RETCODES.DISCRETE.safpb_api_rc;
02390                break;
02391             case SafESMRC_NOTIMPL:
02392                /* Allowed */
02393                EsmRet = 0;
02394                break;
02395             /* All other cases represent an ESM Module failure */
02396             default:
02397                break;
02398          }
02399       }
02400    }
02401 
02402    /* A "not-complete" return code is not an error here */
02403    if (Ret == saf78_SAF_RC_NOT_COMPLETE) Ret = 0;
02404 
02405    /* If successful, update private history sequence number */
02406    if (! Ret && Cache) UpdateSequenceNumber = Cache->Sequence;
02407 
02408 
02409    /* Clean up and return */
02410 done:
02411 
02412    /* Check for ESM Module failure */
02413    if (EsmRet > SafESMRC_NOTIMPL) ErrType = EsmrcToString(EsmRet);
02414    if (ErrType)
02415    {
02416       /* Log this */
02417       SafLog
02418       (
02419          114
02420        , SafMsgERR
02421        , "ESM Module %d (%s) returned error code %d (%s) from Update"
02422        , CurrEsm
02423        , SafEsmName(CurrEsm-1)
02424        , (int)EsmRet
02425        , ErrType
02426       );
02427 
02428       /* Convert to failure result */
02429       Ret = saf78_SAF_RC_FAILURE;
02430       PBlock->RETCODES.DISCRETE.safpb_mgr_return = saf78_RC_DATABASE_ERROR;
02431    }
02432 
02433    /* Unlock if necessary */
02434    if (Locked) UnlockUpdateArea();
02435 
02436    /* Logging and auditing */
02437    if (PBlock)
02438    {
02439       char UserBuf[9], ResourceBuf[40];
02440       size_t Len;
02441       int Category, Event;
02442 
02443       /* Set return code in parameter block */
02444       PBlock->RETCODES.DISCRETE.safpb_api_rc = Ret;
02445 
02446       /* Audit */
02447       memcpy(UserBuf, Acee->User, 8);
02448       UserBuf[Acee->UserLen] = '\0';
02449 
02450       Len = PBlock->REQUESTS.UPDATE.safpb_update_ENTITY_len;
02451       if (Len > sizeof ResourceBuf - 1) Len = sizeof ResourceBuf - 1;
02452       memcpy(ResourceBuf, PBlock->REQUESTS.UPDATE.safpb_update_ENTITY_ptr, Len);
02453       ResourceBuf[Len] = '\0';
02454 
02455       if (Ret)
02456       {
02457          Category = AUDIT_EVENT_CATEGORY_SEC_API_RES_ERROR;
02458          Event = AUDIT_EVENT_UPDATE_ESM_ERROR;
02459 
02460          /* Log the failure */
02461          SafLog
02462          (
02463             104
02464           , SafMsgWARN
02465           , "Update (%s) request failed: %d"
02466           , UpdateTypeToString(PBlock->safpb_type)
02467           , (int) Ret
02468          );
02469       }
02470       else
02471       {
02472          Category = AUDIT_EVENT_CATEGORY_SEC_API_RES_SUCCESS;
02473          Event = AUDIT_EVENT_UPDATE_SUCCESS;
02474       }
02475 
02476       SafRaiseAuditEvent
02477       (
02478           Event
02479         , Category
02480         , 4
02481         , SafEventData
02482           (
02483              AUDIT_RECORD_DATA_TYPE_STRING
02484            , UserBuf
02485            , (int)strlen(UserBuf)
02486           )
02487         , SafEventData
02488           (
02489              AUDIT_RECORD_DATA_TYPE_COMP5
02490            , &PBlock->safpb_safesm_index
02491            , (int)sizeof PBlock->safpb_safesm_index
02492           )
02493         , SafEventData
02494           (
02495              AUDIT_RECORD_DATA_TYPE_COMP5
02496            , &PBlock->REQUESTS.UPDATE.safpb_update_ACTION
02497            , (int)sizeof PBlock->REQUESTS.UPDATE.safpb_update_ACTION
02498           )
02499         , SafEventData
02500           (
02501              AUDIT_RECORD_DATA_TYPE_STRING
02502            , ResourceBuf
02503            , (int)strlen(ResourceBuf)
02504           )
02505       );
02506    }
02507 
02508    #if _DEBUG && SafLOG_ALL
02509       /* Log result */
02510       if (Ret) SafLog(2005, SafMsgINFO, "Update failed");
02511    #endif
02512 
02513    return Ret;
02514 }
02515 
02516 
02517 
02518 /***
02519 Handle pending updates in a shared-memory environment.
02520 In non-shared-memory environments, this function is a no-op.
02521 
02522 Check for pending requests by comparing our last-update-processed
02523 sequence number with the sequence number of the current saved update:
02524 
02525    - If they're the same, we already processed the saved update.
02526 
02527    - If they're different by one, we have not processed the saved
02528    update yet. Do so.
02529 
02530    - If they're different by more than one, we missed at least one
02531    update. Flush everything.
02532 
02533 The input parameter UpdateCache can be null, for the normal behavior, or
02534 a pointer to the shared update area if the caller has already addressed the
02535 update area. In that case, the function assumes the caller has also already
02536 acquired the global update-area lock.
02537 
02538 Returns a SafRet error code.
02539 ***/
02540 
02541 static SafRet HandlePendingUpdates(struct UpdateCache *Cache)
02542 {
02543    SafRet Ret = SafR_OK;
02544    mf_uns32 PendingUpdates;
02545    int CallerLocked = (Cache != NULL);
02546    mf_uns32 CurrEsm, EsmRet = 0, MaxEsmRet = 0;
02547    const char *ErrType = NULL;
02548 
02549    /* We need the cache */
02550    if (! Cache)
02551    {
02552       if (LockUpdateArea()) Cache = GetUpdateCache();
02553       if (! Cache) goto done;
02554    }
02555 
02556    /* See if we have pending updates */
02557    PendingUpdates = CheckForPendingSharedUpdate(Cache);
02558 
02559    if (PendingUpdates == 1)
02560    {
02561       /* TODO: When caching is implemented, need to update local cache */
02562 
02563       /* Notify appropriate ESM Module(s) */
02564       if (Cache->PBlock.safpb_safesm_index)
02565       {
02566          EsmRet = SafEsmCUpdate
02567          (
02568             SafESM_UPDATED
02569           , Cache->PBlock.safpb_safesm_index - 1
02570           , & Cache->PBlock
02571          );
02572          if (! EsmRet) Ret = Cache->PBlock.RETCODES.DISCRETE.safpb_api_rc;
02573       }
02574       else
02575       {
02576          Cache->PBlock.RETCODES.DISCRETE.safpb_api_rc     = 0;
02577 
02578          for (CurrEsm=0, EsmRet = 0; CurrEsm < NumESMMods; CurrEsm++)
02579          {
02580             Cache->PBlock.safpb_safesm_index = (unsigned char) CurrEsm + 1;
02581             EsmRet = SafEsmCUpdate(SafESM_UPDATED, CurrEsm, &Cache->PBlock);
02582             switch (EsmRet)
02583             {
02584                case SafESMRC_OK:
02585                   /* Convert failure response to EsmRet code for logging */
02586                   if (Cache->PBlock.RETCODES.DISCRETE.safpb_api_rc >
02587                       saf78_SAF_RC_NOT_COMPLETE)
02588                      EsmRet = SafESMRC_FAIL;
02589                   break;
02590                case SafESMRC_NOTIMPL:
02591                   /* Allowed */
02592                   EsmRet = 0;
02593                   break;
02594                /* All other cases represent an ESM Module failure */
02595                default:
02596                   break;
02597             }
02598             if (EsmRet > MaxEsmRet) MaxEsmRet = EsmRet;
02599          }
02600 
02601          EsmRet = MaxEsmRet;
02602       }
02603    }
02604 
02605    else if (PendingUpdates > 1)
02606    {
02607       /* TODO: When caching is implemented, need to flush local cache */
02608 
02609       /* Flush all ESMs */
02610       for (CurrEsm=0, EsmRet = 0; CurrEsm < NumESMMods; CurrEsm++)
02611       {
02612          EsmRet = SafEsmCUpdate(SafESM_REFRESH, CurrEsm, NULL);
02613          if (EsmRet == SafESMRC_NOTIMPL) EsmRet = 0;
02614          if (EsmRet > MaxEsmRet) MaxEsmRet = EsmRet;
02615       }
02616 
02617       EsmRet = MaxEsmRet;
02618    }
02619 
02620    /* Log any error */
02621    if (EsmRet > 0)
02622    {
02623       ErrType = EsmrcToString(EsmRet);
02624       SafLog
02625       (
02626          105
02627        , SafMsgWARN
02628        , "ESM Module %d (%s) returned error code %d (%s) from Update"
02629          " (%s)"
02630        , CurrEsm
02631        , SafEsmName(CurrEsm-1)
02632        , (int)EsmRet
02633        , ErrType
02634        , PendingUpdates == 1? "single update" : "refresh all"
02635       );
02636 
02637       /* Set Ret based on EsmRet */
02638       switch (EsmRet)
02639       {
02640          case SafESMRC_PARAM:    Ret = SafR_PARAM;    break;
02641          case SafESMRC_RESOURCE: Ret = SafR_RESOURCE; break;
02642          case SafESMRC_EXTERNAL: Ret = SafR_EXFAIL;   break;
02643          case SafESMRC_MGRFAIL:  Ret = SafR_INTERNAL; break;
02644          case SafESMRC_FAIL:     Ret = SafR_ESM;      break;
02645          default:                Ret = SafR_ESM;      break;
02646       }
02647    }
02648 
02649    /* Update the private update-history sequence number */
02650    UpdateSequenceNumber = Cache->Sequence;
02651 
02652 done:
02653    /* Unlock shared area if the caller didn't do the locking for us */
02654    if (! CallerLocked) UnlockUpdateArea();
02655    return Ret;
02656 }
02657 
02658 
02659 /***
02660 Helper functions to acquire and release the global locks for the shared
02661 update cache area. These are stubs in non-shared-memory environments.
02662 
02663 They return 1 if the action actually took place, 0 if locking is unnecessary.
02664 ***/
02665 
02666 static int LockUpdateArea(void)
02667 {
02668    if (SafIsSharedMemory())
02669    {
02670       SafLockEnq
02671       (
02672          "#ESFMgr"
02673        , "AdminUpd"
02674        , SafESM_LCK_NONE
02675        , 1
02676        , SafESM_LCK_PROC
02677       );
02678       return 1;
02679    }
02680 
02681    return 0;
02682 }
02683 
02684 static int UnlockUpdateArea(void)
02685 {
02686    if (SafIsSharedMemory())
02687    {
02688       SafLockDeq("#ESFMgr", "AdminUpd");
02689       return 1;
02690    }
02691 
02692    return 0;
02693 }
02694 
02695 
02696 /***
02697 Helper to get (or allocate, if this is the first update request) the shared
02698 update cache area.
02699 
02700 We need to allocate an area big enough for PBlock, plus the indirect
02701 separately-allocated data (eg entity name, ACEE), plus the cache header.
02702 The entity name length can vary. We impose a maximum length to avoid
02703 having to reallocate the update cache area; if we get a request that
02704 exceeds that length, we truncate the entity name in the cache. (We could
02705 force other processes to flush all their private cached data in this case
02706 by incrementing the sequence number by two, but frankly I'm not very
02707 worried about this case. If people create unreasonable security data, they
02708 get suboptimal behavior.)
02709 ***/
02710 
02711 static struct UpdateCache *GetUpdateCache(void)
02712 {
02713    struct UpdateCache *Cache = NULL;
02714    SafRet Ret;
02715    size_t CacheSize;
02716 
02717    CacheSize = sizeof *Cache;
02718    Ret = SafShmOpen("#SafCache", &CacheSize, (void **)&Cache);
02719    if (Ret || !Cache || CacheSize != sizeof *Cache)
02720    {
02721       /* TODO: Log this. */
02722       Cache = NULL;
02723    }
02724 
02725    return Cache;
02726 }
02727 
02728 
02729 
02730 /***
02731 Helper function to check to see if there's a pending administrative update
02732 in shared memory. In non-shared-memory environments, this function always
02733 returns false.
02734 
02735 The input parameter UpdateCache can be null, for the normal behavior, or
02736 a pointer to the shared update area if the caller has already addressed the
02737 update area. In that case, the function assumes the caller has also already
02738 acquired the global update-area lock.
02739 
02740 Possible return values are 0 (no shared update pending), 1 (an update is
02741 present and needs to be processed), and >1 (multiple updates were missed,
02742 and all cached data needs to be flushed). If the return code is nonzero,
02743 this function will leave the global update-area lock aquired, and the caller
02744 must at least release that lock.
02745 ***/
02746 
02747 static mf_uns32 CheckForPendingSharedUpdate(struct UpdateCache *Cache)
02748 {
02749    mf_uns32 Result = 0;
02750    int Locked = 0;
02751 
02752    /* If caller didn't get shared area and lock, do that */
02753    if (! Cache)
02754    {
02755       Locked = LockUpdateArea();
02756 
02757       /* Only need to look for shared area if lock succeeded */
02758       if (Locked) Cache = GetUpdateCache();
02759    }
02760 
02761    /* If we have an update cache area, check it */
02762    if (Cache)
02763    {
02764       /* Check the global update sequence number against ours */
02765       Result = Cache->Sequence - UpdateSequenceNumber;
02766 
02767       /* Update our sequence number so we know what we've seen */
02768       UpdateSequenceNumber = Cache->Sequence;
02769    }
02770 
02771    /* If we're up to date, and we locked the area, release the lock */
02772    if (! Result && Locked) UnlockUpdateArea();
02773 
02774    /* Let caller know result */
02775    return Result;
02776 }
02777 
02778 
02779 /***
02780 Translate update types to strings.
02781 ***/
02782 
02783 static const char *UpdateTypeToString(unsigned char Type)
02784 {
02785    static const char *Types[] =
02786    {
02787       "all"
02788     , "user"
02789     , "group"
02790     , "resource"
02791     , "users"
02792     , "groups"
02793     , "resources"
02794    };
02795 
02796    if (Type < sizeof Types / sizeof *Types)
02797       return Types[Type];
02798    else
02799       return "unknown";
02800 }
02801 
02802 
02803 
02804 /* end of source module saf-process.c */
02805