diff options
Diffstat (limited to 'agent/mibgroup/snmpv3/usmUser.c')
-rw-r--r-- | agent/mibgroup/snmpv3/usmUser.c | 1587 |
1 files changed, 1587 insertions, 0 deletions
diff --git a/agent/mibgroup/snmpv3/usmUser.c b/agent/mibgroup/snmpv3/usmUser.c new file mode 100644 index 0000000..c09e44d --- /dev/null +++ b/agent/mibgroup/snmpv3/usmUser.c @@ -0,0 +1,1587 @@ +/* + * usmUser.c + */ + +#include <net-snmp/net-snmp-config.h> +#include <stdlib.h> + +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif + +#if HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +#include "util_funcs.h" +#include "usmUser.h" + +int usmStatusCheck(struct usmUser *uptr); + +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; + +void +init_usmUser(void) +{ + REGISTER_MIB("snmpv3/usmUser", usmUser_variables, variable4, + usmUser_variables_oid); +} + +void +init_register_usmUser_context(const char *contextName) { + register_mib_context("snmpv3/usmUser", + (struct variable *) usmUser_variables, + sizeof(struct variable4), + sizeof(usmUser_variables)/sizeof(struct variable4), + usmUser_variables_oid, + sizeof(usmUser_variables_oid)/sizeof(oid), + DEFAULT_MIB_PRIORITY, 0, 0, NULL, + contextName, -1, 0); +} + +/*******************************************************************-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 < (int) uptr->engineIDLen; i++) + indexOid[prefixLen + 1 + i] = (oid) uptr->engineID[i]; + + indexOid[prefixLen + uptr->engineIDLen + 1] = strlen(uptr->name); + for (i = 0; i < (int) 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 ((int) 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 ((int) 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); + if (*engineID == NULL) { + DEBUGMSGTL(("usmUser", + "parse_oid: malloc of the engineID failed\n")); + return 1; + } + *engineIDLen = engineIDL; + + *name = (unsigned char *) malloc(nameL + 1); + if (*name == NULL) { + DEBUGMSGTL(("usmUser", "parse_oid: malloc of the name failed\n")); + free(*engineID); + return 1; + } + *nameLen = nameL; + + for (i = 0; i < engineIDL; i++) { + if (oidIndex[i + 1] > 255) { + goto UPO_parse_error; + } + engineID[0][i] = (unsigned char) oidIndex[i + 1]; + } + + for (i = 0; i < nameL; i++) { + if (oidIndex[i + 2 + engineIDL] > 255) { + UPO_parse_error: + free(*engineID); + free(*name); + return 1; + } + name[0][i] = (unsigned char) 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 */ + + if (!vp || !name || !length || !var_len) + return NULL; + + *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 < (int) 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; + break; + } + } + } + } /* 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 < (int) 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 != (long) 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) +{ + struct usmUser *uptr, *cloneFrom; + + if (action == RESERVE1) { + 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 > USM_LENGTH_OID_MAX * sizeof(oid) || + var_val_len % sizeof(oid) != 0) { + DEBUGMSGTL(("usmUser", + "write to usmUserCloneFrom: bad length\n")); + return SNMP_ERR_WRONGLENGTH; + } + } else if (action == RESERVE2) { + if ((uptr = usm_parse_user(name, name_len)) == NULL) { + /* + * We don't allow creations here. + */ + return SNMP_ERR_INCONSISTENTNAME; + } + + /* + * Has the user already been cloned? If so, writes to this variable + * are defined to have no effect and to produce no error. + */ + if (uptr->cloneFrom != NULL) { + return SNMP_ERR_NOERROR; + } + + cloneFrom = + usm_parse_user((oid *) var_val, var_val_len / sizeof(oid)); + if (cloneFrom == NULL || cloneFrom->userStatus != SNMP_ROW_ACTIVE) { + return SNMP_ERR_INCONSISTENTNAME; + } + uptr->cloneFrom = snmp_duplicate_objid((oid *) var_val, + var_val_len / sizeof(oid)); + usm_cloneFrom_user(cloneFrom, uptr); + + if (usmStatusCheck(uptr) && uptr->userStatus == SNMP_ROW_NOTREADY) { + uptr->userStatus = SNMP_ROW_NOTINSERVICE; + } + } + + return SNMP_ERR_NOERROR; +} + +/*******************************************************************-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) +{ + static oid *optr; + static size_t olen; + static int resetOnFail; + struct usmUser *uptr; + + if (action == RESERVE1) { + resetOnFail = 0; + 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 > USM_LENGTH_OID_MAX * sizeof(oid) || + var_val_len % sizeof(oid) != 0) { + DEBUGMSGTL(("usmUser", + "write to usmUserAuthProtocol: bad length\n")); + return SNMP_ERR_WRONGLENGTH; + } + } else if (action == RESERVE2) { + if ((uptr = usm_parse_user(name, name_len)) == NULL) { + return SNMP_ERR_INCONSISTENTNAME; + } + + if (uptr->userStatus == RS_ACTIVE + || uptr->userStatus == RS_NOTREADY + || uptr->userStatus == RS_NOTINSERVICE) { + /* + * The authProtocol is already set. It is only legal to CHANGE it + * to usmNoAuthProtocol... + */ + if (snmp_oid_compare + ((oid *) var_val, var_val_len / sizeof(oid), + usmNoAuthProtocol, + sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0) { + /* + * ... and then only if the privProtocol is equal to + * usmNoPrivProtocol. + */ + if (snmp_oid_compare + (uptr->privProtocol, uptr->privProtocolLen, + usmNoPrivProtocol, + sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0) { + return SNMP_ERR_INCONSISTENTVALUE; + } + optr = uptr->authProtocol; + olen = uptr->authProtocolLen; + resetOnFail = 1; + uptr->authProtocol = snmp_duplicate_objid((oid *) var_val, + var_val_len / + sizeof(oid)); + if (uptr->authProtocol == NULL) { + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + uptr->authProtocolLen = var_val_len / sizeof(oid); + } else + if (snmp_oid_compare + ((oid *) var_val, var_val_len / sizeof(oid), + uptr->authProtocol, uptr->authProtocolLen) == 0) { + /* + * But it's also okay to set it to the same thing as it + * currently is. + */ + return SNMP_ERR_NOERROR; + } else { + return SNMP_ERR_INCONSISTENTVALUE; + } + } else { + /* + * This row is under creation. It's okay to set + * usmUserAuthProtocol to any valid authProtocol but it will be + * overwritten when usmUserCloneFrom is set (so don't write it if + * that has already been set). + */ + + if (snmp_oid_compare + ((oid *) var_val, var_val_len / sizeof(oid), + usmNoAuthProtocol, + sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0 +#ifndef NETSNMP_DISABLE_MD5 + || snmp_oid_compare((oid *) var_val, + var_val_len / sizeof(oid), + usmHMACMD5AuthProtocol, + sizeof(usmHMACMD5AuthProtocol) / + sizeof(oid)) == 0 +#endif + || snmp_oid_compare((oid *) var_val, + var_val_len / sizeof(oid), + usmHMACSHA1AuthProtocol, + sizeof(usmHMACSHA1AuthProtocol) / + sizeof(oid)) == 0) { + if (uptr->cloneFrom != NULL) { + optr = uptr->authProtocol; + olen = uptr->authProtocolLen; + resetOnFail = 1; + uptr->authProtocol = + snmp_duplicate_objid((oid *) var_val, + var_val_len / sizeof(oid)); + if (uptr->authProtocol == NULL) { + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + uptr->authProtocolLen = var_val_len / sizeof(oid); + } + } else { + /* + * Unknown authentication protocol. + */ + return SNMP_ERR_WRONGVALUE; + } + } + } else if (action == COMMIT) { + SNMP_FREE(optr); + optr = NULL; + } else if (action == FREE || action == UNDO) { + if ((uptr = usm_parse_user(name, name_len)) != NULL) { + if (resetOnFail) { + SNMP_FREE(uptr->authProtocol); + uptr->authProtocol = optr; + uptr->authProtocolLen = olen; + } + } + } + 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) +{ + struct usmUser *uptr; + unsigned char buf[SNMP_MAXBUF_SMALL]; + size_t buflen = SNMP_MAXBUF_SMALL; + const char fnAuthKey[] = "write_usmUserAuthKeyChange"; + const char fnOwnAuthKey[] = "write_usmUserOwnAuthKeyChange"; + const char *fname; + static unsigned char *oldkey; + static size_t oldkeylen; + static int resetOnFail; + + if (name[USM_MIB_LENGTH - 1] == 6) { + fname = fnAuthKey; + } else { + fname = fnOwnAuthKey; + } + + if (action == RESERVE1) { + resetOnFail = 0; + 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 == 0) { + return SNMP_ERR_WRONGLENGTH; + } + } else if (action == RESERVE2) { + if ((uptr = usm_parse_user(name, name_len)) == NULL) { + return SNMP_ERR_INCONSISTENTNAME; + } else { +#ifndef NETSNMP_DISABLE_MD5 + if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen, + usmHMACMD5AuthProtocol, + sizeof(usmHMACMD5AuthProtocol) / + sizeof(oid)) == 0) { + if (var_val_len != 0 && var_val_len != 32) { + return SNMP_ERR_WRONGLENGTH; + } + } else +#endif + if (snmp_oid_compare + (uptr->authProtocol, uptr->authProtocolLen, + usmHMACSHA1AuthProtocol, + sizeof(usmHMACSHA1AuthProtocol) / sizeof(oid)) == 0) { + if (var_val_len != 0 && var_val_len != 40) { + return SNMP_ERR_WRONGLENGTH; + } + } + } + } else if (action == ACTION) { + if ((uptr = usm_parse_user(name, name_len)) == NULL) { + return SNMP_ERR_INCONSISTENTNAME; + } + if (uptr->cloneFrom == NULL) { + return SNMP_ERR_INCONSISTENTNAME; + } + if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen, + usmNoAuthProtocol, + sizeof(usmNoAuthProtocol) / sizeof(oid)) == + 0) { + /* + * "When the value of the corresponding usmUserAuthProtocol is + * usmNoAuthProtocol, then a set is successful, but effectively + * is a no-op." + */ + DEBUGMSGTL(("usmUser", + "%s: noAuthProtocol keyChange... success!\n", + fname)); + return SNMP_ERR_NOERROR; + } + + /* + * 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)); + resetOnFail = 1; + oldkey = uptr->authKey; + oldkeylen = uptr->authKeyLen; + memdup(&uptr->authKey, buf, buflen); + if (uptr->authKey == NULL) { + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + uptr->authKeyLen = buflen; + } else if (action == COMMIT) { + SNMP_FREE(oldkey); + oldkey = NULL; + } else if (action == UNDO) { + if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) { + SNMP_FREE(uptr->authKey); + uptr->authKey = oldkey; + uptr->authKeyLen = oldkeylen; + } + } + + 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) +{ + static oid *optr; + static size_t olen; + static int resetOnFail; + struct usmUser *uptr; + + if (action == RESERVE1) { + resetOnFail = 0; + 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 > USM_LENGTH_OID_MAX * sizeof(oid) || + var_val_len % sizeof(oid) != 0) { + DEBUGMSGTL(("usmUser", + "write to usmUserPrivProtocol: bad length\n")); + return SNMP_ERR_WRONGLENGTH; + } + } else if (action == RESERVE2) { + if ((uptr = usm_parse_user(name, name_len)) == NULL) { + return SNMP_ERR_INCONSISTENTNAME; + } + + if (uptr->userStatus == RS_ACTIVE + || uptr->userStatus == RS_NOTREADY + || uptr->userStatus == RS_NOTINSERVICE) { + /* + * The privProtocol is already set. It is only legal to CHANGE it + * to usmNoPrivProtocol. + */ + if (snmp_oid_compare + ((oid *) var_val, var_val_len / sizeof(oid), + usmNoPrivProtocol, + sizeof(usmNoPrivProtocol) / sizeof(oid)) == 0) { + resetOnFail = 1; + optr = uptr->privProtocol; + olen = uptr->privProtocolLen; + uptr->privProtocol = snmp_duplicate_objid((oid *) var_val, + var_val_len / + sizeof(oid)); + if (uptr->privProtocol == NULL) { + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + uptr->privProtocolLen = var_val_len / sizeof(oid); + } else + if (snmp_oid_compare + ((oid *) var_val, var_val_len / sizeof(oid), + uptr->privProtocol, uptr->privProtocolLen) == 0) { + /* + * But it's also okay to set it to the same thing as it + * currently is. + */ + return SNMP_ERR_NOERROR; + } else { + return SNMP_ERR_INCONSISTENTVALUE; + } + } else { + /* + * This row is under creation. It's okay to set + * usmUserPrivProtocol to any valid privProtocol with the proviso + * that if usmUserAuthProtocol is set to usmNoAuthProtocol, it may + * only be set to usmNoPrivProtocol. The value will be overwritten + * when usmUserCloneFrom is set (so don't write it if that has + * already been set). + */ + if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen, + usmNoAuthProtocol, + sizeof(usmNoAuthProtocol) / + sizeof(oid)) == 0) { + if (snmp_oid_compare + ((oid *) var_val, var_val_len / sizeof(oid), + usmNoPrivProtocol, + sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0) { + return SNMP_ERR_INCONSISTENTVALUE; + } + } else { + if (snmp_oid_compare + ((oid *) var_val, var_val_len / sizeof(oid), + usmNoPrivProtocol, + sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0 +#ifndef NETSNMP_DISABLE_DES + && snmp_oid_compare + ((oid *) var_val, var_val_len / sizeof(oid), + usmDESPrivProtocol, + sizeof(usmDESPrivProtocol) / sizeof(oid)) != 0 +#endif + && snmp_oid_compare + ((oid *) var_val, var_val_len / sizeof(oid), + usmAESPrivProtocol, + sizeof(usmAESPrivProtocol) / sizeof(oid)) != 0) { + return SNMP_ERR_WRONGVALUE; + } + } + resetOnFail = 1; + optr = uptr->privProtocol; + olen = uptr->privProtocolLen; + uptr->privProtocol = snmp_duplicate_objid((oid *) var_val, + var_val_len / + sizeof(oid)); + if (uptr->privProtocol == NULL) { + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + uptr->privProtocolLen = var_val_len / sizeof(oid); + } + } else if (action == COMMIT) { + SNMP_FREE(optr); + optr = NULL; + } else if (action == FREE || action == UNDO) { + if ((uptr = usm_parse_user(name, name_len)) != NULL) { + if (resetOnFail) { + SNMP_FREE(uptr->privProtocol); + uptr->privProtocol = optr; + uptr->privProtocolLen = olen; + } + } + } + + 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) +{ + struct usmUser *uptr; + unsigned char buf[SNMP_MAXBUF_SMALL]; + size_t buflen = SNMP_MAXBUF_SMALL; + const char fnPrivKey[] = "write_usmUserPrivKeyChange"; + const char fnOwnPrivKey[] = "write_usmUserOwnPrivKeyChange"; + const char *fname; + static unsigned char *oldkey; + static size_t oldkeylen; + static int resetOnFail; + + if (name[USM_MIB_LENGTH - 1] == 9) { + fname = fnPrivKey; + } else { + fname = fnOwnPrivKey; + } + + if (action == RESERVE1) { + resetOnFail = 0; + 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 == 0) { + return SNMP_ERR_WRONGLENGTH; + } + } else if (action == RESERVE2) { + if ((uptr = usm_parse_user(name, name_len)) == NULL) { + return SNMP_ERR_INCONSISTENTNAME; + } else { +#ifndef NETSNMP_DISABLE_DES + if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen, + usmDESPrivProtocol, + sizeof(usmDESPrivProtocol) / + sizeof(oid)) == 0) { + if (var_val_len != 0 && var_val_len != 32) { + return SNMP_ERR_WRONGLENGTH; + } + } +#endif + if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen, + usmAESPrivProtocol, + sizeof(usmAESPrivProtocol) / + sizeof(oid)) == 0) { + if (var_val_len != 0 && var_val_len != 32) { + return SNMP_ERR_WRONGLENGTH; + } + } + } + } else if (action == ACTION) { + if ((uptr = usm_parse_user(name, name_len)) == NULL) { + return SNMP_ERR_INCONSISTENTNAME; + } + if (uptr->cloneFrom == NULL) { + return SNMP_ERR_INCONSISTENTNAME; + } + if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen, + usmNoPrivProtocol, + sizeof(usmNoPrivProtocol) / sizeof(oid)) == + 0) { + /* + * "When the value of the corresponding usmUserPrivProtocol is + * usmNoPrivProtocol, then a set is successful, but effectively + * is a no-op." + */ + DEBUGMSGTL(("usmUser", + "%s: noPrivProtocol keyChange... success!\n", + fname)); + return SNMP_ERR_NOERROR; + } + + /* + * 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)); + resetOnFail = 1; + oldkey = uptr->privKey; + oldkeylen = uptr->privKeyLen; + memdup(&uptr->privKey, buf, buflen); + if (uptr->privKey == NULL) { + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + uptr->privKeyLen = buflen; + } else if (action == COMMIT) { + SNMP_FREE(oldkey); + oldkey = NULL; + } else if (action == UNDO) { + if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) { + SNMP_FREE(uptr->privKey); + uptr->privKey = oldkey; + uptr->privKeyLen = oldkeylen; + } + } + + 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) +{ + struct usmUser *uptr = NULL; + + 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 < 0 || var_val_len > 32) { + 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(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) +{ + long long_ret = *((long *) var_val); + static long oldValue; + struct usmUser *uptr; + static int resetOnFail; + + if (action == RESERVE1) { + resetOnFail = 0; + 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)) { + DEBUGMSGTL(("usmUser", + "write to usmUserStorageType: bad length\n")); + return SNMP_ERR_WRONGLENGTH; + } + if (long_ret < 1 || long_ret > 5) { + return SNMP_ERR_WRONGVALUE; + } + } else if (action == RESERVE2) { + if ((uptr = usm_parse_user(name, name_len)) == NULL) { + return SNMP_ERR_INCONSISTENTNAME; + } + if ((long_ret == ST_VOLATILE || long_ret == ST_NONVOLATILE) && + (uptr->userStorageType == ST_VOLATILE || + uptr->userStorageType == ST_NONVOLATILE)) { + oldValue = uptr->userStorageType; + uptr->userStorageType = long_ret; + resetOnFail = 1; + } else { + /* + * From RFC2574: + * + * "Note that any user who employs authentication or privacy must + * allow its secret(s) to be updated and thus cannot be 'readOnly'. + * + * If an initial set operation tries to set the value to 'readOnly' + * for a user who employs authentication or privacy, then an + * 'inconsistentValue' error must be returned. Note that if the + * value has been previously set (implicit or explicit) to any + * value, then the rules as defined in the StorageType Textual + * Convention apply. + */ + DEBUGMSGTL(("usmUser", + "long_ret %d uptr->st %d uptr->status %d\n", + long_ret, uptr->userStorageType, + uptr->userStatus)); + + if (long_ret == ST_READONLY && + uptr->userStorageType != ST_READONLY && + (uptr->userStatus == RS_ACTIVE || + uptr->userStatus == RS_NOTINSERVICE)) { + return SNMP_ERR_WRONGVALUE; + } else if (long_ret == ST_READONLY && + (snmp_oid_compare + (uptr->privProtocol, uptr->privProtocolLen, + usmNoPrivProtocol, + sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0 + || snmp_oid_compare(uptr->authProtocol, + uptr->authProtocolLen, + usmNoAuthProtocol, + sizeof(usmNoAuthProtocol) / + sizeof(oid)) != 0)) { + return SNMP_ERR_INCONSISTENTVALUE; + } else { + return SNMP_ERR_WRONGVALUE; + } + } + } else if (action == UNDO || action == FREE) { + if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) { + uptr->userStorageType = oldValue; + } + } + return SNMP_ERR_NOERROR; +} /* end write_usmUserStorageType() */ + +/* + * Return 1 if enough objects have been set up to transition rowStatus to + * notInService(2) or active(1). + */ + +int +usmStatusCheck(struct usmUser *uptr) +{ + if (uptr == NULL) { + return 0; + } else { + if (uptr->cloneFrom == NULL) { + return 0; + } + } + return 1; +} + +/*******************************************************************-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 = NULL; + + if (action == RESERVE1) { + 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; + } + long_ret = *((long *) var_val); + if (long_ret == RS_NOTREADY || long_ret < 1 || long_ret > 6) { + return SNMP_ERR_WRONGVALUE; + } + + /* + * 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)) { + DEBUGMSGTL(("usmUser", + "can't parse the OID for engineID or name\n")); + return SNMP_ERR_INCONSISTENTNAME; + } + + if (engineIDLen < 5 || engineIDLen > 32 || nameLen < 1 + || nameLen > 32) { + SNMP_FREE(engineID); + SNMP_FREE(newName); + return SNMP_ERR_NOCREATION; + } + + /* + * Now see if a user already exists with these index values. + */ + uptr = usm_get_user(engineID, engineIDLen, newName); + + if (uptr != NULL) { + if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) { + SNMP_FREE(engineID); + SNMP_FREE(newName); + long_ret = RS_NOTREADY; + return SNMP_ERR_INCONSISTENTVALUE; + } + SNMP_FREE(engineID); + SNMP_FREE(newName); + } else { + if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) { + SNMP_FREE(engineID); + SNMP_FREE(newName); + return SNMP_ERR_INCONSISTENTVALUE; + } + if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) { + if ((uptr = usm_create_user()) == NULL) { + SNMP_FREE(engineID); + SNMP_FREE(newName); + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + uptr->engineID = engineID; + uptr->name = newName; + uptr->secName = strdup(uptr->name); + if (uptr->secName == NULL) { + usm_free_user(uptr); + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + uptr->engineIDLen = engineIDLen; + + /* + * Set status to createAndGo or createAndWait so we can tell + * that this row is under creation. + */ + + uptr->userStatus = long_ret; + + /* + * Add to the list of users (we will take it off again + * later if something goes wrong). + */ + + usm_add_user(uptr); + } else { + SNMP_FREE(engineID); + SNMP_FREE(newName); + } + } + } else if (action == ACTION) { + usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH, + &engineID, &engineIDLen, (u_char **) & newName, + &nameLen); + uptr = usm_get_user(engineID, engineIDLen, newName); + SNMP_FREE(engineID); + SNMP_FREE(newName); + + if (uptr != NULL) { + if (long_ret == RS_CREATEANDGO || long_ret == RS_ACTIVE) { + if (usmStatusCheck(uptr)) { + uptr->userStatus = RS_ACTIVE; + } else { + SNMP_FREE(engineID); + SNMP_FREE(newName); + return SNMP_ERR_INCONSISTENTVALUE; + } + } else if (long_ret == RS_CREATEANDWAIT) { + if (usmStatusCheck(uptr)) { + uptr->userStatus = RS_NOTINSERVICE; + } else { + uptr->userStatus = RS_NOTREADY; + } + } else if (long_ret == RS_NOTINSERVICE) { + if (uptr->userStatus == RS_ACTIVE || + uptr->userStatus == RS_NOTINSERVICE) { + uptr->userStatus = RS_NOTINSERVICE; + } else { + return SNMP_ERR_INCONSISTENTVALUE; + } + } + } + } else if (action == COMMIT) { + usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH, + &engineID, &engineIDLen, (u_char **) & newName, + &nameLen); + uptr = usm_get_user(engineID, engineIDLen, newName); + SNMP_FREE(engineID); + SNMP_FREE(newName); + + if (uptr != NULL) { + if (long_ret == RS_DESTROY) { + usm_remove_user(uptr); + usm_free_user(uptr); + } + } + } else if (action == UNDO || action == FREE) { + if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH, + &engineID, &engineIDLen, (u_char **) & newName, + &nameLen)) { + /* Can't extract engine info from the OID - nothing to undo */ + return SNMP_ERR_NOERROR; + } + uptr = usm_get_user(engineID, engineIDLen, newName); + SNMP_FREE(engineID); + SNMP_FREE(newName); + + if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) { + usm_remove_user(uptr); + usm_free_user(uptr); + } + } + + return SNMP_ERR_NOERROR; +} + +#if 0 + + /* + * 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(engineIDLen); + if (uptr->engineID == NULL) { + free(engineID); + free(newName); + usm_free_user(uptr); + return SNMP_ERR_GENERR; + } + uptr->engineIDLen = engineIDLen; + memcpy(uptr->engineID, engineID, engineIDLen); + free(engineID); + + /* + * copy in the name and secname + */ + 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() */ +#endif |