blob: ac42cc0e7415152d3a7ea16b2e22c3a3f3e5cbc0 [file] [log] [blame]
/*
* usmUser.c
*/
#include <config.h>
#include <stdlib.h>
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#ifdef HAVE_KMT_H
# include <kmt.h>
#endif
#ifdef HAVE_KMT_ALGS_H
# include <kmt_algs.h>
#endif
#include "mibincl.h"
#include "snmpusm.h"
#include "snmpv3.h"
#include "snmp-tc.h"
#include "read_config.h"
#include "agent_read_config.h"
#include "util_funcs.h"
#include "keytools.h"
#include "tools.h"
#include "callback.h"
#include "usmUser.h"
#include "transform_oids.h"
struct variable4 usmUser_variables[] = {
{ USMUSERSPINLOCK , ASN_INTEGER , RWRITE, var_usmUser, 1, { 1 } },
{ USMUSERSECURITYNAME , ASN_OCTET_STR , RONLY , var_usmUser, 3, { 2,1,3 } },
{ USMUSERCLONEFROM , ASN_OBJECT_ID , RWRITE, var_usmUser, 3, { 2,1,4 } },
{ USMUSERAUTHPROTOCOL , ASN_OBJECT_ID , RWRITE, var_usmUser, 3, { 2,1,5 } },
{ USMUSERAUTHKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,6 } },
{ USMUSEROWNAUTHKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,7 } },
{ USMUSERPRIVPROTOCOL , ASN_OBJECT_ID , RWRITE, var_usmUser, 3, { 2,1,8 } },
{ USMUSERPRIVKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,9 } },
{ USMUSEROWNPRIVKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,10 } },
{ USMUSERPUBLIC , ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,11 } },
{ USMUSERSTORAGETYPE , ASN_INTEGER , RWRITE, var_usmUser, 3, { 2,1,12 } },
{ USMUSERSTATUS , ASN_INTEGER , RWRITE, var_usmUser, 3, { 2,1,13 } },
};
oid usmUser_variables_oid[] = {1,3,6,1,6,3,15,1,2};
/* needed for the write_ functions to find the start of the index */
#define USM_MIB_LENGTH 12
static unsigned int usmUserSpinLock=0;
int
store_usmUser(int majorID, int minorID, void *serverarg, void *clientarg)
{
/* save the user base */
usm_save_users("usmUser", "snmpd");
return SNMPERR_SUCCESS;
}
void
init_usmUser(void)
{
snmpd_register_config_handler("usmUser",
usm_parse_config_usmUser, NULL,
"internal use only");
/* we need to be called back later */
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
store_usmUser, NULL);
REGISTER_MIB("snmpv3/usmUser", usmUser_variables, variable4, \
usmUser_variables_oid);
}
/*******************************************************************-o-******
* usm_generate_OID
*
* Parameters:
* *prefix (I) OID prefix to the usmUser table entry.
* prefixLen (I)
* *uptr (I) Pointer to a user in the user list.
* *length (O) Length of generated index OID.
*
* Returns:
* Pointer to the OID index for the user (uptr) -OR-
* NULL on failure.
*
*
* Generate the index OID for a given usmUser name. 'length' is set to
* the length of the index OID.
*
* Index OID format is:
*
* <...prefix>.<engineID_length>.<engineID>.<user_name_length>.<user_name>
*/
oid *
usm_generate_OID(oid *prefix, size_t prefixLen, struct usmUser *uptr,
size_t *length)
{
oid *indexOid;
int i;
*length = 2 + uptr->engineIDLen + strlen(uptr->name) + prefixLen;
indexOid = (oid *) malloc(*length * sizeof(oid));
if (indexOid) {
memmove(indexOid, prefix, prefixLen * sizeof (oid));
indexOid[prefixLen] = uptr->engineIDLen;
for(i = 0; i < uptr->engineIDLen; i++)
indexOid[prefixLen+1+i] = (oid) uptr->engineID[i];
indexOid[prefixLen + uptr->engineIDLen + 1] = strlen(uptr->name);
for(i = 0; i < strlen(uptr->name); i++)
indexOid[prefixLen + uptr->engineIDLen + 2 + i] = (oid) uptr->name[i];
}
return indexOid;
} /* end usm_generate_OID() */
/* usm_parse_oid(): parses an index to the usmTable to break it down into
a engineID component and a name component. The results are stored in:
**engineID: a newly malloced string.
*engineIDLen: The length of the malloced engineID string above.
**name: a newly malloced string.
*nameLen: The length of the malloced name string above.
returns 1 if an error is encountered, or 0 if successful.
*/
int
usm_parse_oid(oid *oidIndex, size_t oidLen,
unsigned char **engineID, size_t *engineIDLen,
unsigned char **name, size_t *nameLen)
{
int nameL;
int engineIDL;
int i;
/* first check the validity of the oid */
if ((oidLen <= 0) || (!oidIndex)) {
DEBUGMSGTL(("usmUser","parse_oid: null oid or zero length oid passed in\n"));
return 1;
}
engineIDL = *oidIndex; /* initial engineID length */
if (oidLen < engineIDL + 2) {
DEBUGMSGTL(("usmUser","parse_oid: invalid oid length: less than the engineIDLen\n"));
return 1;
}
nameL = oidIndex[engineIDL+1]; /* the initial name length */
if (oidLen != engineIDL + nameL + 2) {
DEBUGMSGTL(("usmUser","parse_oid: invalid oid length: length is not exact\n"));
return 1;
}
/* its valid, malloc the space and store the results */
if (engineID == NULL || name == NULL) {
DEBUGMSGTL(("usmUser","parse_oid: null storage pointer passed in.\n"));
return 1;
}
*engineID = (unsigned char *) malloc(engineIDL*sizeof(unsigned char));
if (*engineID == NULL) {
DEBUGMSGTL(("usmUser","parse_oid: malloc of the engineID failed\n"));
return 1;
}
*engineIDLen = engineIDL;
*name = (unsigned char *) malloc((nameL+1)*sizeof(unsigned char));
if (*name == NULL) {
DEBUGMSGTL(("usmUser","parse_oid: malloc of the name failed\n"));
return 1;
}
*nameLen = nameL;
for(i = 0; i < engineIDL; i++)
engineID[0][i] = oidIndex[i+1];
for(i = 0; i < nameL; i++)
name[0][i] = oidIndex[i+2+engineIDL];
name[0][nameL] = 0;
return 0;
} /* end usm_parse_oid() */
/*******************************************************************-o-******
* usm_parse_user
*
* Parameters:
* *name Complete OID indexing a given usmUser entry.
* name_length
*
* Returns:
* Pointer to a usmUser -OR-
* NULL if name does not convert to a usmUser.
*
* Convert an (full) OID and return a pointer to a matching user in the
* user list if one exists.
*/
struct usmUser *
usm_parse_user(oid *name, size_t name_len)
{
struct usmUser *uptr;
char *newName;
u_char *engineID;
size_t nameLen, engineIDLen;
/* get the name and engineID out of the incoming oid */
if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len-USM_MIB_LENGTH,
&engineID, &engineIDLen, (u_char **)&newName, &nameLen))
return NULL;
/* Now see if a user exists with these index values */
uptr = usm_get_user(engineID, engineIDLen, newName);
free(engineID);
free(newName);
return uptr;
} /* end usm_parse_user() */
/*******************************************************************-o-******
* var_usmUser
*
* Parameters:
* *vp (I) Variable-binding associated with this action.
* *name (I/O) Input name requested, output name found.
* *length (I/O) Length of input and output oid's.
* exact (I) TRUE if an exact match was requested.
* *var_len (O) Length of variable or 0 if function returned.
* (**write_method) Hook to name a write method (UNUSED).
*
* Returns:
* Pointer to (char *) containing related data of length 'length'
* (May be NULL.)
*
*
* Call-back function passed to the agent in order to return information
* for the USM MIB tree.
*
*
* If this invocation is not for USMUSERSPINLOCK, lookup user name
* in the usmUser list.
*
* If the name does not match any user and the request
* is for an exact match, -or- if the usmUser list is empty, create a
* new list entry.
*
* Finally, service the given USMUSER* var-bind. A NULL user generally
* results in a NULL return value.
*/
u_char *
var_usmUser(
struct variable *vp,
oid *name,
size_t *length,
int exact,
size_t *var_len,
WriteMethod **write_method)
{
struct usmUser *uptr=NULL, *nptr, *pptr;
int i, rtest, result;
oid *indexOid;
size_t len;
/* variables we may use later */
static long long_ret;
static u_char string[1];
static oid objid[2]; /* for .0.0 */
*write_method = 0; /* assume it isnt writable for the time being */
*var_len = sizeof(long_ret); /* assume an integer and change later if not */
if (vp->magic != USMUSERSPINLOCK) {
oid newname[MAX_OID_LEN];
len = (*length < vp->namelen) ? *length : vp->namelen;
rtest = snmp_oid_compare(name, len, vp->name, len);
if (rtest > 0 ||
/* (rtest == 0 && !exact && (int) vp->namelen+1 < (int) *length) || */
(exact == 1 && rtest != 0)) {
if (var_len)
*var_len = 0;
return 0;
}
memset(newname, 0, sizeof(newname));
if (((int) *length) <= (int) vp->namelen || rtest == -1) {
/* oid is not within our range yet */
/* need to fail if not exact */
uptr = usm_get_userList();
} else {
for(nptr = usm_get_userList(), pptr = NULL, uptr = NULL; nptr != NULL;
pptr = nptr, nptr = nptr->next) {
indexOid = usm_generate_OID(vp->name, vp->namelen, nptr, &len);
result = snmp_oid_compare(name, *length, indexOid, len);
DEBUGMSGTL(("usmUser", "Checking user: %s - ", nptr->name));
for(i = 0; i < nptr->engineIDLen; i++) {
DEBUGMSG(("usmUser", " %x",nptr->engineID[i]));
}
DEBUGMSG(("usmUser"," - %d \n -> OID: ", result));
DEBUGMSGOID(("usmUser", indexOid, len));
DEBUGMSG(("usmUser","\n"));
free(indexOid);
if (exact) {
if (result == 0) {
uptr = nptr;
}
} else {
if (result == 0) {
/* found an exact match. Need the next one for !exact */
uptr = nptr->next;
} else if (result == 1) {
uptr = nptr;
}
}
}
} /* endif -- name <= vp->name */
/* if uptr is NULL and exact we need to continue for creates */
if (uptr == NULL && !exact)
return(NULL);
if (uptr) {
indexOid = usm_generate_OID(vp->name, vp->namelen, uptr, &len);
*length = len;
memmove(name, indexOid, len*sizeof(oid));
DEBUGMSGTL(("usmUser", "Found user: %s - ", uptr->name));
for(i = 0; i < uptr->engineIDLen; i++) {
DEBUGMSG(("usmUser", " %x",uptr->engineID[i]));
}
DEBUGMSG(("usmUser","\n -> OID: "));
DEBUGMSGOID(("usmUser", indexOid, len));
DEBUGMSG(("usmUser","\n"));
free(indexOid);
}
} else {
if (header_generic(vp,name,length,exact,var_len,write_method))
return 0;
} /* endif -- vp->magic != USMUSERSPINLOCK */
switch(vp->magic) {
case USMUSERSPINLOCK:
*write_method = write_usmUserSpinLock;
long_ret = usmUserSpinLock;
return (unsigned char *) &long_ret;
case USMUSERSECURITYNAME:
if (uptr) {
*var_len = strlen(uptr->secName);
return (unsigned char *) uptr->secName;
}
return NULL;
case USMUSERCLONEFROM:
*write_method = write_usmUserCloneFrom;
if (uptr) {
objid[0] = 0; /* "When this object is read, the ZeroDotZero OID */
objid[1] = 0; /* is returned." */
*var_len = sizeof(oid)*2;
return (unsigned char *) objid;
}
return NULL;
case USMUSERAUTHPROTOCOL:
*write_method = write_usmUserAuthProtocol;
if (uptr) {
*var_len = uptr->authProtocolLen*sizeof(oid);
return (u_char *)uptr->authProtocol;
}
return NULL;
case USMUSERAUTHKEYCHANGE:
case USMUSEROWNAUTHKEYCHANGE:
/* we treat these the same, and let the calling module
distinguish between them */
*write_method = write_usmUserAuthKeyChange;
if (uptr) {
*string = 0; /* always return a NULL string */
*var_len = 0;
return string;
}
return NULL;
case USMUSERPRIVPROTOCOL:
*write_method = write_usmUserPrivProtocol;
if (uptr) {
*var_len = uptr->privProtocolLen*sizeof(oid);
return (u_char *)uptr->privProtocol;
}
return NULL;
case USMUSERPRIVKEYCHANGE:
case USMUSEROWNPRIVKEYCHANGE:
/* we treat these the same, and let the calling module
distinguish between them */
*write_method = write_usmUserPrivKeyChange;
if (uptr) {
*string = 0; /* always return a NULL string */
*var_len = 0;
return string;
}
return NULL;
case USMUSERPUBLIC:
*write_method = write_usmUserPublic;
if (uptr) {
if (uptr->userPublicString) {
*var_len = strlen((char *)uptr->userPublicString);
return uptr->userPublicString;
}
*string = 0;
*var_len = 0; /* return an empty string if the public
string hasn't been defined yet */
return string;
}
return NULL;
case USMUSERSTORAGETYPE:
*write_method = write_usmUserStorageType;
if (uptr) {
long_ret = uptr->userStorageType;
return (unsigned char *) &long_ret;
}
return NULL;
case USMUSERSTATUS:
*write_method = write_usmUserStatus;
if (uptr) {
long_ret = uptr->userStatus;
return (unsigned char *) &long_ret;
}
return NULL;
default:
DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_usmUser\n", vp->magic));
}
return 0;
} /* end var_usmUser() */
/* write_usmUserSpinLock(): called when a set is performed on the
usmUserSpinLock object */
int
write_usmUserSpinLock(
int action,
u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
oid *name,
size_t name_len)
{
/* variables we may use later */
static long long_ret;
if (var_val_type != ASN_INTEGER){
DEBUGMSGTL(("usmUser","write to usmUserSpinLock not ASN_INTEGER\n"));
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(long_ret)){
DEBUGMSGTL(("usmUser","write to usmUserSpinLock: bad length\n"));
return SNMP_ERR_WRONGLENGTH;
}
long_ret = *((long *) var_val);
if (long_ret != usmUserSpinLock)
return SNMP_ERR_INCONSISTENTVALUE;
if (action == COMMIT) {
if (usmUserSpinLock == 2147483647)
usmUserSpinLock = 0;
else
usmUserSpinLock++;
}
return SNMP_ERR_NOERROR;
} /* end write_usmUserSpinLock() */
/*******************************************************************-o-******
* write_usmUserCloneFrom
*
* Parameters:
* action
* *var_val
* var_val_type
* var_val_len
* *statP (UNUSED)
* *name OID of user to clone from.
* name_len
*
* Returns:
* SNMP_ERR_NOERROR On success -OR- If user exists
* and has already been cloned.
* SNMP_ERR_GENERR Local function call failures.
* SNMP_ERR_INCONSISTENTNAME 'name' does not exist in user list
* -OR- user to clone from != RS_ACTIVE.
* SNMP_ERR_WRONGLENGTH OID length > than local buffer size.
* SNMP_ERR_WRONGTYPE ASN_OBJECT_ID is wrong.
*
*
* XXX: should handle action=UNDO's.
*/
int
write_usmUserCloneFrom(
int action,
u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
oid *name,
size_t name_len)
{
/* variables we may use later */
static oid objid[USM_LENGTH_OID_MAX], *oidptr;
struct usmUser *uptr, *cloneFrom;
size_t size;
if (var_val_type != ASN_OBJECT_ID){
DEBUGMSGTL(("usmUser","write to usmUserCloneFrom not ASN_OBJECT_ID\n"));
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(objid)){
DEBUGMSGTL(("usmUser","write to usmUserCloneFrom: bad length\n"));
return SNMP_ERR_WRONGLENGTH;
}
if (action == COMMIT){
/* parse the clonefrom objid */
size = var_val_len/sizeof(oid);
memcpy(objid, var_val, var_val_len);
if ((uptr = usm_parse_user(name, name_len)) == NULL)
/* We don't allow creations here */
return SNMP_ERR_INCONSISTENTNAME;
/* have the user already been cloned? If so, second cloning is
not allowed, but does not generate an error */
if (uptr->cloneFrom)
return SNMP_ERR_NOERROR;
/* does the cloneFrom user exist? */
if ((cloneFrom = usm_parse_user(objid, size)) == NULL)
/* We don't allow creations here */
return SNMP_ERR_INCONSISTENTNAME;
/* is it active */
if (cloneFrom->userStatus != RS_ACTIVE)
return SNMP_ERR_INCONSISTENTNAME;
/* set the cloneFrom OID */
if ((oidptr = snmp_duplicate_objid(objid, size/sizeof(oid))) == NULL)
return SNMP_ERR_GENERR;
/* do the actual cloning */
if (uptr->cloneFrom)
free(uptr->cloneFrom);
uptr->cloneFrom = oidptr;
usm_cloneFrom_user(cloneFrom, uptr);
} /* endif: action == COMMIT */
return SNMP_ERR_NOERROR;
} /* end write_usmUserCloneFrom() */
/*******************************************************************-o-******
* write_usmUserAuthProtocol
*
* Parameters:
* action
* *var_val OID of auth transform to set.
* var_val_type
* var_val_len
* *statP
* *name OID of user upon which to perform set operation.
* name_len
*
* Returns:
* SNMP_ERR_NOERROR On success.
* SNMP_ERR_GENERR
* SNMP_ERR_INCONSISTENTVALUE
* SNMP_ERR_NOSUCHNAME
* SNMP_ERR_WRONGLENGTH
* SNMP_ERR_WRONGTYPE
*/
int
write_usmUserAuthProtocol(
int action,
u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
oid *name,
size_t name_len)
{
/* variables we may use later */
static oid objid[USM_LENGTH_OID_MAX];
static oid *optr;
struct usmUser *uptr;
size_t size;
if (var_val_type != ASN_OBJECT_ID){
DEBUGMSGTL(("usmUser","write to usmUserAuthProtocol not ASN_OBJECT_ID\n"));
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(objid)){
DEBUGMSGTL(("usmUser","write to usmUserAuthProtocol: bad length\n"));
return SNMP_ERR_WRONGLENGTH;
}
if (action == COMMIT){
size = var_val_len/sizeof(oid);
memcpy(objid, var_val, var_val_len);
/* don't allow creations here */
if ((uptr = usm_parse_user(name, name_len)) == NULL)
return SNMP_ERR_NOSUCHNAME;
/* check the objid for validity */
/* only allow sets to perform a change to usmNoAuthProtocol */
if (snmp_oid_compare(objid, size, usmNoAuthProtocol,
sizeof(usmNoAuthProtocol)/sizeof(oid)) != 0)
return SNMP_ERR_INCONSISTENTVALUE;
/* if the priv protocol is not usmNoPrivProtocol, we can't change */
if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen, usmNoPrivProtocol,
sizeof(usmNoPrivProtocol)/sizeof(oid)) != 0)
return SNMP_ERR_INCONSISTENTVALUE;
/* finally, we can do it */
optr = uptr->authProtocol;
if ((uptr->authProtocol = snmp_duplicate_objid(objid, size))
== NULL) {
uptr->authProtocol = optr;
return SNMP_ERR_GENERR;
}
free(optr);
uptr->authProtocolLen = size;
}
return SNMP_ERR_NOERROR;
} /* end write_usmUserAuthProtocol() */
/*******************************************************************-o-******
* write_usmUserAuthKeyChange
*
* Parameters:
* action
* *var_val Octet string representing new KeyChange value.
* var_val_type
* var_val_len
* *statP (UNUSED)
* *name OID of user upon which to perform set operation.
* name_len
*
* Returns:
* SNMP_ERR_NOERR Success.
* SNMP_ERR_WRONGTYPE
* SNMP_ERR_WRONGLENGTH
* SNMP_ERR_NOSUCHNAME
* SNMP_ERR_GENERR
*
* Note: This function handles both the usmUserAuthKeyChange and
* usmUserOwnAuthKeyChange objects. We are not passed the name
* of the user requseting the keychange, so we leave this to the
* calling module to verify when and if we should be called. To
* change this would require a change in the mib module API to
* pass in the securityName requesting the change.
*
* XXX: should handle action=UNDO's.
*/
int
write_usmUserAuthKeyChange(
int action,
u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
oid *name,
size_t name_len)
{
static unsigned char string[SNMP_MAXBUF_SMALL];
struct usmUser *uptr;
unsigned char buf[SNMP_MAXBUF_SMALL];
size_t buflen = SNMP_MAXBUF_SMALL;
char fnAuthKey[] = "write_usmUserAuthKeyChange",
fnOwnAuthKey[] = "write_usmUserOwnAuthKeyChange",
*fname;
if (name[USM_MIB_LENGTH-1] == 6)
fname = fnAuthKey;
else
fname = fnOwnAuthKey;
if (var_val_type != ASN_OCTET_STR) {
DEBUGMSGTL(("usmUser","write to %s not ASN_OCTET_STR\n", fname));
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(string)) {
DEBUGMSGTL(("usmUser","write to %s: bad length\n", fname));
return SNMP_ERR_WRONGLENGTH;
}
if (action == COMMIT) {
/* don't allow creations here */
if ((uptr = usm_parse_user(name, name_len)) == NULL) {
return SNMP_ERR_NOSUCHNAME;
}
/* Change the key. */
DEBUGMSGTL(("usmUser","%s: changing auth key for user %s\n", fname, uptr->secName));
if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
uptr->authKey, uptr->authKeyLen,
var_val, var_val_len,
buf, &buflen) != SNMPERR_SUCCESS) {
DEBUGMSGTL(("usmUser","%s: ... failed\n", fname));
return SNMP_ERR_GENERR;
}
DEBUGMSGTL(("usmUser","%s: ... succeeded\n", fname));
SNMP_FREE(uptr->authKey);
memdup(&uptr->authKey, buf, buflen);
uptr->authKeyLen = buflen;
}
return SNMP_ERR_NOERROR;
} /* end write_usmUserAuthKeyChange() */
int
write_usmUserPrivProtocol(
int action,
u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
oid *name,
size_t name_len)
{
/* variables we may use later */
static oid objid[USM_LENGTH_OID_MAX];
static oid *optr;
struct usmUser *uptr;
size_t size;
if (var_val_type != ASN_OBJECT_ID){
DEBUGMSGTL(("usmUser","write to usmUserPrivProtocol not ASN_OBJECT_ID\n"));
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(objid)){
DEBUGMSGTL(("usmUser","write to usmUserPrivProtocol: bad length\n"));
return SNMP_ERR_WRONGLENGTH;
}
if (action == COMMIT){
size = var_val_len/sizeof(oid);
memcpy(objid, var_val, var_val_len);
/* don't allow creations here */
if ((uptr = usm_parse_user(name, name_len)) == NULL)
return SNMP_ERR_NOSUCHNAME;
/* check the objid for validity */
/* only allow sets to perform a change to usmNoPrivProtocol */
if (snmp_oid_compare(objid, size, usmNoPrivProtocol,
sizeof(usmNoPrivProtocol)/sizeof(oid)) != 0)
return SNMP_ERR_INCONSISTENTVALUE;
/* finally, we can do it */
optr = uptr->privProtocol;
if ((uptr->privProtocol = snmp_duplicate_objid(objid, size))
== NULL) {
uptr->privProtocol = optr;
return SNMP_ERR_GENERR;
}
free(optr);
uptr->privProtocolLen = size;
}
return SNMP_ERR_NOERROR;
} /* end write_usmUserPrivProtocol() */
/*
* Note: This function handles both the usmUserPrivKeyChange and
* usmUserOwnPrivKeyChange objects. We are not passed the name
* of the user requseting the keychange, so we leave this to the
* calling module to verify when and if we should be called. To
* change this would require a change in the mib module API to
* pass in the securityName requesting the change.
*
*/
int
write_usmUserPrivKeyChange(
int action,
u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
oid *name,
size_t name_len)
{
static unsigned char string[SNMP_MAXBUF_SMALL];
struct usmUser *uptr;
unsigned char buf[SNMP_MAXBUF_SMALL];
size_t buflen = SNMP_MAXBUF_SMALL;
char fnPrivKey[] = "write_usmUserPrivKeyChange",
fnOwnPrivKey[] = "write_usmUserOwnPrivKeyChange",
*fname;
if (name[USM_MIB_LENGTH-1] == 9)
fname = fnPrivKey;
else
fname = fnOwnPrivKey;
if (var_val_type != ASN_OCTET_STR) {
DEBUGMSGTL(("usmUser","write to %s not ASN_OCTET_STR\n", fname));
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(string)) {
DEBUGMSGTL(("usmUser","write to %s: bad length\n", fname));
return SNMP_ERR_WRONGLENGTH;
}
if (action == COMMIT) {
/* don't allow creations here */
if ((uptr = usm_parse_user(name, name_len)) == NULL) {
return SNMP_ERR_NOSUCHNAME;
}
/* Change the key. */
DEBUGMSGTL(("usmUser","%s: changing priv key for user %s\n", fname, uptr->secName));
if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
uptr->privKey, uptr->privKeyLen,
var_val, var_val_len,
buf, &buflen) != SNMPERR_SUCCESS) {
DEBUGMSGTL(("usmUser","%s: ... failed\n", fname));
return SNMP_ERR_GENERR;
}
DEBUGMSGTL(("usmUser","%s: ... succeeded\n", fname));
SNMP_FREE(uptr->privKey);
memdup(&uptr->privKey, buf, buflen);
uptr->privKeyLen = buflen;
}
return SNMP_ERR_NOERROR;
} /* end write_usmUserPrivKeyChange() */
int
write_usmUserPublic(
int action,
u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
oid *name,
size_t name_len)
{
/* variables we may use later */
static unsigned char string[SNMP_MAXBUF];
struct usmUser *uptr;
if (var_val_type != ASN_OCTET_STR){
DEBUGMSGTL(("usmUser","write to usmUserPublic not ASN_OCTET_STR\n"));
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(string)){
DEBUGMSGTL(("usmUser","write to usmUserPublic: bad length\n"));
return SNMP_ERR_WRONGLENGTH;
}
if (action == COMMIT) {
/* don't allow creations here */
if ((uptr = usm_parse_user(name, name_len)) == NULL) {
return SNMP_ERR_NOSUCHNAME;
}
if (uptr->userPublicString)
free(uptr->userPublicString);
uptr->userPublicString = (u_char *) malloc(sizeof(char)*var_val_len+1);
if (uptr->userPublicString == NULL) {
return SNMP_ERR_GENERR;
}
memcpy(uptr->userPublicString, var_val, var_val_len);
uptr->userPublicString[var_val_len] = 0;
DEBUGMSG(("usmUser", "setting public string: %d - %s\n", var_val_len,
uptr->userPublicString));
}
return SNMP_ERR_NOERROR;
} /* end write_usmUserPublic() */
int
write_usmUserStorageType(
int action,
u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
oid *name,
size_t name_len)
{
/* variables we may use later */
static long long_ret;
struct usmUser *uptr;
if (var_val_type != ASN_INTEGER){
DEBUGMSGTL(("usmUser","write to usmUserStorageType not ASN_INTEGER\n"));
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(long_ret)){
DEBUGMSGTL(("usmUser","write to usmUserStorageType: bad length\n"));
return SNMP_ERR_WRONGLENGTH;
}
if (action == COMMIT){
/* don't allow creations here */
if ((uptr = usm_parse_user(name, name_len)) == NULL) {
return SNMP_ERR_NOSUCHNAME;
}
long_ret = *((long *) var_val);
if ((long_ret == ST_VOLATILE || long_ret == ST_NONVOLATILE) &&
(uptr->userStorageType == ST_VOLATILE ||
uptr->userStorageType == ST_NONVOLATILE))
uptr->userStorageType = long_ret;
else
return SNMP_ERR_INCONSISTENTVALUE;
}
return SNMP_ERR_NOERROR;
} /* end write_usmUserStorageType() */
/*******************************************************************-o-******
* write_usmUserStatus
*
* Parameters:
* action
* *var_val
* var_val_type
* var_val_len
* *statP
* *name
* name_len
*
* Returns:
* SNMP_ERR_NOERROR On success.
* SNMP_ERR_GENERR
* SNMP_ERR_INCONSISTENTNAME
* SNMP_ERR_INCONSISTENTVALUE
* SNMP_ERR_WRONGLENGTH
* SNMP_ERR_WRONGTYPE
*/
int
write_usmUserStatus(
int action,
u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
oid *name,
size_t name_len)
{
/* variables we may use later */
static long long_ret;
unsigned char *engineID;
size_t engineIDLen;
char *newName;
size_t nameLen;
struct usmUser *uptr;
if (var_val_type != ASN_INTEGER){
DEBUGMSGTL(("usmUser","write to usmUserStatus not ASN_INTEGER\n"));
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len > sizeof(long_ret)){
DEBUGMSGTL(("usmUser","write to usmUserStatus: bad length\n"));
return SNMP_ERR_WRONGLENGTH;
}
if (action == COMMIT){
long_ret = *((long *) var_val);
/* ditch illegal values now */
/* notReady can not be used, but the return error code is not mentioned */
if (long_ret == RS_NOTREADY || long_ret < 1 || long_ret > 6)
return SNMP_ERR_INCONSISTENTVALUE;
/* see if we can parse the oid for engineID/name first */
if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len-USM_MIB_LENGTH,
&engineID, &engineIDLen, (u_char **)&newName, &nameLen))
return SNMP_ERR_INCONSISTENTNAME;
/* Now see if a user already exists with these index values */
uptr = usm_get_user(engineID, engineIDLen, newName);
if (uptr) { /* If so, we set the appropriate value... */
free(engineID);
free(newName);
if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
return SNMP_ERR_INCONSISTENTVALUE;
}
if (long_ret == RS_DESTROY) {
usm_remove_user(uptr);
usm_free_user(uptr);
} else {
uptr->userStatus = long_ret;
}
} else { /* ...else we create a new user */
/* check for a valid status column set */
if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) {
free(engineID);
free(newName);
return SNMP_ERR_INCONSISTENTVALUE;
}
if (long_ret == RS_DESTROY) {
/* destroying a non-existent row is actually legal */
free(engineID);
free(newName);
return SNMP_ERR_NOERROR;
}
/* generate a new user */
if ((uptr = usm_create_user()) == NULL) {
free(engineID);
free(newName);
return SNMP_ERR_GENERR;
}
/* copy in the engineID */
uptr->engineID =
(unsigned char *) malloc(sizeof(unsigned char)*engineIDLen);
if (uptr->engineID == NULL) {
free(engineID);
free(newName);
free(uptr);
return SNMP_ERR_GENERR;
}
uptr->engineIDLen = engineIDLen;
memcpy(uptr->engineID, engineID, engineIDLen*sizeof(unsigned char));
free(engineID);
/* copy in the name and secname */
uptr->name = (char *) malloc(strlen(newName));
if ((uptr->name = strdup(newName)) == NULL) {
free(newName);
usm_free_user(uptr);
return SNMP_ERR_GENERR;
}
free(newName);
if ((uptr->secName = strdup(uptr->name)) == NULL) {
usm_free_user(uptr);
return SNMP_ERR_GENERR;
}
/* set the status of the row based on the request */
if (long_ret == RS_CREATEANDGO)
uptr->userStatus = RS_ACTIVE;
else if (long_ret == RS_CREATEANDWAIT)
uptr->userStatus = RS_NOTINSERVICE;
/* finally, add it to our list of users */
usm_add_user(uptr);
} /* endif -- uptr */
} /* endif -- action==COMMIT */
return SNMP_ERR_NOERROR;
} /* end write_usmUserStatus() */