Files
epics-base/modules/libcom/src/as/asLibRoutines.c
Michael Davidsaver 1595ed8860 quieting clang-tidy, non-functional changes
Changes to syntax which should not effect generated code
2023-08-28 14:17:00 +02:00

1411 lines
42 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.
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 10-15-93 */
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "osiSock.h"
#include "epicsTypes.h"
#include "epicsStdio.h"
#include "dbDefs.h"
#include "epicsThread.h"
#include "cantProceed.h"
#include "epicsMutex.h"
#include "errlog.h"
#include "gpHash.h"
#include "freeList.h"
#include "macLib.h"
#include "postfix.h"
#include "asLib.h"
#undef ECHO /* from termios.h */
int asCheckClientIP;
static epicsMutexId asLock;
#define LOCK epicsMutexMustLock(asLock)
#define UNLOCK epicsMutexUnlock(asLock)
/*following must be global because asCa nneeds it*/
ASBASE volatile *pasbase=NULL;
static ASBASE *pasbasenew=NULL;
int asActive = FALSE;
static void *freeListPvt = NULL;
#define DEFAULT "DEFAULT"
/* Defined in asLib.y */
static int myParse(ASINPUTFUNCPTR inputfunction);
/*private routines */
static long asAddMemberPvt(ASMEMBERPVT *pasMemberPvt,const char *asgName);
static long asComputeAllAsgPvt(void);
static long asComputeAsgPvt(ASG *pasg);
static long asComputePvt(ASCLIENTPVT asClientPvt);
static UAG *asUagAdd(const char *uagName);
static long asUagAddUser(UAG *puag,const char *user);
static HAG *asHagAdd(const char *hagName);
static long asHagAddHost(HAG *phag,const char *host);
static ASG *asAsgAdd(const char *asgName);
static long asAsgAddInp(ASG *pasg,const 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,const char *name);
static long asAsgRuleHagAdd(ASGRULE *pasgrule,const char *name);
static long asAsgRuleCalc(ASGRULE *pasgrule,const 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)
{
osiSockAttach();
asLock = epicsMutexMustCreate();
}
long epicsStdCall 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(CALCPERFORM_NARGS, sizeof(double));
pasg = (ASG *)ellNext(&pasg->node);
}
gphInitPvt(&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) {
errlogPrintf("Duplicated user '%s' in UAG '%s'\n",
puagname->user, puag->name);
}
puagname = (UAGNAME *)ellNext(&puagname->node);
}
puag = (UAG *)ellNext(&puag->node);
}
phag = (HAG *)ellFirst(&pasbasenew->hagList);
while(phag) {
phagname = (HAGNAME *)ellFirst(&phag->list);
while(phagname) {
pgphentry = gphAdd(pasbasenew->phash,phagname->host,phag);
if(!pgphentry) {
errlogPrintf("Duplicated host '%s' in HAG '%s'\n",
phagname->host, phag->name);
}
phagname = (HAGNAME *)ellNext(&phagname->node);
}
phag = (HAG *)ellNext(&phag->node);
}
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(&poldmem->node);
ellDelete(&poldasg->memberList,&poldmem->node);
status = asAddMemberPvt(&poldmem,poldmem->asgName);
poldmem = pnextoldmem;
}
poldasg = (ASG *)ellNext(&poldasg->node);
}
asFreeAll(pasbaseold);
}
asActive = TRUE;
UNLOCK;
return(0);
}
long epicsStdCall asInitFile(const char *filename,const char *substitutions)
{
FILE *fp;
long status;
fp = fopen(filename,"r");
if(!fp) {
errlogPrintf("asInitFile: Can't open file '%s'\n", filename);
return(S_asLib_badConfig);
}
status = asInitFP(fp,substitutions);
if(fclose(fp)==EOF) {
errMessage(0,"asInitFile: fclose failed!");
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);
if(n<0) {
errlogPrintf("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 epicsStdCall 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,substitutions,&macPairs);
if(macPairs ==NULL) {
macDeleteHandle(macHandle);
macHandle = NULL;
} else {
macInstallMacros(macHandle,macPairs);
free(macPairs);
mac_input_buffer = mac_buffer;
}
}
status = asInitialize(myInputFunction);
if(macHandle) {
macDeleteHandle(macHandle);
macHandle = NULL;
}
return(status);
}
static const char* membuf;
static int memInputFunction(char *buf, int max_size)
{
int ret = 0;
if(!membuf) return ret;
while(max_size && *membuf) {
*buf++ = *membuf++;
max_size--;
ret++;
}
return ret;
}
long epicsStdCall asInitMem(const char *acf, const char *substitutions)
{
long ret = S_asLib_InitFailed;
if(!acf) return ret;
membuf = acf;
ret = asInitialize(&memInputFunction);
membuf = NULL;
return ret;
}
long epicsStdCall asAddMember(ASMEMBERPVT *pasMemberPvt,const char *asgName)
{
long status;
if(!asActive) return(S_asLib_asNotActive);
LOCK;
status = asAddMemberPvt(pasMemberPvt,asgName);
UNLOCK;
return(status);
}
long epicsStdCall 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) {
UNLOCK;
return(S_asLib_clientsExist);
}
if(pasgmember->pasg) {
ellDelete(&pasgmember->pasg->memberList,&pasgmember->node);
} else {
errMessage(-1,"Logic error in asRemoveMember");
UNLOCK;
return(-1);
}
free(pasgmember);
*asMemberPvt = NULL;
UNLOCK;
return(0);
}
long epicsStdCall asChangeGroup(ASMEMBERPVT *asMemberPvt,const 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,&pasgmember->node);
} else {
errMessage(-1,"Logic error in asChangeGroup");
UNLOCK;
return(-1);
}
status = asAddMemberPvt(asMemberPvt,newAsgName);
UNLOCK;
return(status);
}
void * epicsStdCall asGetMemberPvt(ASMEMBERPVT asMemberPvt)
{
ASGMEMBER *pasgmember = asMemberPvt;
if(!asActive) return(NULL);
if(!pasgmember) return(NULL);
return(pasgmember->userPvt);
}
void epicsStdCall asPutMemberPvt(ASMEMBERPVT asMemberPvt,void *userPvt)
{
ASGMEMBER *pasgmember = asMemberPvt;
if(!asActive) return;
if(!pasgmember) return;
pasgmember->userPvt = userPvt;
}
long epicsStdCall asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt,
int asl,const char *user,char *host)
{
ASGMEMBER *pasgmember = asMemberPvt;
ASGCLIENT *pasgclient;
int len, i;
long status;
if(!asActive) return(S_asLib_asNotActive);
if(!pasgmember) return(S_asLib_badMember);
pasgclient = freeListCalloc(freeListPvt);
if(!pasgclient) return(S_asLib_noMemory);
len = strlen(host);
for (i = 0; i < len; i++) {
host[i] = (char)tolower((int)host[i]);
}
*pasClientPvt = pasgclient;
pasgclient->pasgMember = asMemberPvt;
pasgclient->level = asl;
pasgclient->user = user;
pasgclient->host = host;
LOCK;
ellAdd(&pasgmember->clientList,&pasgclient->node);
status = asComputePvt(pasgclient);
UNLOCK;
return(status);
}
long epicsStdCall asChangeClient(
ASCLIENTPVT asClientPvt,int asl,const char *user,char *host)
{
ASGCLIENT *pasgclient = asClientPvt;
long status;
int len, i;
if(!asActive) return(S_asLib_asNotActive);
if(!pasgclient) return(S_asLib_badClient);
len = strlen(host);
for (i = 0; i < len; i++) {
host[i] = (char)tolower((int)host[i]);
}
LOCK;
pasgclient->level = asl;
pasgclient->user = user;
pasgclient->host = host;
status = asComputePvt(pasgclient);
UNLOCK;
return(status);
}
long epicsStdCall 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,&pasgclient->node);
UNLOCK;
freeListFree(freeListPvt,pasgclient);
*asClientPvt = NULL;
return(0);
}
long epicsStdCall 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 * epicsStdCall asGetClientPvt(ASCLIENTPVT asClientPvt)
{
ASGCLIENT *pasgclient = asClientPvt;
if(!asActive) return(NULL);
if(!pasgclient) return(NULL);
return(pasgclient->userPvt);
}
void epicsStdCall asPutClientPvt(ASCLIENTPVT asClientPvt,void *userPvt)
{
ASGCLIENT *pasgclient = asClientPvt;
if(!asActive) return;
if(!pasgclient) return;
LOCK;
pasgclient->userPvt = userPvt;
UNLOCK;
}
long epicsStdCall asComputeAllAsg(void)
{
long status;
if(!asActive) return(S_asLib_asNotActive);
LOCK;
status = asComputeAllAsgPvt();
UNLOCK;
return(status);
}
long epicsStdCall asComputeAsg(ASG *pasg)
{
long status;
if(!asActive) return(S_asLib_asNotActive);
LOCK;
status = asComputeAsgPvt(pasg);
UNLOCK;
return(status);
}
long epicsStdCall 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 inconsistent data.*/
/*HOWEVER if they did lock and a user interrupts one of then then BAD BAD*/
static const char *asAccessName[] = {"NONE","READ","WRITE"};
static const char *asTrapOption[] = {"NOTRAPWRITE","TRAPWRITE"};
static const char *asLevelName[] = {"ASL0","ASL1"};
int epicsStdCall asDump(
void (*memcallback)(struct asgMember *,FILE *),
void (*clientcallback)(struct asgClient *,FILE *),
int verbose)
{
return asDumpFP(stdout,memcallback,clientcallback,verbose);
}
int epicsStdCall asDumpFP(
FILE *fp,
void (*memcallback)(struct asgMember *,FILE *),
void (*clientcallback)(struct asgClient *,FILE *),
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(&puagname->node);
if(puagname) fprintf(fp,","); else fprintf(fp,"}\n");
}
puag = (UAG *)ellNext(&puag->node);
}
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(&phagname->node);
if(phagname) fprintf(fp,","); else fprintf(fp,"}\n");
}
phag = (HAG *)ellNext(&phag->node);
}
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 & (1ul << pasginp->inpIndex)))
fprintf(fp," INVALID");
else
fprintf(fp," VALID");
fprintf(fp," value=%f",pasg->pavalue[pasginp->inpIndex]);
}
fprintf(fp,"\n");
pasginp = (ASGINP *)ellNext(&pasginp->node);
}
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(&pasguag->node);
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(&pasghag->node);
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==1 ? "TRUE" : "FALSE"));
fprintf(fp,"\n");
}
if(print_end_brace) fprintf(fp,"\t}\n");
pasgrule = (ASGRULE *)ellNext(&pasgrule->node);
}
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,fp);
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<=2)
fprintf(fp," %s %s",
asAccessName[pasgclient->access],
asTrapOption[pasgclient->trapMask]);
else
fprintf(fp," Illegal Access %d",pasgclient->access);
if(clientcallback) clientcallback(pasgclient,fp);
fprintf(fp,"\n");
pasgclient = (ASGCLIENT *)ellNext(&pasgclient->node);
}
pasgmember = (ASGMEMBER *)ellNext(&pasgmember->node);
}
if(print_end_brace) fprintf(fp,"}\n");
pasg = (ASG *)ellNext(&pasg->node);
}
return(0);
}
int epicsStdCall asDumpUag(const char *uagname)
{
return asDumpUagFP(stdout,uagname);
}
int epicsStdCall asDumpUagFP(FILE *fp,const 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(&puag->node);
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(&puagname->node);
if(puagname) fprintf(fp,","); else fprintf(fp,"}\n");
}
puag = (UAG *)ellNext(&puag->node);
}
return(0);
}
int epicsStdCall asDumpHag(const char *hagname)
{
return asDumpHagFP(stdout,hagname);
}
int epicsStdCall asDumpHagFP(FILE *fp,const 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(&phag->node);
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(&phagname->node);
if(phagname) fprintf(fp,","); else fprintf(fp,"}\n");
}
phag = (HAG *)ellNext(&phag->node);
}
return(0);
}
int epicsStdCall asDumpRules(const char *asgname)
{
return asDumpRulesFP(stdout,asgname);
}
int epicsStdCall asDumpRulesFP(FILE *fp,const 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(&pasg->node);
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 & (1ul << pasginp->inpIndex)))
fprintf(fp," INVALID");
fprintf(fp," value=%f",pasg->pavalue[pasginp->inpIndex]);
fprintf(fp,"\n");
pasginp = (ASGINP *)ellNext(&pasginp->node);
}
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(&pasguag->node);
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(&pasghag->node);
if(pasghag) fprintf(fp,","); else fprintf(fp,")\n");
}
if(pasgrule->calc) {
fprintf(fp,"\t\tCALC(\"%s\")",pasgrule->calc);
fprintf(fp," result=%s",(pasgrule->result==1 ? "TRUE" : "FALSE"));
fprintf(fp,"\n");
}
if(print_end_brace) fprintf(fp,"\t}\n");
pasgrule = (ASGRULE *)ellNext(&pasgrule->node);
}
if(print_end_brace) fprintf(fp,"}\n");
pasg = (ASG *)ellNext(&pasg->node);
}
return(0);
}
int epicsStdCall asDumpMem(const char *asgname,void (*memcallback)(ASMEMBERPVT,FILE *),
int clients)
{
return asDumpMemFP(stdout,asgname,memcallback,clients);
}
int epicsStdCall asDumpMemFP(FILE *fp,const char *asgname,
void (*memcallback)(ASMEMBERPVT,FILE *),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(&pasg->node);
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,fp);
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<=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(&pasgclient->node);
}
pasgmember = (ASGMEMBER *)ellNext(&pasgmember->node);
}
pasg = (ASG *)ellNext(&pasg->node);
}
return(0);
}
LIBCOM_API int epicsStdCall asDumpHash(void)
{
return asDumpHashFP(stdout);
}
LIBCOM_API int epicsStdCall asDumpHashFP(FILE *fp)
{
if(!asActive) return(0);
gphDumpFP(fp,pasbase->phash);
return(0);
}
/*Start of private routines*/
/* asCalloc is "friend" function */
LIBCOM_API void * epicsStdCall asCalloc(size_t nobj,size_t size)
{
void *p;
p=callocMustSucceed(nobj,size,"asCalloc");
return(p);
}
LIBCOM_API char * epicsStdCall asStrdup(unsigned char *str)
{
size_t len = strlen((char *) str);
char *buf = asCalloc(1, len + 1);
strcpy(buf, (char *) str);
return buf;
}
static long asAddMemberPvt(ASMEMBERPVT *pasMemberPvt,const 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(&pgroup->node);
}
/* Put it in DEFAULT*/
pgroup = (ASG *)ellFirst(&pasbase->asgList);
while(pgroup) {
if(strcmp(pgroup->name,DEFAULT)==0) goto got_it;
pgroup = (ASG *)ellNext(&pgroup->node);
}
errMessage(-1,"Logic Error in asAddMember");
return(-1);
got_it:
pasgmember->pasg = pgroup;
ellAdd(&pgroup->memberList,&pasgmember->node);
pasgclient = (ASGCLIENT *)ellFirst(&pasgmember->clientList);
while(pasgclient) {
asComputePvt((ASCLIENTPVT)pasgclient);
pasgclient = (ASGCLIENT *)ellNext(&pasgclient->node);
}
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(&pasg->node);
}
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 = pasgrule->result; /* set for VAL */
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(&pasgrule->node);
}
pasg->inpChanged = FALSE;
pasgmember = (ASGMEMBER *)ellFirst(&pasg->memberList);
while(pasgmember) {
pasgclient = (ASGCLIENT *)ellFirst(&pasgmember->clientList);
while(pasgclient) {
asComputePvt((ASCLIENTPVT)pasgclient);
pasgclient = (ASGCLIENT *)ellNext(&pasgclient->node);
}
pasgmember = (ASGMEMBER *)ellNext(&pasgmember->node);
}
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(&pasguag->node);
}
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(&pasghag->node);
}
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(&pasgrule->node);
}
pasgclient->access = access;
pasgclient->trapMask = trapMask;
if(pasgclient->pcallback && oldaccess!=access) {
(*pasgclient->pcallback)(pasgclient,asClientCOAR);
}
return(0);
}
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(&puagname->node);
ellDelete(&puag->list,&puagname->node);
free(puagname);
puagname = pnext;
}
pnext = ellNext(&puag->node);
ellDelete(&pasbase->uagList,&puag->node);
free(puag);
puag = pnext;
}
phag = (HAG *)ellFirst(&pasbase->hagList);
while(phag) {
phagname = (HAGNAME *)ellFirst(&phag->list);
while(phagname) {
pnext = ellNext(&phagname->node);
ellDelete(&phag->list,&phagname->node);
free(phagname);
phagname = pnext;
}
pnext = ellNext(&phag->node);
ellDelete(&pasbase->hagList,&phag->node);
free(phag);
phag = pnext;
}
pasg = (ASG *)ellFirst(&pasbase->asgList);
while(pasg) {
free(pasg->pavalue);
pasginp = (ASGINP *)ellFirst(&pasg->inpList);
while(pasginp) {
pnext = ellNext(&pasginp->node);
ellDelete(&pasg->inpList,&pasginp->node);
free(pasginp);
pasginp = pnext;
}
pasgrule = (ASGRULE *)ellFirst(&pasg->ruleList);
while(pasgrule) {
free(pasgrule->calc);
free(pasgrule->rpcl);
pasguag = (ASGUAG *)ellFirst(&pasgrule->uagList);
while(pasguag) {
pnext = ellNext(&pasguag->node);
ellDelete(&pasgrule->uagList,&pasguag->node);
free(pasguag);
pasguag = pnext;
}
pasghag = (ASGHAG *)ellFirst(&pasgrule->hagList);
while(pasghag) {
pnext = ellNext(&pasghag->node);
ellDelete(&pasgrule->hagList,&pasghag->node);
free(pasghag);
pasghag = pnext;
}
pnext = ellNext(&pasgrule->node);
ellDelete(&pasg->ruleList,&pasgrule->node);
free(pasgrule);
pasgrule = pnext;
}
pnext = ellNext(&pasg->node);
ellDelete(&pasbase->asgList,&pasg->node);
free(pasg);
pasg = pnext;
}
gphFreeMem(pasbase->phash);
free(pasbase);
}
/*Beginning of routines called by lex code*/
static UAG *asUagAdd(const 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) {
errlogPrintf("Duplicate User Access Group named '%s'\n", uagName);
return(NULL);
}
pnext = (UAG *)ellNext(&pnext->node);
}
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,&puag->node);
} else {
pprev = (UAG *)ellPrevious(&pnext->node);
ellInsert(&pasbase->uagList,&pprev->node,&puag->node);
}
return(puag);
}
static long asUagAddUser(UAG *puag,const 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,&puagname->node);
return(0);
}
static HAG *asHagAdd(const 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) {
errlogPrintf("Duplicate Host Access Group named '%s'\n", hagName);
return(NULL);
}
pnext = (HAG *)ellNext(&pnext->node);
}
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,&phag->node);
} else {
pprev = (HAG *)ellPrevious(&pnext->node);
ellInsert(&pasbase->hagList,&pprev->node,&phag->node);
}
return(phag);
}
static long asHagAddHost(HAG *phag,const char *host)
{
HAGNAME *phagname;
if (!phag) return 0;
if(!asCheckClientIP) {
size_t i, len = strlen(host);
phagname = asCalloc(1, sizeof(*phagname) + len);
for (i = 0; i < len; i++) {
phagname->host[i] = (char)tolower((int)host[i]);
}
} else {
struct sockaddr_in addr;
epicsUInt32 ip;
if(aToIPAddr(host, 0, &addr)) {
static const char unresolved[] = "unresolved:";
errlogPrintf("ACF: Unable to resolve host '%s'\n", host);
phagname = asCalloc(1, sizeof(*phagname) + sizeof(unresolved)-1+strlen(host));
strcpy(phagname->host, unresolved);
strcat(phagname->host, host);
} else {
ip = ntohl(addr.sin_addr.s_addr);
phagname = asCalloc(1, sizeof(*phagname) + 24);
epicsSnprintf(phagname->host, 24,
"%u.%u.%u.%u",
(ip>>24)&0xff,
(ip>>16)&0xff,
(ip>>8)&0xff,
(ip>>0)&0xff);
}
}
ellAdd(&phag->list, &phagname->node);
return 0;
}
static ASG *asAsgAdd(const 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);
}
errlogPrintf("Duplicate Access Security Group named '%s'\n", asgName);
return(NULL);
}
pnext = (ASG *)ellNext(&pnext->node);
}
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,&pasg->node);
} else {
pprev = (ASG *)ellPrevious(&pnext->node);
ellInsert(&pasbase->asgList,&pprev->node,&pasg->node);
}
return(pasg);
}
static long asAsgAddInp(ASG *pasg,const 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,&pasginp->node);
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,&pasgrule->node);
return(pasgrule);
}
static long asAsgAddRuleOptions(ASGRULE *pasgrule,int trapMask)
{
if(!pasgrule) return(0);
pasgrule->trapMask = trapMask;
return(0);
}
static long asAsgRuleUagAdd(ASGRULE *pasgrule, const char *name)
{
ASGUAG *pasguag;
UAG *puag;
ASBASE *pasbase = (ASBASE *)pasbasenew;
if (!pasgrule)
return 0;
puag = (UAG *)ellFirst(&pasbase->uagList);
while (puag) {
if (strcmp(puag->name, name)==0)
break;
puag = (UAG *)ellNext(&puag->node);
}
if (!puag){
errlogPrintf("No User Access Group named '%s' defined\n", name);
return S_asLib_noUag;
}
pasguag = asCalloc(1, sizeof(ASGUAG));
pasguag->puag = puag;
ellAdd(&pasgrule->uagList, &pasguag->node);
return 0;
}
static long asAsgRuleHagAdd(ASGRULE *pasgrule, const char *name)
{
ASGHAG *pasghag;
HAG *phag;
ASBASE *pasbase = (ASBASE *)pasbasenew;
if (!pasgrule)
return 0;
phag = (HAG *)ellFirst(&pasbase->hagList);
while (phag) {
if (strcmp(phag->name, name)==0)
break;
phag = (HAG *)ellNext(&phag->node);
}
if (!phag){
errlogPrintf("No Host Access Group named '%s' defined\n", name);
return S_asLib_noHag;
}
pasghag = asCalloc(1, sizeof(ASGHAG));
pasghag->phag = phag;
ellAdd(&pasgrule->hagList, &pasghag->node);
return 0;
}
static long asAsgRuleCalc(ASGRULE *pasgrule,const char *calc)
{
short err;
long status;
size_t insize;
unsigned long stores;
if (!pasgrule) return 0;
insize = strlen(calc) + 1;
pasgrule->calc = asCalloc(1, insize);
strcpy(pasgrule->calc, calc);
pasgrule->rpcl = asCalloc(1, INFIX_TO_POSTFIX_SIZE(insize));
status = postfix(pasgrule->calc, pasgrule->rpcl, &err);
if(status) {
free(pasgrule->calc);
free(pasgrule->rpcl);
pasgrule->calc = NULL;
pasgrule->rpcl = NULL;
status = S_asLib_badCalc;
errlogPrintf("%s in CALC expression '%s'\n", calcErrorStr(err), calc);
return status;
}
calcArgUsage(pasgrule->rpcl, &pasgrule->inpUsed, &stores);
/* Until someone proves stores are not dangerous, don't allow them */
if (stores) {
free(pasgrule->calc);
free(pasgrule->rpcl);
pasgrule->calc = NULL;
pasgrule->rpcl = NULL;
status = S_asLib_badCalc;
errlogPrintf("Assignment operator used in CALC expression '%s'\n",
calc);
}
return(status);
}