blob: ba4b75ac051a6b4cafd2c9c31f290f801aced4ec [file] [log] [blame]
#include <config.h>
#include <sys/types.h>
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#include "asn1.h"
#include "snmp.h"
#include "snmp_impl.h"
#include "snmp_vars.h"
#include "acl.h"
#define OIDCMP(l1, l2, o1, o2) (((l1) == (l2)) \
&& !bcmp((char *)(o1), (char *)(o2), \
(l1)*sizeof(oid)))
#define ACLTARGET_MASK 0x01
#define ACLSUBJECT_MASK 0x02
#define ACLRESOURCES_MASK 0x04
#define ACLPRIVILEGES_MASK 0x08
#define ACLSTORAGETYPE_MASK 0x10
#define ACLSTATUS_MASK 0x20
#define ACLCOMPLETE_MASK 0x3F /* all columns */
struct aclEntry *
acl_rowCreate(target, subject, resources)
int target, subject, resources;
{
struct aclEntry *ap;
ap = acl_createEntry(target, subject, resources);
ap->aclBitMask = 0;
ap->reserved->aclStatus = ACLNONEXISTENT;
ap->aclBitMask = ap->reserved->aclBitMask =
ACLTARGET_MASK | ACLSUBJECT_MASK;
/* Watch out for this becoming permanent by accident:
* If during FREE stage below we discover row didn't exist before,
* free row.
*/
return ap;
}
acl_rowDelete(target, subject, resources)
int target, subject, resources;
{
acl_destroyEntry(target, subject, resources);
}
/*
* If statP is non-NULL, the referenced object is at that location.
* If statP is NULL and ap is non-NULL, the instance exists, but not this variable.
* If statP is NULL and ap is NULL, then neither this instance nor the variable exists.
*/
int
write_acl(action, var_val, var_val_type, var_val_len, statP, name, length)
int action;
u_char *var_val;
u_char var_val_type;
int var_val_len;
u_char *statP;
oid *name;
int length;
{
struct aclEntry *ap, *rp;
int var, targetlen, subjectlen;
oid *target, *subject;
long val;
int bigsize = 1000;
/*
* This routine handles requests for variables of the form:
* .iso.org.dod.internet.snmpSecrets.partyAccess.aclTable.aclEntry.X.oidlen.oid.oidlen.oid
* or .1.3.6.1.2.1.21.2.1.1.X.oidlen.oid.oidlen.oid, where the oid suffixes are
* variable length.
* Therefore, the length of the first index is name[11] and the index starts
* at name[12]. The length of the second index starts at name[12 + name[11]],
* and the second index starts at name[13 + name[1]].
*/
if (length < 16)
return SNMP_ERR_NOCREATION;
var = name[10];
targetlen = name[11];
target = name + 12;
if (length <= 12 + targetlen)
return SNMP_ERR_NOCREATION;
subjectlen = name[12 + targetlen];
subject = name + 13 + targetlen;
if (length != 13 + targetlen + subjectlen)
return SNMP_ERR_NOCREATION;
/* XXX are these length checks necessary? If not, take them out of
here and party_vars.c */
ap = acl_getEntry(target, targetlen, subject, subjectlen);
if (ap)
rp = ap->reserved;
if (action == RESERVE1 && !ap){
if ((ap = acl_rowCreate(target, targetlen,
subject, subjectlen)) == NULL)
return SNMP_ERR_RESOURCEUNAVAILABLE;
rp = ap->reserved;
/* create default vals here in reserve area */
rp->aclPriveleges = ACLPRIVELEGESGET | ACLPRIVELEGESGETNEXT;
rp->aclStatus = ACLACTIVE;
rp->aclBitMask = ACLCOMPLETE_MASK;
} else if (action == COMMIT){
if (ap->aclStatus == ACLNONEXISTENT){
/* commit the default vals */
/* This haapens at most once per entry because the status is set to
valid after the first pass. After that, this commit code
does not get executed. It is also important to note that this
gets executed before any of the commits below (and never after
them), so they overlay their data on top of these defaults.
This commit code should allow for the object specific code
to have overlayed data after the code above has executed.
*/
ap->aclPriveleges = rp->aclPriveleges;
ap->aclStatus = rp->aclStatus;
ap->aclBitMask = rp->aclBitMask;
}
} else if (action == FREE){
if (ap && ap->aclStatus == ACLNONEXISTENT){
acl_rowDelete(target, targetlen, subject, subjectlen);
ap = rp = NULL;
}
if (ap) /* satisfy postcondition for bitMask */
rp->aclBitMask = ap->aclBitMask;
}
/* XXX !!! check return values from the asn_parse_* routines */
switch(var){
case ACLPRIVELEGES:
if (action == RESERVE1){
if (var_val_type != ASN_INTEGER)
return SNMP_ERR_WRONGTYPE;
asn_parse_int(var_val, &bigsize, &var_val_type, &val, sizeof(val));
if (val < 0 || val > 31)
return SNMP_ERR_WRONGVALUE;
rp->aclPriveleges = val;
rp->aclBitMask |= ACLPRIVILEGES_MASK;
} else if (action == COMMIT){
ap->aclPriveleges = rp->aclPriveleges;
}
break;
case ACLSTATUS:
if (action == RESERVE1){
if (var_val_type != ASN_INTEGER)
return SNMP_ERR_WRONGTYPE;
asn_parse_int(var_val, &bigsize, &var_val_type, &val, sizeof(val));
if (val < 1 || val > 2)
return SNMP_ERR_WRONGVALUE;
rp->aclStatus = val;
rp->aclBitMask |= ACLSTATUS_MASK;
} else if (action == RESERVE2){
if ((rp->aclStatus == ACLACTIVE)
&& (rp->aclBitMask != ACLCOMPLETE_MASK))
return SNMP_ERR_INCONSISTENTVALUE;
/* tried to set incomplete row valid */
} else if (action == COMMIT){
ap->aclStatus = rp->aclStatus;
} else if (action == ACTION && ap->aclStatus == ACLDESTROY){
acl_rowDelete(ap->aclTarget, ap->aclSubject, ap->aclResources);
}
break;
case ACLTARGET:
case ACLSUBJECT:
default:
return SNMP_ERR_NOCREATION;
}
if (action == COMMIT) /* make any new columns aapear */
ap->aclBitMask = rp->aclBitMask;
return SNMP_ERR_NOERROR;
}
u_char *
var_acl(vp, name, length, exact, var_len, write_method)
register struct variable *vp; /* IN - pointer to variable entry that points here */
register oid *name; /* IN/OUT - input name requested, output name found */
register int *length; /* IN/OUT - length of input and output oid's */
int exact; /* IN - TRUE if an exact match was requested. */
int *var_len; /* OUT - length of variable or 0 if function returned. */
int (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
{
oid newname[MAX_NAME_LEN], lowname[MAX_NAME_LEN], *np;
int newnamelen, lownamelen;
struct aclEntry *ap, *lowap = NULL;
u_long mask;
int target, subject, resources;
/*
* This routine handles requests for variables of the form:
*
* .iso.org.dod.internet.snmpV2.snmpModules.partyMIB.partyMIBObjects
* .snmpAccess.aclTable.aclEntry.X.tgt.sub.res
* or .1.3.6.1.6.3.3.2.3.1.1.X.sub.tgt.res
* Therefore, the target is at name[12], the subject is at name[13], and
* the resources is at name[14].
*/
mask = 1 << (vp->magic - 1);
bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
if (exact){
if (*length != 15 ||
bcmp((char *)name, (char *)vp->name, 12 * sizeof(oid)))
return NULL;
target = name[12];
subject = name[13];
resources = name[14];
*write_method = write_acl;
ap = acl_getEntry(target, subject, resources);
if (ap == NULL)
return NULL;
if (!(ap->aclBitMask & mask))
return NULL;
} else {
/* find "next" control entry */
acl_scanInit();
for(ap = acl_scanNext(); ap; ap = acl_scanNext()){
if (!(ap->aclBitMask & mask))
continue;
np = newname + 12;
*np++ = ap->aclTarget;
*np++ = ap->aclSubject;
*np = ap->aclResources;
newnamelen = 15;
if ((compare(newname, newnamelen, name, *length) > 0) &&
(!lowap || compare(newname, newnamelen,
lowname, lownamelen) < 0)){
/*
* if new one is greater than input and closer to input than
* previous lowest, save this one as the "next" one.
*/
bcopy((char *)newname, (char *)lowname, newnamelen * sizeof(oid));
lownamelen = newnamelen;
lowap = ap;
}
}
if (lowap == NULL)
return NULL;
ap = lowap;
bcopy((char *)lowname, (char *)name, lownamelen * sizeof(oid));
*length = lownamelen;
}
*var_len = sizeof(long);
long_return = 0;
switch (vp->magic){
case ACLPRIVELEGES:
return (u_char *)&ap->aclPriveleges;
case ACLSTORAGETYPE:
return (u_char *)&ap->aclStorageType;
case ACLSTATUS:
return (u_char *)&ap->aclStatus;
default:
ERROR("");
}
return NULL;
}