diff --git a/src/as/Makefile.Vx b/src/as/Makefile.Vx index c57453975..3f924aac1 100644 --- a/src/as/Makefile.Vx +++ b/src/as/Makefile.Vx @@ -3,8 +3,8 @@ include $(TOP)/config/CONFIG_BASE USR_CFLAGS = -DACCESS_SECURITY -D_NO_PROTO -SRCS.c = ../asDbLib.c ../asCa.c asLib.c -LIBOBJS = asDbLib.o asCa.o asLib.o +SRCS.c = ../asDbLib.c ../asCa.c ../asTrapWrite.c asLib.c +LIBOBJS = asDbLib.o asCa.o asTrapWrite.o asLib.o LIBNAME = asLibrary include $(TOP)/config/RULES.Vx diff --git a/src/as/asLib.y b/src/as/asLib.y index ac12a32ca..a61180a69 100644 --- a/src/as/asLib.y +++ b/src/as/asLib.y @@ -132,7 +132,9 @@ inp_body: tokenNAME rule_config: tokenRULE rule_head rule_body | tokenRULE rule_head -rule_head: '(' tokenINTEGER ',' tokenNAME ')' +rule_head: rule_head_manditory rule_head_options + +rule_head_manditory: '(' tokenINTEGER ',' tokenNAME { asAccessRights rights; @@ -151,6 +153,21 @@ rule_head: '(' tokenINTEGER ',' tokenNAME ')' } ; +rule_head_options: ')' + | rule_log_options + +rule_log_options: ',' tokenNAME ')' + { + if((strcmp($2,"TRAPWRITE")==0)) { + long status; + status = asAsgAddRuleOptions(yyAsgRule,AS_TRAP_WRITE); + if(status) yyerror(""); + } else if((strcmp($2,"NOTRAPWRITE")!=0)) { + yyerror("Illegal access type"); + } + free((void *)$2); + } + ; rule_body: '{' rule_list '}' ; @@ -225,7 +242,7 @@ static int myParse(ASINPUTFUNCPTR inputfunction) if (!FirstFlag) { line_num=1; yyFailed = FALSE; - yyreset(NULL); + yyreset(); yyrestart(NULL); } FirstFlag = 0; diff --git a/src/as/asLibRoutines.c b/src/as/asLibRoutines.c index 24bb56ca9..ea430415c 100644 --- a/src/as/asLibRoutines.c +++ b/src/as/asLibRoutines.c @@ -77,6 +77,7 @@ static long asHagAddHost(HAG *phag,char *host); static ASG *asAsgAdd(char *asgName); static long asAsgAddInp(ASG *pasg,char *inp,int inpIndex); static ASGRULE *asAsgAddRule(ASG *pasg,asAccessRights access,int level); +static long asAsgAddRuleOptions(ASGRULE *pasgrule,int trapMask); static long asAsgRuleUagAdd(ASGRULE *pasgrule,char *name); static long asAsgRuleHagAdd(ASGRULE *pasgrule,char *name); static long asAsgRuleCalc(ASGRULE *pasgrule,char *calc); @@ -477,6 +478,7 @@ long epicsShareAPI asCompute(ASCLIENTPVT asClientPvt) /*The dump routines do not lock. Thus they may get inconsistant data.*/ /*HOWEVER if they did lock and a user interrupts one of then then BAD BAD*/ static char *asAccessName[] = {"NONE","READ","WRITE"}; +static char *asTrapOption[] = {"NOTRAPWRITE","TRAPWRITE"}; static char *asLevelName[] = {"ASL0","ASL1"}; int epicsShareAPI asDump( void (*memcallback)(struct asgMember *), @@ -553,8 +555,9 @@ int epicsShareAPI asDump( while(pasgrule) { int print_end_brace; - printf("\tRULE(%d,%s)", - pasgrule->level,asAccessName[pasgrule->access]); + printf("\tRULE(%d,%s,%s)", + pasgrule->level,asAccessName[pasgrule->access], + asTrapOption[pasgrule->trapMask]); pasguag = (ASGUAG *)ellFirst(&pasgrule->uagList); pasghag = (ASGHAG *)ellFirst(&pasgrule->hagList); if(pasguag || pasghag || pasgrule->calc) { @@ -604,7 +607,9 @@ int epicsShareAPI asDump( else printf(" Illegal Level %d",pasgclient->level); if(pasgclient->access>=0 && pasgclient->access<=2) - printf(" %s",asAccessName[pasgclient->access]); + printf(" %s %s", + asAccessName[pasgclient->access], + asTrapOption[pasgclient->trapMask]); else printf(" Illegal Access %d",pasgclient->access); if(clientcallback) clientcallback(pasgclient); @@ -710,8 +715,9 @@ int epicsShareAPI asDumpRules(char *asgname) while(pasgrule) { int print_end_brace; - printf("\tRULE(%d,%s)", - pasgrule->level,asAccessName[pasgrule->access]); + printf("\tRULE(%d,%s,%s)", + pasgrule->level,asAccessName[pasgrule->access], + asTrapOption[pasgrule->trapMask]); pasguag = (ASGUAG *)ellFirst(&pasgrule->uagList); pasghag = (ASGHAG *)ellFirst(&pasgrule->hagList); if(pasguag || pasghag || pasgrule->calc) { @@ -783,7 +789,9 @@ int epicsShareAPI asDumpMem(char *asgname,void (*memcallback)(ASMEMBERPVT),int c else printf(" Illegal Level %d",pasgclient->level); if(pasgclient->access>=0 && pasgclient->access<=2) - printf(" %s",asAccessName[pasgclient->access]); + printf(" %s %s", + asAccessName[pasgclient->access], + asTrapOption[pasgclient->trapMask]); else printf(" Illegal Access %d",pasgclient->access); printf("\n"); @@ -909,6 +917,7 @@ static long asComputeAsgPvt(ASG *pasg) static long asComputePvt(ASCLIENTPVT asClientPvt) { asAccessRights access=asNOACCESS; + int trapMask=0; ASGCLIENT *pasgclient = asClientPvt; ASGMEMBER *pasgMember; ASG *pasg; @@ -961,12 +970,15 @@ check_hag: } check_calc: if(!pasgrule->calc - || (!(pasg->inpBad & pasgrule->inpUsed) && (pasgrule->result==1))) + || (!(pasg->inpBad & pasgrule->inpUsed) && (pasgrule->result==1))) { access = pasgrule->access; + trapMask = pasgrule->trapMask; + } next_rule: pasgrule = (ASGRULE *)ellNext((ELLNODE *)pasgrule); } pasgclient->access = access; + pasgclient->trapMask = trapMask; if(pasgclient->pcallback && oldaccess!=access) { (*pasgclient->pcallback)(pasgclient,asClientCOAR); } @@ -1205,6 +1217,7 @@ static ASGRULE *asAsgAddRule(ASG *pasg,asAccessRights access,int level) if(!pasg) return(0); pasgrule = asCalloc(1,sizeof(ASGRULE)); pasgrule->access = access; + pasgrule->trapMask = 0; pasgrule->level = level; ellInit(&pasgrule->uagList); ellInit(&pasgrule->hagList); @@ -1212,6 +1225,16 @@ static ASGRULE *asAsgAddRule(ASG *pasg,asAccessRights access,int level) return(pasgrule); } +static long asAsgAddRuleOptions(ASGRULE *pasgrule,int trapMask) +{ + if(!pasgrule) { + errMessage(S_asLib_badConfig," Access Security internal failure"); + return(0); + } + pasgrule->trapMask = trapMask; + return(0); +} + static long asAsgRuleUagAdd(ASGRULE *pasgrule,char *name) { ASGUAG *pasguag; diff --git a/src/as/asTrapWrite.c b/src/as/asTrapWrite.c new file mode 100644 index 000000000..39367906c --- /dev/null +++ b/src/as/asTrapWrite.c @@ -0,0 +1,166 @@ +/*asTrapWrite.c */ +/* Author: Marty Kraimer Date: 07NOV2000 */ +/***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +**********************************************************************/ + +/* Matthias Clausen and Vladis Korobov at DESY + * implemented the first logging of Channel Access Puts + * This implementation uses many ideas from their implementation +*/ + +#include +#include +#include +#include + +#include "callback.h" +#include "freeList.h" +#include "asLib.h" +#include "asTrapWrite.h" +#include "semLib.h" +#include "ellLib.h" + +typedef struct listenerPvt { + ELLNODE node; + struct listener *plistener; + void *userPvt; +}listenerPvt; + +typedef struct listener{ + ELLNODE node; + asTrapWriteListener func; +}listener; + +typedef struct writeMessage { + ELLNODE node; + asTrapWriteMessage message; + ELLLIST listenerPvtList; +}writeMessage; + + +typedef struct asTrapWritePvt +{ + ELLLIST listenerList; + ELLLIST writeMessageList; + void *freeListWriteMessage; + void *freeListListenerPvt; + SEM_ID lock; +}asTrapWritePvt; + +static asTrapWritePvt *pasTrapWritePvt = 0; + +static void asTrapWriteInit(void) +{ + pasTrapWritePvt = calloc(1,sizeof(asTrapWritePvt)); + ellInit(&pasTrapWritePvt->listenerList); + ellInit(&pasTrapWritePvt->writeMessageList); + freeListInitPvt( + &pasTrapWritePvt->freeListWriteMessage,sizeof(writeMessage),20); + freeListInitPvt( + &pasTrapWritePvt->freeListListenerPvt,sizeof(listenerPvt),20); + pasTrapWritePvt->lock = semMCreate( + SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY); +} + +asTrapWriteId epicsShareAPI asTrapWriteRegisterListener( + asTrapWriteListener func) +{ + listener *plistener; + if(pasTrapWritePvt==0) asTrapWriteInit(); + plistener = calloc(1,sizeof(listener)); + plistener->func = func; + semTake(pasTrapWritePvt->lock,WAIT_FOREVER); + ellAdd(&pasTrapWritePvt->listenerList,&plistener->node); + semGive(pasTrapWritePvt->lock); + return((asTrapWriteId)plistener); +} + +void epicsShareAPI asTrapWriteUnregisterListener(asTrapWriteId id) +{ + listener *plistener = (listener *)id; + writeMessage *pwriteMessage; + + if(pasTrapWritePvt==0) return; + semTake(pasTrapWritePvt->lock,WAIT_FOREVER); + pwriteMessage = (writeMessage *)ellFirst(&pasTrapWritePvt->writeMessageList); + while(pwriteMessage) { + listenerPvt *plistenerPvt + = (listenerPvt *)ellFirst(&pwriteMessage->listenerPvtList); + while(plistenerPvt) { + listenerPvt *pnext + = (listenerPvt *)ellNext(&plistenerPvt->node); + if(plistenerPvt->plistener == plistener) { + ellDelete(&pwriteMessage->listenerPvtList,&plistenerPvt->node); + freeListFree(pasTrapWritePvt->freeListListenerPvt,(void *)plistenerPvt); + } + plistenerPvt = pnext; + } + pwriteMessage = (writeMessage *)ellNext(&pwriteMessage->node); + } + ellDelete(&pasTrapWritePvt->listenerList,&plistener->node); + free((void *)plistener); + semGive(pasTrapWritePvt->lock); +} + +void * epicsShareAPI asTrapWriteBeforeWrite( + char *userid,char *hostid,void *addr) +{ + writeMessage *pwriteMessage; + listener *plistener; + listenerPvt *plistenerPvt; + + if(pasTrapWritePvt==0) return(0); + if(ellCount(&pasTrapWritePvt->listenerList)<=0) return 0; + pwriteMessage = (writeMessage *)freeListCalloc( + pasTrapWritePvt->freeListWriteMessage); + pwriteMessage->message.userid = userid; + pwriteMessage->message.hostid = hostid; + pwriteMessage->message.serverSpecific = addr; + ellInit(&pwriteMessage->listenerPvtList); + semTake(pasTrapWritePvt->lock,WAIT_FOREVER); + ellAdd(&pasTrapWritePvt->writeMessageList,&pwriteMessage->node); + plistener = (listener *)ellFirst(&pasTrapWritePvt->listenerList); + while(plistener) { + plistenerPvt = (listenerPvt *)freeListCalloc( + pasTrapWritePvt->freeListListenerPvt); + plistenerPvt->plistener = plistener; + pwriteMessage->message.userPvt = 0; + (*plistener->func)(&pwriteMessage->message,0); + plistenerPvt->userPvt = pwriteMessage->message.userPvt; + ellAdd(&pwriteMessage->listenerPvtList,&plistenerPvt->node); + plistener = (listener *)ellNext(&plistener->node); + } + semGive(pasTrapWritePvt->lock); + return((void *)pwriteMessage); +} + +void epicsShareAPI asTrapWriteAfterWrite(void *pvt) +{ + writeMessage *pwriteMessage = (writeMessage *)pvt; + listenerPvt *plistenerPvt; + + if(pwriteMessage==0 || pasTrapWritePvt==0) return; + semTake(pasTrapWritePvt->lock,WAIT_FOREVER); + plistenerPvt = (listenerPvt *)ellFirst(&pwriteMessage->listenerPvtList); + while(plistenerPvt) { + listenerPvt *pnext = (listenerPvt *)ellNext(&plistenerPvt->node); + listener *plistener; + plistener = plistenerPvt->plistener; + pwriteMessage->message.userPvt = plistenerPvt->userPvt; + (*plistener->func)(&pwriteMessage->message,1); + ellDelete(&pwriteMessage->listenerPvtList,&plistenerPvt->node); + freeListFree(pasTrapWritePvt->freeListListenerPvt,(void *)plistenerPvt); + plistenerPvt = pnext; + } + ellDelete(&pasTrapWritePvt->writeMessageList,&pwriteMessage->node); + freeListFree(pasTrapWritePvt->freeListWriteMessage,(void *)pwriteMessage); + semGive(pasTrapWritePvt->lock); +} diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c index 2e6be4efc..8b0cae130 100644 --- a/src/rsrv/camessage.c +++ b/src/rsrv/camessage.c @@ -678,6 +678,7 @@ struct client *client struct channel_in_use *pciu; int v41; long status; + void *asWritePvt; pciu = MPTOPCIU(mp); if(!pciu){ @@ -725,11 +726,14 @@ struct client *client mp->m_count); #endif + asWritePvt = asTrapWriteBefore(pciu->asClientPVT, + pciu->client->pUserName,pciu->client->pHostName,(void *)&pciu->addr); status = db_put_field( &pciu->addr, mp->m_dataType, mp + 1, mp->m_count); + asTrapWriteAfter(asWritePvt); if (status < 0) { SEND_LOCK(client); send_err(