| /* |
| * 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; |
| 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(), uptr = NULL; |
| nptr != NULL; 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; |
| uptr->authKey = netsnmp_memdup(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; |
| uptr->privKey = netsnmp_memdup(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 |