safmgr.c

Go to the documentation of this file.
00001 /****************************************************************************
00002  *
00003  *      Copyright (C) 2006-2007 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  *      Manager Startup and Control
00016  *
00017  *      @(#)safmgr.c   $Revision: 1.2 $     
00018  *
00019  *      $Date: 2008/07/01 08:32:52 $
00020  *
00021  ****************************************************************************/
00022 
00023 /* Copyright */
00024 static const char *copyright =
00025    "Copyright (C) 2006-2007 Micro Focus (IP) Limited";
00026 static const char *sccsid =
00027    "@(#)safmgr.c  $Revision: 1.2 $ built " __DATE__ " " __TIME__;
00028 
00029 /* Start of source module safmgr.c */
00030 
00031 
00048 /* System Headers */
00049 
00050 /* ANSI/ISO standard headers */
00051 #include <stddef.h>
00052 #include <stdlib.h>
00053 #include <stdio.h>
00054 #include <stdarg.h>
00055 #include <string.h>
00056 #include <time.h>
00057 #include <errno.h>
00058 #include <ctype.h>
00059 
00060 /* UNIX headers */
00061 #if defined(UNIX)
00062 #   include <unistd.h>
00063 #   include <sys/time.h>
00064 #endif
00065 
00066 /* Win32 headers */
00067 #if defined(WIN32)
00068 #   include <windows.h>
00069 #   include <sys/types.h>
00070 #   include <sys/stat.h>
00071 #endif
00072 
00073 
00074 /* External Headers */
00075 #if defined(UNIX)
00076 #  include "gptypes.h"          /* RTS types, req. by CCI */
00077 #elif defined(WIN32)
00078 #  include "pc_rts.h"           /* ditto for Win32 */
00079 #endif
00080 #include "cci.h"                /* CCI API and types */
00081                                 /* (required for mf_os_size typedef) */
00082 #include "mdsa.h"               /* MDSA SAF and ESM configuration */
00083 
00084 
00085 /* SAF Headers */
00086 #include "safmgr.h"
00087 #include "saf-env.h"
00088 #include "saf-cache.h"
00089 #include "saf-esm.h"
00090 #include "saf-process.h"
00091 #include "saf-audit.h"
00092 #include "mfaudit.h"
00093 
00094 #if defined(WIN32)
00095    /* Stub DLL initialization entry point for C RTS */
00096    BOOL APIENTRY DllMain(HANDLE Inst, DWORD Reason, LPVOID Reserved)
00097    {
00098       switch (Reason)
00099       {
00100          case DLL_PROCESS_ATTACH:
00101          case DLL_THREAD_ATTACH:
00102          case DLL_PROCESS_DETACH:
00103          case DLL_THREAD_DETACH:
00104             break;
00105       }
00106       return TRUE;
00107    }
00108 #endif
00109 
00110 
00111 static int EsmCmp(const void *EPtr1, const void *EPtr2);
00112 
00113 /* SAF Manager state */
00114 static enum
00115 {
00116    SafUNINITIALIZED = 0
00117  , SafRUNNING       = 1
00118  , SafTERMINATED    = 2
00119 } ManagerState = SafUNINITIALIZED;
00120 
00121 /* SAF Manager Custom Configuration associative store */
00122 static struct SafStore *CustCfg = NULL;
00123 
00124 
00125 
00163 mf_uns32 safmgr(struct SafInit *Init)
00164 {
00165    unsigned Esm;
00166    mf_uns32 Ret = SafINIT_OK;
00167    struct SafInit *NewSafInit = NULL, *CallerInit = NULL;
00168    struct cas_saf_config_internal *NewSafCfg;
00169    struct cas_esm_config_internal *NewEsmCfg;
00170    char *CfgVal = NULL;
00171    SafRet SRet;
00172 
00173 
00174    #if defined WIN32 && defined _DEBUG
00175       /***
00176       Auto-debug support: create a file named c:/tmp/debug-safmgr.  The
00177       first process to open this file in exclusive mode will call DebugBreak().
00178       ***/
00179 
00180       if
00181       (
00182          CreateFile
00183          (
00184             "c:/tmp/debug-safmgr"
00185           , FILE_READ_DATA
00186           , 0                         /* unsharable */
00187           , NULL
00188           , OPEN_EXISTING
00189           , 0
00190           , NULL
00191          ) != INVALID_HANDLE_VALUE
00192       )
00193       {
00194          #if 0
00195             DebugBreak();
00196          #elif 0
00197             extern void CBL_DEBUGBREAK(void);
00198             CBL_DEBUGBREAK();
00199          #else
00200             char DbgBuf[80];
00201             DWORD Pid = GetCurrentProcessId();
00202             sprintf(DbgBuf, "cmd /c \"start windbg -p %lu\"", Pid);
00203             system(DbgBuf);
00204             Sleep(15000);
00205             DebugBreak();
00206          #endif
00207       }
00208    #endif
00209 
00210    if (! Init)
00211    {
00212       Ret = SafINIT_NULL;
00213       goto done;
00214    }
00215 
00216    /***
00217    Try to heuristically distinguish between version skew and invalid
00218    input: assume that Version should be an integer in the range [0,10]
00219    for the foreseeable future.  Similarly, assume that we have garbage
00220    if ESMCnt is more than 10 times the current maximum.
00221    ***/
00222 
00223    if (Init->Version > 10 ||
00224        Init->ESMCnt > 10*SafESM_MAX)
00225    {
00226       Ret = SafINIT_BAD_CB;
00227       goto done;
00228    }
00229 
00230    /* Now check for "sensible" errors */
00231    if (Init->Version != SafMGR_API_VER)
00232    {
00233       Ret = SafINIT_VER;
00234       goto done;
00235    }
00236    if (! Init->Config)
00237    {
00238       Ret = SafINIT_CFG;
00239       goto done;
00240    }
00241    if (Init->ESMCnt > SafESM_MAX)
00242    {
00243       Ret = SafINIT_CNT;
00244       goto done;
00245    }
00246 
00247    /* Make sure all the ESMs have configuration blocks */
00248    for (Esm = 0; Esm < Init->ESMCnt; Esm++)
00249       if (! Init->ESMCfg[Esm])
00250       {
00251          Ret = SafINIT_ESMCFG;
00252          goto done;
00253       }
00254 
00255 
00256    /* Structure looks OK; reset error indicators */
00257    Init->Reason = Init->Detail = 0;
00258    
00259    /* Return now if we're already initialized */
00260    /* TODO: Handle reconfigure here */
00261    if (ManagerState == SafRUNNING)
00262    {
00263       Ret = SafINIT_OK;
00264       goto done;
00265    }
00266 
00267    /***
00268    Copy the configuration areas, convert integer values to native
00269    ordering, and change the init structure to point to the copies.  This
00270    is necessary because the structures are shared, and CAS expects the
00271    values to remain unchanged; and because we have no guarantee that
00272    callers won't discard the init structure.  (CAS doesn't, currently,
00273    but MFDS might, and it'd be a very dodgy thing to rely on.)
00274    ***/
00275 
00276    /* Copy SAF Init structure */
00277    NewSafInit = malloc(sizeof *NewSafInit);
00278    if (! NewSafInit)
00279    {
00280       Ret = SafINIT_RESRCE;
00281       goto done;
00282    }
00283    *NewSafInit = *Init;
00284 
00285    /* Replace Init with copy */
00286    CallerInit = Init;
00287    Init = NewSafInit;
00288 
00289    /* Copy SAF Manager config */
00290    NewSafCfg = malloc(sizeof *NewSafCfg);
00291    if (! NewSafCfg)
00292    {
00293       Ret = SafINIT_RESRCE;
00294       goto done;
00295    }
00296 
00297    NewSafCfg->version = SafNative32u(Init->Config->version);
00298    NewSafCfg->cache_TTL = SafNative32u(Init->Config->cache_TTL);
00299    NewSafCfg->cache_limit = SafNative32u(Init->Config->cache_limit);
00300    NewSafCfg->option_flags = SafNative32u(Init->Config->option_flags);
00301 
00302    /* TODO: Parse config so we don't have to save it */
00303    NewSafCfg->config = Init->Config->config;
00304    NewSafCfg->reserved = Init->Config->reserved;
00305 
00306    /* Replace SAF config with copy */
00307    Init->Config = NewSafCfg;
00308 
00309    /* Copy ESM configs */
00310    for (Esm = 0; Esm < Init->ESMCnt; Esm++)
00311    {
00312       NewEsmCfg = malloc(sizeof *NewEsmCfg);
00313       if (! NewEsmCfg)
00314       {
00315          Ret = SafINIT_RESRCE;
00316          goto done;
00317       }
00318       
00319       NewEsmCfg->version = SafNative32u(Init->ESMCfg[Esm]->version);
00320       NewEsmCfg->state = SafNative32u(Init->ESMCfg[Esm]->state);
00321       NewEsmCfg->priority = SafNative32u(Init->ESMCfg[Esm]->priority);
00322       NewEsmCfg->cache_TTL = SafNative32u(Init->ESMCfg[Esm]->cache_TTL);
00323       NewEsmCfg->cache_limit = SafNative32u(Init->ESMCfg[Esm]->cache_limit);
00324 
00325       strcpy(NewEsmCfg->name, Init->ESMCfg[Esm]->name);
00326       strcpy(NewEsmCfg->module, Init->ESMCfg[Esm]->module);
00327       strcpy(NewEsmCfg->psz_id, Init->ESMCfg[Esm]->psz_id);
00328       strcpy(NewEsmCfg->psz_pwd, Init->ESMCfg[Esm]->psz_pwd);
00329       strcpy(NewEsmCfg->psz_connection_path,
00330              Init->ESMCfg[Esm]->psz_connection_path);
00331 
00332       /* TODO: Save copy of config? (Not nec for CAS) */
00333       NewEsmCfg->config = Init->ESMCfg[Esm]->config;
00334       NewEsmCfg->reserved = Init->ESMCfg[Esm]->reserved;
00335 
00336       /* Replace ESM config with copy */
00337       Init->ESMCfg[Esm] = NewEsmCfg;
00338    }
00339 
00340    /* Sort the ESMs by priority */
00341    qsort(Init->ESMCfg, Init->ESMCnt, sizeof *Init->ESMCfg, EsmCmp);
00342 
00343 
00344    /* Initialize the environment */
00345    Ret = SafEnvInit(Init);
00346 
00347    /* Don't return an internal code */
00348    if (Ret >= SafINIT_BADENV || (Ret == SafINIT_FAIL && ! Init->Reason))
00349    {
00350       /***
00351       We can't log this - the environment module is required for logging,
00352       and it didn't initialize successfully.
00353       ***/
00354 
00355       Init->Reason = SafMGR_FAIL_ENV;
00356       Init->Detail = Ret;
00357       Ret = SafINIT_FAIL;
00358    }
00359    if (Ret) goto done;
00360 
00361 
00362    /***
00363    Load the manager's custom configuration information into an associative
00364    store for later querying.  We have to do this after environment
00365    initialization, because the Store functions use some environment
00366    functionality (eg serialization).
00367    ***/
00368 
00369    SRet = SafAllocStore(&CustCfg);
00370    if (SRet)
00371    {
00372       Init->Reason = SafMGR_FAIL_RESOURCE;
00373       Ret = SafINIT_FAIL;
00374       goto done;
00375    }
00376 
00377    if (Init->Config->config) SafStoreLoad(CustCfg, Init->Config->config);
00378 
00379    /***
00380    548616: Allow "ES_ESF_ALLOW_LIST" to set [Admin]/allow-list if the
00381    latter isn't set in the configuration. Undocumented; used only by
00382    Testing.
00383    ***/
00384 
00385    SRet = SafQueryCfg("Admin", "allow-list", &CfgVal);
00386    if (SRet || !CfgVal || !*CfgVal)
00387    {
00388       char *EnvVal = getenv("ES_ESF_ALLOW_LIST");
00389       if (EnvVal) SafStoreAdd(CustCfg, "Admin", "allow-list", EnvVal);
00390    }
00391 
00392 
00393    /* Initialize auditing */
00394    Ret = SafInitAuditing(Init);
00395 
00396    /* Don't return an internal code */
00397    if (Ret >= SafINIT_BADENV || (Ret == SafINIT_FAIL && ! Init->Reason))
00398    {
00399       Init->Reason = SafMGR_FAIL_ENV;
00400       Init->Detail = Ret;
00401       Ret = SafINIT_FAIL;
00402    }
00403    if (Ret)
00404    {
00405       /* TODO: Refactor this code for explaining return codes */
00406       const char *Reason = "unrecognized failure code";
00407 
00408       switch (Ret)
00409       {
00410          case SafINIT_EXTERNAL:
00411             Reason = "Could not connect to audit manager";
00412             break;
00413          case SafINIT_ENVFUNC:
00414             Reason = "Could not resolve audit functions";
00415             break;
00416       }
00417 
00418       SafLog
00419       (
00420          601
00421        , SafMsgCRIT
00422        , "Auditing subsystem startup failed: (%d) %s"
00423        , Ret
00424        , Reason
00425       );
00426 
00427       goto done;
00428    }
00429    
00430    /* AUDITEVENTCALL Subsystem Event: Initialization */
00431    Ret = SafRaiseAuditEvent
00432    (
00433       AUDIT_EVENT_SAFMGR_INITIALIZING
00434     , AUDIT_EVENT_CATEGORY_SYSTEM
00435     , 0
00436    );
00437 
00438    /* Don't return an internal code */
00439    if (Ret >= SafINIT_BADENV || (Ret == SafINIT_FAIL && ! Init->Reason))
00440    {
00441       /* TODO: Log this */
00442       Init->Reason = SafMGR_FAIL_ENV;
00443       Init->Detail = Ret;
00444       Ret = SafINIT_FAIL;
00445    }
00446    if (Ret) goto done;
00447 
00448 
00449    /* TODO: Initialize the cache */
00450 
00451 
00452    /* Initialize the ESM Modules */
00453    Ret = SafEsmInit(Init);
00454    if (Ret >= SafINIT_BADENV || (Ret == SafINIT_FAIL && ! Init->Reason))
00455    {
00456       if (! Init->Reason)
00457          Ret = SafINIT_OTHER;
00458       else
00459          Ret = SafINIT_FAIL;
00460    }
00461 
00462    if (Ret)
00463    {
00464       /* TODO: Shut down any ESMs that did start (note that Init->ESMCnt
00465          will have been updated) */
00466       goto done;
00467    }
00468 
00469 
00470    /* Initialize the request processor */
00471    Ret = SafProcInit(Init);
00472    if (Ret) goto done;
00473 
00474 
00475    /* Initialization succeeded */
00476    SafThrLock("manager-state", 1);
00477    ManagerState = SafRUNNING;
00478    SafThrUnlock("manager-state");
00479 
00480 done:
00481 
00482    if (CallerInit)
00483    {
00484       /* Copy back return fields */
00485       CallerInit->Reason = Init->Reason;
00486       CallerInit->Detail = Init->Detail;
00487       CallerInit->ESMCnt = Init->ESMCnt;
00488    }
00489 
00490    switch (Ret)
00491    {
00492       case SafINIT_OK:
00493          /* AUDITEVENTCALL Subsystem Event: Initialized */
00494          SafRaiseAuditEvent
00495          (
00496             AUDIT_EVENT_SAFMGR_STARTED
00497           , AUDIT_EVENT_CATEGORY_SYSTEM
00498           , 0
00499          );
00500          break;
00501 
00502       case SafR_PARAM:
00503       case SafR_RESOURCE:
00504       case SafR_EXFAIL:
00505       case SafR_STATE:
00506       case SafR_INTERNAL:
00507       case SafR_NOTFOUND:
00508       case SafR_TRUNCATED:
00509       default:
00510          /* AUDITEVENTCALL Subsystem Event: Initialization Failure */
00511          /* RaiseAuditEvent(); */
00512          break;
00513    }
00514 
00515    return Ret;
00516 }
00517 
00518 
00534 mf_uns32 safterm(mf_uns32 What, void *Reserved)
00535 {
00536    /***
00537    TODO: Call cache manager, call environment; in environment, if MFDS,
00538    should call cobtidy / cobthreadtidy (probably - check with Henry).
00539    In MFDS, need to end UOW/task or process locks, for thread or process
00540    exit respectively.  (In MFDS, we don't distinguish between UOWs and
00541    tasks.)
00542    ***/
00543 
00544    if (What == SafTERM_PROCESS)
00545    {
00546       /* Serialize */
00547       SafThrLock("manager-state", 1);
00548 
00549       if (ManagerState == SafRUNNING) 
00550       {
00551          /* Audit */
00552          SafRaiseAuditEvent
00553          (
00554             AUDIT_EVENT_SAFMGR_TERMINATING
00555           , AUDIT_EVENT_CATEGORY_SYSTEM
00556           , 0
00557          );
00558 
00559          /* Notify ESMs */
00560          SafEsmExit();
00561 
00562          /* Update manager state */
00563          ManagerState = SafTERMINATED;
00564       }
00565 
00566       SafThrUnlock("manager-state");
00567    }
00568 
00569    return 0;
00570 }
00571 
00572 
00586 int SafState(void)
00587 {
00588    return (int)ManagerState;
00589 }
00590 
00591 
00610 SafRet SafQueryCfg(const char *Class, const char *Name, char **ValueP)
00611 {
00612    return SafStoreFind(CustCfg, Class, Name, (void**)ValueP);
00613 }
00614 
00615 
00616 
00617 /* Helper function to convert network-order mf_uns32 values to native */
00618 mf_uns32 SafNative32u(mf_uns32 NetValue)
00619 {
00620    unsigned char *Bytes = (unsigned char *)&NetValue;
00621    return (Bytes[0] << 24) |
00622           (Bytes[1] << 16) |
00623           (Bytes[2] <<  8) |
00624           (Bytes[3] <<  0);
00625 }
00626 
00627 
00628 /* Helper function to compare two ESM configs by priority value */
00629 static int EsmCmp(const void *EPtr1, const void *EPtr2)
00630 {
00631    /***
00632    The following shouldn't require a cast, as far as I can tell.  void* is
00633    convertible into any object pointer type, and qualified-void* should be
00634    convertible into any object pointer type that's similarly qualified.
00635    But IBM's VAC++ (in C mode) complains.
00636    ***/
00637 
00638    const struct cas_esm_config_internal
00639       **EsmPtr1 = (const struct cas_esm_config_internal **)EPtr1,
00640       **EsmPtr2 = (const struct cas_esm_config_internal **)EPtr2;
00641 
00642    /***
00643    We want to sort by lowest-priority-first, so return a negative number
00644    if the first ESM has a lower priority than the second, and so on.
00645    Note we've already ensured there are no null pointers in array.
00646    ***/
00647 
00648    return (*EsmPtr1)->priority - (*EsmPtr2)->priority;
00649 }
00650 
00651 
00652 /* end of source module safmgr.c */
00653