Files
epics-base/src/as/asLibRoutines.c
2004-03-29 19:32:20 +00:00

1332 lines
36 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* share/src/as/asLibRoutines.c */
/* share/src/as $Id$ */
/* Author: Marty Kraimer Date: 10-15-93 */
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "dbDefs.h"
#include "epicsThread.h"
#include "ellLib.h"
#include "cantProceed.h"
#include "epicsMutex.h"
#include "epicsPrint.h"
#include "gpHash.h"
#include "freeList.h"
#include "macLib.h"
#include "postfix.h"
#include "errlog.h"
#include "ellLib.h"
static epicsMutexId asLock;
#define LOCK epicsMutexMustLock(asLock)
#define UNLOCK epicsMutexUnlock(asLock)
#define epicsExportSharedSymbols
#include "asLib.h"
/*following must be global because asCa nneeds it*/
epicsShareDef ASBASE volatile *pasbase=NULL;
static ASBASE *pasbasenew=NULL;
epicsShareDef int asActive = FALSE;
static void *freeListPvt = NULL;
#define RPCL_LEN 184
#define DEFAULT "DEFAULT"
/*private routines */
static long asAddMemberPvt(ASMEMBERPVT *pasMemberPvt,char *asgName);
static long asComputeAllAsgPvt(void);
static long asComputeAsgPvt(ASG *pasg);
static long asComputePvt(ASCLIENTPVT asClientPvt);
static void asFreeAll(ASBASE *pasbase);
static UAG *asUagAdd(char *uagName);
static long asUagAddUser(UAG *puag,char *user);
static HAG *asHagAdd(char *hagName);
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);
/*
asInitialize can be called while access security is already active.
This is accomplished by doing the following:
The version pointed to by pasbase is kept as is but locked against changes
A new version is created and pointed to by pasbasenew
If anything goes wrong. The original version is kept. This results is some
wasted space but at least things still work.
If the new access security configuration is successfully read then:
the old memberList is moved from old to new.
the old structures are freed.
*/
static void asInitializeOnce(void *arg)
{
asLock = epicsMutexMustCreate();
}
long epicsShareAPI asInitialize(ASINPUTFUNCPTR inputfunction)
{
ASG *pasg;
long status;
ASBASE *pasbaseold;
GPHENTRY *pgphentry;
UAG *puag;
UAGNAME *puagname;
HAG *phag;
HAGNAME *phagname;
static epicsThreadOnceId asInitializeOnceFlag = EPICS_THREAD_ONCE_INIT;
epicsThreadOnce(&asInitializeOnceFlag,asInitializeOnce,(void *)0);
LOCK;
pasbasenew = asCalloc(1,sizeof(ASBASE));
if(!freeListPvt) freeListInitPvt(&freeListPvt,sizeof(ASGCLIENT),20);
ellInit(&pasbasenew->uagList);
ellInit(&pasbasenew->hagList);
ellInit(&pasbasenew->asgList);
asAsgAdd(DEFAULT);
status = myParse(inputfunction);
if(status) {
status = S_asLib_badConfig;
/*Not safe to call asFreeAll */
UNLOCK;
return(status);
}
pasg = (ASG *)ellFirst(&pasbasenew->asgList);
while(pasg) {
pasg->pavalue = asCalloc(ASMAXINP,sizeof(double));
pasg = (ASG *)ellNext((ELLNODE *)pasg);
}
gphInitPvt(&((ASBASE *)pasbasenew)->phash,256);
/*Hash each uagname and each hagname*/
puag = (UAG *)ellFirst(&pasbasenew->uagList);
while(puag) {
puagname = (UAGNAME *)ellFirst(&puag->list);
while(puagname) {
pgphentry = gphAdd(pasbasenew->phash,puagname->user,puag);
if(!pgphentry) {
epicsPrintf("UAG %s duplicate user = %s\n",
puag->name, puagname->user);
}
puagname = (UAGNAME *)ellNext((ELLNODE *)puagname);
}
puag = (UAG *)ellNext((ELLNODE *)puag);
}
phag = (HAG *)ellFirst(&pasbasenew->hagList);
while(phag) {
phagname = (HAGNAME *)ellFirst(&phag->list);
while(phagname) {
pgphentry = gphAdd(pasbasenew->phash,phagname->host,phag);
if(!pgphentry) {
epicsPrintf("HAG %s duplicate host = %s\n",
phag->name,phagname->host);
}
phagname = (HAGNAME *)ellNext((ELLNODE *)phagname);
}
phag = (HAG *)ellNext((ELLNODE *)phag);
}
pasbaseold = (ASBASE *)pasbase;
pasbase = (ASBASE volatile *)pasbasenew;
if(pasbaseold) {
ASG *poldasg;
ASGMEMBER *poldmem;
ASGMEMBER *pnextoldmem;
poldasg = (ASG *)ellFirst(&pasbaseold->asgList);
while(poldasg) {
poldmem = (ASGMEMBER *)ellFirst(&poldasg->memberList);
while(poldmem) {
pnextoldmem = (ASGMEMBER *)ellNext((ELLNODE *)poldmem);
ellDelete(&poldasg->memberList,(ELLNODE *)poldmem);
status = asAddMemberPvt(&poldmem,poldmem->asgName);
poldmem = pnextoldmem;
}
poldasg = (ASG *)ellNext((ELLNODE *)poldasg);
}
asFreeAll(pasbaseold);
}
asActive = TRUE;
UNLOCK;
return(0);
}
long epicsShareAPI asInitFile(const char *filename,const char *substitutions)
{
FILE *fp;
long status;
fp = fopen(filename,"r");
if(!fp) {
errMessage(0,"asInitFile failure on fopen");
return(S_asLib_badConfig);
}
status = asInitFP(fp,substitutions);
if(fclose(fp)==EOF) {
errMessage(0,"asInitFile fclose failure");
if(!status) status = S_asLib_badConfig;
}
return(status);
}
#define BUF_SIZE 200
static char *my_buffer;
static char *my_buffer_ptr;
static FILE *stream;
static char *mac_input_buffer=NULL;
static MAC_HANDLE *macHandle = NULL;
static int myInputFunction(char *buf, int max_size)
{
int l,n;
char *fgetsRtn;
if(*my_buffer_ptr==0) {
if(macHandle) {
fgetsRtn = fgets(mac_input_buffer,BUF_SIZE,stream);
if(fgetsRtn) {
n = macExpandString(macHandle,mac_input_buffer,
my_buffer,BUF_SIZE-1);
if(n<0) {
epicsPrintf("access security: macExpandString failed\n"
"input line: %s\n",mac_input_buffer);
return(0);
}
}
} else {
fgetsRtn = fgets(my_buffer,BUF_SIZE,stream);
}
if(fgetsRtn==NULL) return(0);
my_buffer_ptr = my_buffer;
}
l = strlen(my_buffer_ptr);
n = (l<=max_size ? l : max_size);
memcpy(buf,my_buffer_ptr,n);
my_buffer_ptr += n;
return(n);
}
long epicsShareAPI asInitFP(FILE *fp,const char *substitutions)
{
char buffer[BUF_SIZE];
char mac_buffer[BUF_SIZE];
long status;
char **macPairs;
buffer[0] = 0;
my_buffer = buffer;
my_buffer_ptr = my_buffer;
stream = fp;
if(substitutions) {
if((status = macCreateHandle(&macHandle,NULL))) {
errMessage(status,"asInitFP: macCreateHandle error");
return(status);
}
macParseDefns(macHandle,(char *)substitutions,&macPairs);
if(macPairs ==NULL) {
macDeleteHandle(macHandle);
macHandle = NULL;
} else {
macInstallMacros(macHandle,macPairs);
free((void *)macPairs);
mac_input_buffer = mac_buffer;
}
}
status = asInitialize(myInputFunction);
if(macHandle) {
macDeleteHandle(macHandle);
macHandle = NULL;
}
return(status);
}
long epicsShareAPI asAddMember(ASMEMBERPVT *pasMemberPvt,char *asgName)
{
long status;
if(!asActive) return(S_asLib_asNotActive);
LOCK;
status = asAddMemberPvt(pasMemberPvt,asgName);
UNLOCK;
return(status);
}
long epicsShareAPI asRemoveMember(ASMEMBERPVT *asMemberPvt)
{
ASGMEMBER *pasgmember;
if(!asActive) return(S_asLib_asNotActive);
pasgmember = *asMemberPvt;
if(!pasgmember) return(S_asLib_badMember);
LOCK;
if(ellCount(&pasgmember->clientList)>0) return(S_asLib_clientsExist);
if(pasgmember->pasg) {
ellDelete(&pasgmember->pasg->memberList,(ELLNODE *)pasgmember);
} else {
errMessage(-1,"Logic error in asRemoveMember");
UNLOCK;
exit(-1);
}
free((void *)pasgmember);
*asMemberPvt = NULL;
UNLOCK;
return(0);
}
long epicsShareAPI asChangeGroup(ASMEMBERPVT *asMemberPvt,char *newAsgName)
{
ASGMEMBER *pasgmember;
long status;
if(!asActive) return(S_asLib_asNotActive);
pasgmember = *asMemberPvt;
if(!pasgmember) return(S_asLib_badMember);
LOCK;
if(pasgmember->pasg) {
ellDelete(&pasgmember->pasg->memberList,(ELLNODE *)pasgmember);
} else {
errMessage(-1,"Logic error in asChangeGroup");
UNLOCK;
exit(-1);
}
status = asAddMemberPvt(asMemberPvt,newAsgName);
UNLOCK;
return(status);
}
void * epicsShareAPI asGetMemberPvt(ASMEMBERPVT asMemberPvt)
{
ASGMEMBER *pasgmember = asMemberPvt;
if(!asActive) return(NULL);
if(!pasgmember) return(NULL);
return(pasgmember->userPvt);
}
void epicsShareAPI asPutMemberPvt(ASMEMBERPVT asMemberPvt,void *userPvt)
{
ASGMEMBER *pasgmember = asMemberPvt;
if(!asActive) return;
if(!pasgmember) return;
pasgmember->userPvt = userPvt;
return;
}
long epicsShareAPI asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt,
int asl,char *user,char *host)
{
ASGMEMBER *pasgmember = asMemberPvt;
ASGCLIENT *pasgclient;
int ind;
long status;
if(!asActive) return(S_asLib_asNotActive);
if(!pasgmember) return(S_asLib_badMember);
pasgclient = freeListCalloc(freeListPvt);
if(!pasgclient) return(S_asLib_noMemory);
*pasClientPvt = pasgclient;
pasgclient->pasgMember = asMemberPvt;
pasgclient->level = asl;
pasgclient->user = user;
pasgclient->host = host;
for(ind=0; ind<strlen(pasgclient->host); ind++) {
pasgclient->host[ind] = (char)tolower((int)pasgclient->host[ind]);
}
LOCK;
ellAdd(&pasgmember->clientList,(ELLNODE *)pasgclient);
status = asComputePvt(pasgclient);
UNLOCK;
return(status);
}
long epicsShareAPI asChangeClient(ASCLIENTPVT asClientPvt,int asl,char *user,char *host)
{
ASGCLIENT *pasgclient = asClientPvt;
long status;
if(!asActive) return(S_asLib_asNotActive);
if(!pasgclient) return(S_asLib_badClient);
LOCK;
pasgclient->level = asl;
pasgclient->user = user;
pasgclient->host = host;
status = asComputePvt(pasgclient);
UNLOCK;
return(status);
}
long epicsShareAPI asRemoveClient(ASCLIENTPVT *asClientPvt)
{
ASGCLIENT *pasgclient = *asClientPvt;
ASGMEMBER *pasgMember;
if(!asActive) return(S_asLib_asNotActive);
if(!pasgclient) return(S_asLib_badClient);
LOCK;
pasgMember = pasgclient->pasgMember;
if(!pasgMember) {
errMessage(-1,"asRemoveClient: No ASGMEMBER");
UNLOCK;
return(-1);
}
ellDelete(&pasgMember->clientList,(ELLNODE *)pasgclient);
UNLOCK;
freeListFree(freeListPvt,pasgclient);
*asClientPvt = NULL;
return(0);
}
long epicsShareAPI asRegisterClientCallback(ASCLIENTPVT asClientPvt,
ASCLIENTCALLBACK pcallback)
{
ASGCLIENT *pasgclient = asClientPvt;
if(!asActive) return(S_asLib_asNotActive);
if(!pasgclient) return(S_asLib_badClient);
LOCK;
pasgclient->pcallback = pcallback;
(*pasgclient->pcallback)(pasgclient,asClientCOAR);
UNLOCK;
return(0);
}
void * epicsShareAPI asGetClientPvt(ASCLIENTPVT asClientPvt)
{
ASGCLIENT *pasgclient = asClientPvt;
if(!asActive) return(NULL);
if(!pasgclient) return(NULL);
return(pasgclient->userPvt);
}
void epicsShareAPI asPutClientPvt(ASCLIENTPVT asClientPvt,void *userPvt)
{
ASGCLIENT *pasgclient = asClientPvt;
if(!asActive) return;
if(!pasgclient) return;
LOCK;
pasgclient->userPvt = userPvt;
UNLOCK;
}
long epicsShareAPI asComputeAllAsg(void)
{
long status;
if(!asActive) return(S_asLib_asNotActive);
LOCK;
status = asComputeAllAsgPvt();
UNLOCK;
return(status);
}
long epicsShareAPI asComputeAsg(ASG *pasg)
{
long status;
if(!asActive) return(S_asLib_asNotActive);
LOCK;
status = asComputeAsgPvt(pasg);
UNLOCK;
return(status);
}
long epicsShareAPI asCompute(ASCLIENTPVT asClientPvt)
{
long status;
if(!asActive) return(S_asLib_asNotActive);
LOCK;
status = asComputePvt(asClientPvt);
UNLOCK;
return(status);
}
/*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 *),
void (*clientcallback)(struct asgClient *),
int verbose)
{
return asDumpFP(stdout,memcallback,clientcallback,verbose);
}
int epicsShareAPI asDumpFP(
FILE *fp,
void (*memcallback)(struct asgMember *),
void (*clientcallback)(struct asgClient *),
int verbose)
{
UAG *puag;
UAGNAME *puagname;
HAG *phag;
HAGNAME *phagname;
ASG *pasg;
ASGINP *pasginp;
ASGRULE *pasgrule;
ASGHAG *pasghag;
ASGUAG *pasguag;
ASGMEMBER *pasgmember;
ASGCLIENT *pasgclient;
if(!asActive) return(0);
puag = (UAG *)ellFirst(&pasbase->uagList);
if(!puag) fprintf(fp,"No UAGs\n");
while(puag) {
fprintf(fp,"UAG(%s)",puag->name);
puagname = (UAGNAME *)ellFirst(&puag->list);
if(puagname) fprintf(fp," {"); else fprintf(fp,"\n");
while(puagname) {
fprintf(fp,"%s",puagname->user);
puagname = (UAGNAME *)ellNext((ELLNODE *)puagname);
if(puagname) fprintf(fp,","); else fprintf(fp,"}\n");
}
puag = (UAG *)ellNext((ELLNODE *)puag);
}
phag = (HAG *)ellFirst(&pasbase->hagList);
if(!phag) fprintf(fp,"No HAGs\n");
while(phag) {
fprintf(fp,"HAG(%s)",phag->name);
phagname = (HAGNAME *)ellFirst(&phag->list);
if(phagname) fprintf(fp," {"); else fprintf(fp,"\n");
while(phagname) {
fprintf(fp,"%s",phagname->host);
phagname = (HAGNAME *)ellNext((ELLNODE *)phagname);
if(phagname) fprintf(fp,","); else fprintf(fp,"}\n");
}
phag = (HAG *)ellNext((ELLNODE *)phag);
}
pasg = (ASG *)ellFirst(&pasbase->asgList);
if(!pasg) fprintf(fp,"No ASGs\n");
while(pasg) {
int print_end_brace;
fprintf(fp,"ASG(%s)",pasg->name);
pasginp = (ASGINP *)ellFirst(&pasg->inpList);
pasgrule = (ASGRULE *)ellFirst(&pasg->ruleList);
if(pasginp || pasgrule) {
fprintf(fp," {\n");
print_end_brace = TRUE;
} else {
fprintf(fp,"\n");
print_end_brace = FALSE;
}
while(pasginp) {
fprintf(fp,"\tINP%c(%s)",(pasginp->inpIndex + 'A'),pasginp->inp);
if(verbose) {
if((pasg->inpBad & (1<<pasginp->inpIndex)))
fprintf(fp," INVALID");
else
fprintf(fp," VALID");
fprintf(fp," value=%f",pasg->pavalue[pasginp->inpIndex]);
}
fprintf(fp,"\n");
pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
}
while(pasgrule) {
int print_end_brace;
fprintf(fp,"\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) {
fprintf(fp," {\n");
print_end_brace = TRUE;
} else {
fprintf(fp,"\n");
print_end_brace = FALSE;
}
if(pasguag) fprintf(fp,"\t\tUAG(");
while(pasguag) {
fprintf(fp,"%s",pasguag->puag->name);
pasguag = (ASGUAG *)ellNext((ELLNODE *)pasguag);
if(pasguag) fprintf(fp,","); else fprintf(fp,")\n");
}
pasghag = (ASGHAG *)ellFirst(&pasgrule->hagList);
if(pasghag) fprintf(fp,"\t\tHAG(");
while(pasghag) {
fprintf(fp,"%s",pasghag->phag->name);
pasghag = (ASGHAG *)ellNext((ELLNODE *)pasghag);
if(pasghag) fprintf(fp,","); else fprintf(fp,")\n");
}
if(pasgrule->calc) {
fprintf(fp,"\t\tCALC(\"%s\")",pasgrule->calc);
if(verbose)
fprintf(fp," result=%s",(pasgrule->result ? "TRUE" : "FALSE"));
fprintf(fp,"\n");
}
if(print_end_brace) fprintf(fp,"\t}\n");
pasgrule = (ASGRULE *)ellNext((ELLNODE *)pasgrule);
}
pasgmember = (ASGMEMBER *)ellFirst(&pasg->memberList);
if(!verbose) pasgmember = NULL;
if(pasgmember) fprintf(fp,"\tMEMBERLIST\n");
while(pasgmember) {
if(strlen(pasgmember->asgName)==0)
fprintf(fp,"\t\t<null>");
else
fprintf(fp,"\t\t%s",pasgmember->asgName);
if(memcallback) memcallback(pasgmember);
fprintf(fp,"\n");
pasgclient = (ASGCLIENT *)ellFirst(&pasgmember->clientList);
while(pasgclient) {
fprintf(fp,"\t\t\t %s %s",pasgclient->user,pasgclient->host);
if(pasgclient->level>=0 && pasgclient->level<=1)
fprintf(fp," %s",asLevelName[pasgclient->level]);
else
fprintf(fp," Illegal Level %d",pasgclient->level);
if(pasgclient->access>=0 && pasgclient->access<=2)
fprintf(fp," %s %s",
asAccessName[pasgclient->access],
asTrapOption[pasgclient->trapMask]);
else
fprintf(fp," Illegal Access %d",pasgclient->access);
if(clientcallback) clientcallback(pasgclient);
fprintf(fp,"\n");
pasgclient = (ASGCLIENT *)ellNext((ELLNODE *)pasgclient);
}
pasgmember = (ASGMEMBER *)ellNext((ELLNODE *)pasgmember);
}
if(print_end_brace) fprintf(fp,"}\n");
pasg = (ASG *)ellNext((ELLNODE *)pasg);
}
return(0);
}
int epicsShareAPI asDumpUag(char *uagname)
{
return asDumpUagFP(stdout,uagname);
}
int epicsShareAPI asDumpUagFP(FILE *fp,char *uagname)
{
UAG *puag;
UAGNAME *puagname;
if(!asActive) return(0);
puag = (UAG *)ellFirst(&pasbase->uagList);
if(!puag) fprintf(fp,"No UAGs\n");
while(puag) {
if(uagname && strcmp(uagname,puag->name)!=0) {
puag = (UAG *)ellNext((ELLNODE *)puag);
continue;
}
fprintf(fp,"UAG(%s)",puag->name);
puagname = (UAGNAME *)ellFirst(&puag->list);
if(puagname) fprintf(fp," {"); else fprintf(fp,"\n");
while(puagname) {
fprintf(fp,"%s",puagname->user);
puagname = (UAGNAME *)ellNext((ELLNODE *)puagname);
if(puagname) fprintf(fp,","); else fprintf(fp,"}\n");
}
puag = (UAG *)ellNext((ELLNODE *)puag);
}
return(0);
}
int epicsShareAPI asDumpHag(char *hagname)
{
return asDumpHagFP(stdout,hagname);
}
int epicsShareAPI asDumpHagFP(FILE *fp,char *hagname)
{
HAG *phag;
HAGNAME *phagname;
if(!asActive) return(0);
phag = (HAG *)ellFirst(&pasbase->hagList);
if(!phag) fprintf(fp,"No HAGs\n");
while(phag) {
if(hagname && strcmp(hagname,phag->name)!=0) {
phag = (HAG *)ellNext((ELLNODE *)phag);
continue;
}
fprintf(fp,"HAG(%s)",phag->name);
phagname = (HAGNAME *)ellFirst(&phag->list);
if(phagname) fprintf(fp," {"); else fprintf(fp,"\n");
while(phagname) {
fprintf(fp,"%s",phagname->host);
phagname = (HAGNAME *)ellNext((ELLNODE *)phagname);
if(phagname) fprintf(fp,","); else fprintf(fp,"}\n");
}
phag = (HAG *)ellNext((ELLNODE *)phag);
}
return(0);
}
int epicsShareAPI asDumpRules(char *asgname)
{
return asDumpRulesFP(stdout,asgname);
}
int epicsShareAPI asDumpRulesFP(FILE *fp,char *asgname)
{
ASG *pasg;
ASGINP *pasginp;
ASGRULE *pasgrule;
ASGHAG *pasghag;
ASGUAG *pasguag;
if(!asActive) return(0);
pasg = (ASG *)ellFirst(&pasbase->asgList);
if(!pasg) fprintf(fp,"No ASGs\n");
while(pasg) {
int print_end_brace;
if(asgname && strcmp(asgname,pasg->name)!=0) {
pasg = (ASG *)ellNext((ELLNODE *)pasg);
continue;
}
fprintf(fp,"ASG(%s)",pasg->name);
pasginp = (ASGINP *)ellFirst(&pasg->inpList);
pasgrule = (ASGRULE *)ellFirst(&pasg->ruleList);
if(pasginp || pasgrule) {
fprintf(fp," {\n");
print_end_brace = TRUE;
} else {
fprintf(fp,"\n");
print_end_brace = FALSE;
}
while(pasginp) {
fprintf(fp,"\tINP%c(%s)",(pasginp->inpIndex + 'A'),pasginp->inp);
if((pasg->inpBad & (1<<pasginp->inpIndex))) fprintf(fp," INVALID");
fprintf(fp," value=%f",pasg->pavalue[pasginp->inpIndex]);
fprintf(fp,"\n");
pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
}
while(pasgrule) {
int print_end_brace;
fprintf(fp,"\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) {
fprintf(fp," {\n");
print_end_brace = TRUE;
} else {
fprintf(fp,"\n");
print_end_brace = FALSE;
}
if(pasguag) fprintf(fp,"\t\tUAG(");
while(pasguag) {
fprintf(fp,"%s",pasguag->puag->name);
pasguag = (ASGUAG *)ellNext((ELLNODE *)pasguag);
if(pasguag) fprintf(fp,","); else fprintf(fp,")\n");
}
pasghag = (ASGHAG *)ellFirst(&pasgrule->hagList);
if(pasghag) fprintf(fp,"\t\tHAG(");
while(pasghag) {
fprintf(fp,"%s",pasghag->phag->name);
pasghag = (ASGHAG *)ellNext((ELLNODE *)pasghag);
if(pasghag) fprintf(fp,","); else fprintf(fp,")\n");
}
if(pasgrule->calc) {
fprintf(fp,"\t\tCALC(\"%s\")",pasgrule->calc);
fprintf(fp," result=%s",(pasgrule->result ? "TRUE" : "FALSE"));
fprintf(fp,"\n");
}
if(print_end_brace) fprintf(fp,"\t}\n");
pasgrule = (ASGRULE *)ellNext((ELLNODE *)pasgrule);
}
if(print_end_brace) fprintf(fp,"}\n");
pasg = (ASG *)ellNext((ELLNODE *)pasg);
}
return(0);
}
int epicsShareAPI asDumpMem(char *asgname,void (*memcallback)(ASMEMBERPVT),
int clients)
{
return asDumpMemFP(stdout,asgname,memcallback,clients);
}
int epicsShareAPI asDumpMemFP(FILE *fp,char *asgname,
void (*memcallback)(ASMEMBERPVT),int clients)
{
ASG *pasg;
ASGMEMBER *pasgmember;
ASGCLIENT *pasgclient;
if(!asActive) return(0);
pasg = (ASG *)ellFirst(&pasbase->asgList);
if(!pasg) fprintf(fp,"No ASGs\n");
while(pasg) {
if(asgname && strcmp(asgname,pasg->name)!=0) {
pasg = (ASG *)ellNext((ELLNODE *)pasg);
continue;
}
fprintf(fp,"ASG(%s)\n",pasg->name);
pasgmember = (ASGMEMBER *)ellFirst(&pasg->memberList);
if(pasgmember) fprintf(fp,"\tMEMBERLIST\n");
while(pasgmember) {
if(strlen(pasgmember->asgName)==0)
fprintf(fp,"\t\t<null>");
else
fprintf(fp,"\t\t%s",pasgmember->asgName);
if(memcallback) memcallback(pasgmember);
fprintf(fp,"\n");
pasgclient = (ASGCLIENT *)ellFirst(&pasgmember->clientList);
if(!clients) pasgclient = NULL;
while(pasgclient) {
fprintf(fp,"\t\t\t %s %s",
pasgclient->user,pasgclient->host);
if(pasgclient->level>=0 && pasgclient->level<=1)
fprintf(fp," %s",asLevelName[pasgclient->level]);
else
fprintf(fp," Illegal Level %d",pasgclient->level);
if(pasgclient->access>=0 && pasgclient->access<=2)
fprintf(fp," %s %s",
asAccessName[pasgclient->access],
asTrapOption[pasgclient->trapMask]);
else
fprintf(fp," Illegal Access %d",pasgclient->access);
fprintf(fp,"\n");
pasgclient = (ASGCLIENT *)ellNext((ELLNODE *)pasgclient);
}
pasgmember = (ASGMEMBER *)ellNext((ELLNODE *)pasgmember);
}
pasg = (ASG *)ellNext((ELLNODE *)pasg);
}
return(0);
}
epicsShareFunc int epicsShareAPI asDumpHash(void)
{
return asDumpHashFP(stdout);
}
epicsShareFunc int epicsShareAPI asDumpHashFP(FILE *fp)
{
if(!asActive) return(0);
gphDumpFP(pasbase->phash,fp);
return(0);
}
/*Start of private routines*/
/* asCalloc is "friend" function */
epicsShareFunc void * epicsShareAPI asCalloc(size_t nobj,size_t size)
{
void *p;
p=callocMustSucceed(nobj,size,"asCalloc");
return(p);
}
static long asAddMemberPvt(ASMEMBERPVT *pasMemberPvt,char *asgName)
{
ASGMEMBER *pasgmember;
ASG *pgroup;
ASGCLIENT *pasgclient;
if(*pasMemberPvt) {
pasgmember = *pasMemberPvt;
} else {
pasgmember = asCalloc(1,sizeof(ASGMEMBER));
ellInit(&pasgmember->clientList);
*pasMemberPvt = pasgmember;
}
pasgmember->asgName = asgName;
pgroup = (ASG *)ellFirst(&pasbase->asgList);
while(pgroup) {
if(strcmp(pgroup->name,pasgmember->asgName)==0) goto got_it;
pgroup = (ASG *)ellNext((ELLNODE *)pgroup);
}
/* Put it in DEFAULT*/
pgroup = (ASG *)ellFirst(&pasbase->asgList);
while(pgroup) {
if(strcmp(pgroup->name,DEFAULT)==0) goto got_it;
pgroup = (ASG *)ellNext((ELLNODE *)pgroup);
}
errMessage(-1,"Logic Error in asAddMember");
exit(1);
got_it:
pasgmember->pasg = pgroup;
ellAdd(&pgroup->memberList,(ELLNODE *)pasgmember);
pasgclient = (ASGCLIENT *)ellFirst(&pasgmember->clientList);
while(pasgclient) {
asComputePvt((ASCLIENTPVT)pasgclient);
pasgclient = (ASGCLIENT *)ellNext((ELLNODE *)pasgclient);
}
return(0);
}
static long asComputeAllAsgPvt(void)
{
ASG *pasg;
if(!asActive) return(S_asLib_asNotActive);
pasg = (ASG *)ellFirst(&pasbase->asgList);
while(pasg) {
asComputeAsgPvt(pasg);
pasg = (ASG *)ellNext((ELLNODE *)pasg);
}
return(0);
}
static long asComputeAsgPvt(ASG *pasg)
{
ASGRULE *pasgrule;
ASGMEMBER *pasgmember;
ASGCLIENT *pasgclient;
if(!asActive) return(S_asLib_asNotActive);
pasgrule = (ASGRULE *)ellFirst(&pasg->ruleList);
while(pasgrule) {
double result;
long status;
if(pasgrule->calc && (pasg->inpChanged & pasgrule->inpUsed)) {
status = calcPerform(pasg->pavalue,&result,pasgrule->rpcl);
if(status) {
pasgrule->result = 0;
errMessage(status,"asComputeAsg");
} else {
pasgrule->result = ((result>.99) && (result<1.01)) ? 1 : 0;
}
}
pasgrule = (ASGRULE *)ellNext((ELLNODE *)pasgrule);
}
pasg->inpChanged = FALSE;
pasgmember = (ASGMEMBER *)ellFirst(&pasg->memberList);
while(pasgmember) {
pasgclient = (ASGCLIENT *)ellFirst(&pasgmember->clientList);
while(pasgclient) {
asComputePvt((ASCLIENTPVT)pasgclient);
pasgclient = (ASGCLIENT *)ellNext((ELLNODE *)pasgclient);
}
pasgmember = (ASGMEMBER *)ellNext((ELLNODE *)pasgmember);
}
return(0);
}
static long asComputePvt(ASCLIENTPVT asClientPvt)
{
asAccessRights access=asNOACCESS;
int trapMask=0;
ASGCLIENT *pasgclient = asClientPvt;
ASGMEMBER *pasgMember;
ASG *pasg;
ASGRULE *pasgrule;
asAccessRights oldaccess;
GPHENTRY *pgphentry;
if(!asActive) return(S_asLib_asNotActive);
if(!pasgclient) return(S_asLib_badClient);
pasgMember = pasgclient->pasgMember;
if(!pasgMember) return(S_asLib_badMember);
pasg = pasgMember->pasg;
if(!pasg) return(S_asLib_badAsg);
oldaccess=pasgclient->access;
pasgrule = (ASGRULE *)ellFirst(&pasg->ruleList);
while(pasgrule) {
if(access == asWRITE) break;
if(access>=pasgrule->access) goto next_rule;
if(pasgclient->level > pasgrule->level) goto next_rule;
/*if uagList is empty then no need to check uag*/
if(ellCount(&pasgrule->uagList)>0){
ASGUAG *pasguag;
UAG *puag;
pasguag = (ASGUAG *)ellFirst(&pasgrule->uagList);
while(pasguag) {
if((puag = pasguag->puag)) {
pgphentry = gphFind(pasbase->phash,pasgclient->user,puag);
if(pgphentry) goto check_hag;
}
pasguag = (ASGUAG *)ellNext((ELLNODE *)pasguag);
}
goto next_rule;
}
check_hag:
/*if hagList is empty then no need to check hag*/
if(ellCount(&pasgrule->hagList)>0) {
ASGHAG *pasghag;
HAG *phag;
pasghag = (ASGHAG *)ellFirst(&pasgrule->hagList);
while(pasghag) {
if((phag = pasghag->phag)) {
pgphentry=gphFind(pasbase->phash,pasgclient->host,phag);
if(pgphentry) goto check_calc;
}
pasghag = (ASGHAG *)ellNext((ELLNODE *)pasghag);
}
goto next_rule;
}
check_calc:
if(!pasgrule->calc
|| (!(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);
}
return(0);
}
static void asFreeAll(ASBASE *pasbase)
{
UAG *puag;
UAGNAME *puagname;
HAG *phag;
HAGNAME *phagname;
ASG *pasg;
ASGINP *pasginp;
ASGRULE *pasgrule;
ASGHAG *pasghag;
ASGUAG *pasguag;
void *pnext;
puag = (UAG *)ellFirst(&pasbase->uagList);
while(puag) {
puagname = (UAGNAME *)ellFirst(&puag->list);
while(puagname) {
pnext = ellNext((ELLNODE *)puagname);
ellDelete(&puag->list,(ELLNODE *)puagname);
free((void *)puagname);
puagname = pnext;
}
pnext = ellNext((ELLNODE *)puag);
ellDelete(&pasbase->uagList,(ELLNODE *)puag);
free((void *)puag);
puag = pnext;
}
phag = (HAG *)ellFirst(&pasbase->hagList);
while(phag) {
phagname = (HAGNAME *)ellFirst(&phag->list);
while(phagname) {
pnext = ellNext((ELLNODE *)phagname);
ellDelete(&phag->list,(ELLNODE *)phagname);
free((void *)phagname);
phagname = pnext;
}
pnext = ellNext((ELLNODE *)phag);
ellDelete(&pasbase->hagList,(ELLNODE *)phag);
free((void *)phag);
phag = pnext;
}
pasg = (ASG *)ellFirst(&pasbase->asgList);
while(pasg) {
free((void *)pasg->pavalue);
pasginp = (ASGINP *)ellFirst(&pasg->inpList);
while(pasginp) {
pnext = ellNext((ELLNODE *)pasginp);
ellDelete(&pasg->inpList,(ELLNODE *)pasginp);
free((void *)pasginp);
pasginp = pnext;
}
pasgrule = (ASGRULE *)ellFirst(&pasg->ruleList);
while(pasgrule) {
free((void *)pasgrule->calc);
free((void *)pasgrule->rpcl);
pasguag = (ASGUAG *)ellFirst(&pasgrule->uagList);
while(pasguag) {
pnext = ellNext((ELLNODE *)pasguag);
ellDelete(&pasgrule->uagList,(ELLNODE *)pasguag);
free((void *)pasguag);
pasguag = pnext;
}
pasghag = (ASGHAG *)ellFirst(&pasgrule->hagList);
while(pasghag) {
pnext = ellNext((ELLNODE *)pasghag);
ellDelete(&pasgrule->hagList,(ELLNODE *)pasghag);
free((void *)pasghag);
pasghag = pnext;
}
pnext = ellNext((ELLNODE *)pasgrule);
ellDelete(&pasg->ruleList,(ELLNODE *)pasgrule);
free((void *)pasgrule);
pasgrule = pnext;
}
pnext = ellNext((ELLNODE *)pasg);
ellDelete(&pasbase->asgList,(ELLNODE *)pasg);
free((void *)pasg);
pasg = pnext;
}
gphFreeMem(pasbase->phash);
free((void *)pasbase);
}
/*Beginning of routines called by lex code*/
static UAG *asUagAdd(char *uagName)
{
UAG *pprev;
UAG *pnext;
UAG *puag;
int cmpvalue;
ASBASE *pasbase = (ASBASE *)pasbasenew;
/*Insert in alphabetic order*/
pnext = (UAG *)ellFirst(&pasbase->uagList);
while(pnext) {
cmpvalue = strcmp(uagName,pnext->name);
if(cmpvalue < 0) break;
if(cmpvalue==0) {
errMessage(-1,"Duplicate User Access Group");
return(NULL);
}
pnext = (UAG *)ellNext((ELLNODE *)pnext);
}
puag = asCalloc(1,sizeof(UAG)+strlen(uagName)+1);
ellInit(&puag->list);
puag->name = (char *)(puag+1);
strcpy(puag->name,uagName);
if(pnext==NULL) { /*Add to end of list*/
ellAdd(&pasbase->uagList,(ELLNODE *)puag);
} else {
pprev = (UAG *)ellPrevious((ELLNODE *)pnext);
ellInsert(&pasbase->uagList,(ELLNODE *)pprev,(ELLNODE *)puag);
}
return(puag);
}
static long asUagAddUser(UAG *puag,char *user)
{
UAGNAME *puagname;
if(!puag) return(0);
puagname = asCalloc(1,sizeof(UAGNAME)+strlen(user)+1);
puagname->user = (char *)(puagname+1);
strcpy(puagname->user,user);
ellAdd(&puag->list,(ELLNODE *)puagname);
return(0);
}
static HAG *asHagAdd(char *hagName)
{
HAG *pprev;
HAG *pnext;
HAG *phag;
int cmpvalue;
ASBASE *pasbase = (ASBASE *)pasbasenew;
/*Insert in alphabetic order*/
pnext = (HAG *)ellFirst(&pasbase->hagList);
while(pnext) {
cmpvalue = strcmp(hagName,pnext->name);
if(cmpvalue < 0) break;
if(cmpvalue==0) {
errMessage(-1,"Duplicate Host Access Group");
return(NULL);
}
pnext = (HAG *)ellNext((ELLNODE *)pnext);
}
phag = asCalloc(1,sizeof(HAG)+strlen(hagName)+1);
ellInit(&phag->list);
phag->name = (char *)(phag+1);
strcpy(phag->name,hagName);
if(pnext==NULL) { /*Add to end of list*/
ellAdd(&pasbase->hagList,(ELLNODE *)phag);
} else {
pprev = (HAG *)ellPrevious((ELLNODE *)pnext);
ellInsert(&pasbase->hagList,(ELLNODE *)pprev,(ELLNODE *)phag);
}
return(phag);
}
static long asHagAddHost(HAG *phag,char *host)
{
HAGNAME *phagname;
int ind;
if(!phag) return(0);
phagname = asCalloc(1,sizeof(HAGNAME)+strlen(host)+1);
phagname->host = (char *)(phagname+1);
strcpy(phagname->host,host);
for(ind=0; ind<strlen(phagname->host); ind++) {
phagname->host[ind] = (char)tolower((int)phagname->host[ind]);
}
ellAdd(&phag->list,(ELLNODE *)phagname);
return(0);
}
static ASG *asAsgAdd(char *asgName)
{
ASG *pprev;
ASG *pnext;
ASG *pasg;
int cmpvalue;
ASBASE *pasbase = (ASBASE *)pasbasenew;
/*Insert in alphabetic order*/
pnext = (ASG *)ellFirst(&pasbase->asgList);
while(pnext) {
cmpvalue = strcmp(asgName,pnext->name);
if(cmpvalue < 0) break;
if(cmpvalue==0) {
if(strcmp(DEFAULT,pnext->name)==0) {
if(ellCount(&pnext->inpList)==0
&& ellCount(&pnext->ruleList)==0)
return(pnext);
}
errMessage(S_asLib_dupAsg,"asAsgAdd");
return(NULL);
}
pnext = (ASG *)ellNext((ELLNODE *)pnext);
}
pasg = asCalloc(1,sizeof(ASG)+strlen(asgName)+1);
ellInit(&pasg->inpList);
ellInit(&pasg->ruleList);
ellInit(&pasg->memberList);
pasg->name = (char *)(pasg+1);
strcpy(pasg->name,asgName);
if(pnext==NULL) { /*Add to end of list*/
ellAdd(&pasbase->asgList,(ELLNODE *)pasg);
} else {
pprev = (ASG *)ellPrevious((ELLNODE *)pnext);
ellInsert(&pasbase->asgList,(ELLNODE *)pprev,(ELLNODE *)pasg);
}
return(pasg);
}
static long asAsgAddInp(ASG *pasg,char *inp,int inpIndex)
{
ASGINP *pasginp;
if(!pasg) return(0);
pasginp = asCalloc(1,sizeof(ASGINP)+strlen(inp)+1);
pasginp->inp = (char *)(pasginp+1);
strcpy(pasginp->inp,inp);
pasginp->pasg = pasg;
pasginp->inpIndex = inpIndex;
ellAdd(&pasg->inpList,(ELLNODE *)pasginp);
return(0);
}
static ASGRULE *asAsgAddRule(ASG *pasg,asAccessRights access,int level)
{
ASGRULE *pasgrule;
if(!pasg) return(0);
pasgrule = asCalloc(1,sizeof(ASGRULE));
pasgrule->access = access;
pasgrule->trapMask = 0;
pasgrule->level = level;
ellInit(&pasgrule->uagList);
ellInit(&pasgrule->hagList);
ellAdd(&pasg->ruleList,(ELLNODE *)pasgrule);
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;
UAG *puag;
ASBASE *pasbase = (ASBASE *)pasbasenew;
long status;
if(!pasgrule) return(0);
puag = (UAG *)ellFirst(&pasbase->uagList);
while(puag) {
if(strcmp(puag->name,name)==0) break;
puag = (UAG *)ellNext((ELLNODE *)puag);
}
if(!puag){
status = S_asLib_noUag;
errMessage(status,": access security Error while adding UAG to RULE");
return(S_asLib_noUag);
}
pasguag = asCalloc(1,sizeof(ASGUAG));
pasguag->puag = puag;
ellAdd(&pasgrule->uagList,(ELLNODE *)pasguag);
return(0);
}
static long asAsgRuleHagAdd(ASGRULE *pasgrule,char *name)
{
ASGHAG *pasghag;
HAG *phag;
ASBASE *pasbase = (ASBASE *)pasbasenew;
long status;
if(!pasgrule) return(0);
phag = (HAG *)ellFirst(&pasbase->hagList);
while(phag) {
if(strcmp(phag->name,name)==0) break;
phag = (HAG *)ellNext((ELLNODE *)phag);
}
if(!phag){
status = S_asLib_noHag;
errMessage(status,": access security Error while adding HAG to RULE");
return(S_asLib_noHag);
}
pasghag = asCalloc(1,sizeof(ASGHAG));
pasghag->phag = phag;
ellAdd(&pasgrule->hagList,(ELLNODE *)pasghag);
return(0);
}
static long asAsgRuleCalc(ASGRULE *pasgrule,char *calc)
{
short error_number;
long status;
if(!pasgrule) return(0);
pasgrule->calc = asCalloc(1,strlen(calc)+1);
strcpy(pasgrule->calc,calc);
pasgrule->rpcl = asCalloc(1,RPCL_LEN);
status=postfix(pasgrule->calc,pasgrule->rpcl,&error_number);
if(status) {
free((void *)pasgrule->calc);
free((void *)pasgrule->rpcl);
pasgrule->calc = NULL;
pasgrule->rpcl = NULL;
status = S_asLib_badCalc;
errMessage(status,":Access Security Failure");
} else {
int i;
for(i=0; i<ASMAXINP; i++) {
if(strchr(calc,'A'+i)) pasgrule->inpUsed |= (1<<i);
if(strchr(calc,'a'+i)) pasgrule->inpUsed |= (1<<i);
}
}
return(status);
}