5 #include <net-snmp/net-snmp-config.h>
18 #include <net-snmp/net-snmp-includes.h>
19 #include <net-snmp/agent/net-snmp-agent-includes.h>
21 #include "util_funcs.h"
24 int usmStatusCheck(struct usmUser *uptr);
26 struct variable4 usmUser_variables[] = {
27 {USMUSERSPINLOCK, ASN_INTEGER, RWRITE, var_usmUser, 1, {1}},
28 {USMUSERSECURITYNAME, ASN_OCTET_STR, RONLY, var_usmUser, 3, {2, 1, 3}},
29 {USMUSERCLONEFROM, ASN_OBJECT_ID, RWRITE, var_usmUser, 3, {2, 1, 4}},
30 {USMUSERAUTHPROTOCOL, ASN_OBJECT_ID, RWRITE, var_usmUser, 3,
32 {USMUSERAUTHKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
34 {USMUSEROWNAUTHKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
36 {USMUSERPRIVPROTOCOL, ASN_OBJECT_ID, RWRITE, var_usmUser, 3,
38 {USMUSERPRIVKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
40 {USMUSEROWNPRIVKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
42 {USMUSERPUBLIC, ASN_OCTET_STR, RWRITE, var_usmUser, 3, {2, 1, 11}},
43 {USMUSERSTORAGETYPE, ASN_INTEGER, RWRITE, var_usmUser, 3, {2, 1, 12}},
44 {USMUSERSTATUS, ASN_INTEGER, RWRITE, var_usmUser, 3, {2, 1, 13}},
48 oid usmUser_variables_oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 2 };
52 * needed for the write_ functions to find the start of the index
54 #define USM_MIB_LENGTH 12
56 static unsigned int usmUserSpinLock = 0;
61 snmpd_register_config_handler("usmUser",
62 usm_parse_config_usmUser, NULL, NULL);
63 snmpd_register_config_handler("createUser",
64 usm_parse_create_usmUser, NULL,
65 "username (MD5|SHA) passphrase [DES [passphrase]]");
68 * we need to be called back later
70 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
71 usm_store_users, NULL);
73 REGISTER_MIB("snmpv3/usmUser", usmUser_variables, variable4,
74 usmUser_variables_oid);
77 /*******************************************************************-o-******
81 * *prefix (I) OID prefix to the usmUser table entry.
83 * *uptr (I) Pointer to a user in the user list.
84 * *length (O) Length of generated index OID.
87 * Pointer to the OID index for the user (uptr) -OR-
91 * Generate the index OID for a given usmUser name. 'length' is set to
92 * the length of the index OID.
94 * Index OID format is:
96 * <...prefix>.<engineID_length>.<engineID>.<user_name_length>.<user_name>
99 usm_generate_OID(oid * prefix, size_t prefixLen, struct usmUser *uptr,
105 *length = 2 + uptr->engineIDLen + strlen(uptr->name) + prefixLen;
106 indexOid = (oid *) malloc(*length * sizeof(oid));
108 memmove(indexOid, prefix, prefixLen * sizeof(oid));
110 indexOid[prefixLen] = uptr->engineIDLen;
111 for (i = 0; i < (int) uptr->engineIDLen; i++)
112 indexOid[prefixLen + 1 + i] = (oid) uptr->engineID[i];
114 indexOid[prefixLen + uptr->engineIDLen + 1] = strlen(uptr->name);
115 for (i = 0; i < (int) strlen(uptr->name); i++)
116 indexOid[prefixLen + uptr->engineIDLen + 2 + i] =
121 } /* end usm_generate_OID() */
124 * usm_parse_oid(): parses an index to the usmTable to break it down into
125 * a engineID component and a name component. The results are stored in:
127 * **engineID: a newly malloced string.
128 * *engineIDLen: The length of the malloced engineID string above.
129 * **name: a newly malloced string.
130 * *nameLen: The length of the malloced name string above.
132 * returns 1 if an error is encountered, or 0 if successful.
135 usm_parse_oid(oid * oidIndex, size_t oidLen,
136 unsigned char **engineID, size_t * engineIDLen,
137 unsigned char **name, size_t * nameLen)
144 * first check the validity of the oid
146 if ((oidLen <= 0) || (!oidIndex)) {
147 DEBUGMSGTL(("usmUser",
148 "parse_oid: null oid or zero length oid passed in\n"));
151 engineIDL = *oidIndex; /* initial engineID length */
152 if ((int) oidLen < engineIDL + 2) {
153 DEBUGMSGTL(("usmUser",
154 "parse_oid: invalid oid length: less than the engineIDLen\n"));
157 nameL = oidIndex[engineIDL + 1]; /* the initial name length */
158 if ((int) oidLen != engineIDL + nameL + 2) {
159 DEBUGMSGTL(("usmUser",
160 "parse_oid: invalid oid length: length is not exact\n"));
165 * its valid, malloc the space and store the results
167 if (engineID == NULL || name == NULL) {
168 DEBUGMSGTL(("usmUser",
169 "parse_oid: null storage pointer passed in.\n"));
173 *engineID = (unsigned char *) malloc(engineIDL);
174 if (*engineID == NULL) {
175 DEBUGMSGTL(("usmUser",
176 "parse_oid: malloc of the engineID failed\n"));
179 *engineIDLen = engineIDL;
181 *name = (unsigned char *) malloc(nameL + 1);
183 DEBUGMSGTL(("usmUser", "parse_oid: malloc of the name failed\n"));
189 for (i = 0; i < engineIDL; i++) {
190 if (oidIndex[i + 1] > 255) {
191 goto UPO_parse_error;
193 engineID[0][i] = (unsigned char) oidIndex[i + 1];
196 for (i = 0; i < nameL; i++) {
197 if (oidIndex[i + 2 + engineIDL] > 255) {
203 name[0][i] = (unsigned char) oidIndex[i + 2 + engineIDL];
209 } /* end usm_parse_oid() */
211 /*******************************************************************-o-******
215 * *name Complete OID indexing a given usmUser entry.
219 * Pointer to a usmUser -OR-
220 * NULL if name does not convert to a usmUser.
222 * Convert an (full) OID and return a pointer to a matching user in the
223 * user list if one exists.
226 usm_parse_user(oid * name, size_t name_len)
228 struct usmUser *uptr;
232 size_t nameLen, engineIDLen;
235 * get the name and engineID out of the incoming oid
237 if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
238 &engineID, &engineIDLen, (u_char **) & newName,
243 * Now see if a user exists with these index values
245 uptr = usm_get_user(engineID, engineIDLen, newName);
251 } /* end usm_parse_user() */
253 /*******************************************************************-o-******
257 * *vp (I) Variable-binding associated with this action.
258 * *name (I/O) Input name requested, output name found.
259 * *length (I/O) Length of input and output oid's.
260 * exact (I) TRUE if an exact match was requested.
261 * *var_len (O) Length of variable or 0 if function returned.
262 * (**write_method) Hook to name a write method (UNUSED).
265 * Pointer to (char *) containing related data of length 'length'
269 * Call-back function passed to the agent in order to return information
270 * for the USM MIB tree.
273 * If this invocation is not for USMUSERSPINLOCK, lookup user name
274 * in the usmUser list.
276 * If the name does not match any user and the request
277 * is for an exact match, -or- if the usmUser list is empty, create a
280 * Finally, service the given USMUSER* var-bind. A NULL user generally
281 * results in a NULL return value.
284 var_usmUser(struct variable * vp,
287 int exact, size_t * var_len, WriteMethod ** write_method)
289 struct usmUser *uptr = NULL, *nptr, *pptr;
290 int i, rtest, result;
295 * variables we may use later
297 static long long_ret;
298 static u_char string[1];
299 static oid objid[2]; /* for .0.0 */
301 *write_method = 0; /* assume it isnt writable for the time being */
302 *var_len = sizeof(long_ret); /* assume an integer and change later if not */
304 if (vp->magic != USMUSERSPINLOCK) {
305 oid newname[MAX_OID_LEN];
306 len = (*length < vp->namelen) ? *length : vp->namelen;
307 rtest = snmp_oid_compare(name, len, vp->name, len);
310 * (rtest == 0 && !exact && (int) vp->namelen+1 < (int) *length) ||
312 (exact == 1 && rtest != 0)) {
317 memset(newname, 0, sizeof(newname));
318 if (((int) *length) <= (int) vp->namelen || rtest == -1) {
320 * oid is not within our range yet
323 * need to fail if not exact
325 uptr = usm_get_userList();
328 for (nptr = usm_get_userList(), pptr = NULL, uptr = NULL;
329 nptr != NULL; pptr = nptr, nptr = nptr->next) {
331 usm_generate_OID(vp->name, vp->namelen, nptr, &len);
332 result = snmp_oid_compare(name, *length, indexOid, len);
333 DEBUGMSGTL(("usmUser", "Checking user: %s - ",
335 for (i = 0; i < (int) nptr->engineIDLen; i++) {
336 DEBUGMSG(("usmUser", " %x", nptr->engineID[i]));
338 DEBUGMSG(("usmUser", " - %d \n -> OID: ", result));
339 DEBUGMSGOID(("usmUser", indexOid, len));
340 DEBUGMSG(("usmUser", "\n"));
351 * found an exact match. Need the next one for !exact
354 } else if (result == -1) {
360 } /* endif -- name <= vp->name */
363 * if uptr is NULL and exact we need to continue for creates
365 if (uptr == NULL && !exact)
369 indexOid = usm_generate_OID(vp->name, vp->namelen, uptr, &len);
371 memmove(name, indexOid, len * sizeof(oid));
372 DEBUGMSGTL(("usmUser", "Found user: %s - ", uptr->name));
373 for (i = 0; i < (int) uptr->engineIDLen; i++) {
374 DEBUGMSG(("usmUser", " %x", uptr->engineID[i]));
376 DEBUGMSG(("usmUser", "\n -> OID: "));
377 DEBUGMSGOID(("usmUser", indexOid, len));
378 DEBUGMSG(("usmUser", "\n"));
383 if (header_generic(vp, name, length, exact, var_len, write_method))
385 } /* endif -- vp->magic != USMUSERSPINLOCK */
388 case USMUSERSPINLOCK:
389 *write_method = write_usmUserSpinLock;
390 long_ret = usmUserSpinLock;
391 return (unsigned char *) &long_ret;
393 case USMUSERSECURITYNAME:
395 *var_len = strlen(uptr->secName);
396 return (unsigned char *) uptr->secName;
400 case USMUSERCLONEFROM:
401 *write_method = write_usmUserCloneFrom;
403 objid[0] = 0; /* "When this object is read, the ZeroDotZero OID */
404 objid[1] = 0; /* is returned." */
405 *var_len = sizeof(oid) * 2;
406 return (unsigned char *) objid;
410 case USMUSERAUTHPROTOCOL:
411 *write_method = write_usmUserAuthProtocol;
413 *var_len = uptr->authProtocolLen * sizeof(oid);
414 return (u_char *) uptr->authProtocol;
418 case USMUSERAUTHKEYCHANGE:
419 case USMUSEROWNAUTHKEYCHANGE:
421 * we treat these the same, and let the calling module
422 * distinguish between them
424 *write_method = write_usmUserAuthKeyChange;
426 *string = 0; /* always return a NULL string */
432 case USMUSERPRIVPROTOCOL:
433 *write_method = write_usmUserPrivProtocol;
435 *var_len = uptr->privProtocolLen * sizeof(oid);
436 return (u_char *) uptr->privProtocol;
440 case USMUSERPRIVKEYCHANGE:
441 case USMUSEROWNPRIVKEYCHANGE:
443 * we treat these the same, and let the calling module
444 * distinguish between them
446 *write_method = write_usmUserPrivKeyChange;
448 *string = 0; /* always return a NULL string */
455 *write_method = write_usmUserPublic;
457 if (uptr->userPublicString) {
458 *var_len = strlen((char *) uptr->userPublicString);
459 return uptr->userPublicString;
462 *var_len = 0; /* return an empty string if the public
463 * string hasn't been defined yet */
468 case USMUSERSTORAGETYPE:
469 *write_method = write_usmUserStorageType;
471 long_ret = uptr->userStorageType;
472 return (unsigned char *) &long_ret;
477 *write_method = write_usmUserStatus;
479 long_ret = uptr->userStatus;
480 return (unsigned char *) &long_ret;
485 DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_usmUser\n",
490 } /* end var_usmUser() */
493 * write_usmUserSpinLock(): called when a set is performed on the
494 * usmUserSpinLock object
497 write_usmUserSpinLock(int action,
501 u_char * statP, oid * name, size_t name_len)
504 * variables we may use later
506 static long long_ret;
508 if (var_val_type != ASN_INTEGER) {
509 DEBUGMSGTL(("usmUser",
510 "write to usmUserSpinLock not ASN_INTEGER\n"));
511 return SNMP_ERR_WRONGTYPE;
513 if (var_val_len > sizeof(long_ret)) {
514 DEBUGMSGTL(("usmUser", "write to usmUserSpinLock: bad length\n"));
515 return SNMP_ERR_WRONGLENGTH;
517 long_ret = *((long *) var_val);
518 if (long_ret != (long) usmUserSpinLock)
519 return SNMP_ERR_INCONSISTENTVALUE;
520 if (action == COMMIT) {
521 if (usmUserSpinLock == 2147483647)
526 return SNMP_ERR_NOERROR;
527 } /* end write_usmUserSpinLock() */
529 /*******************************************************************-o-******
530 * write_usmUserCloneFrom
538 * *name OID of user to clone from.
542 * SNMP_ERR_NOERROR On success -OR- If user exists
543 * and has already been cloned.
544 * SNMP_ERR_GENERR Local function call failures.
545 * SNMP_ERR_INCONSISTENTNAME 'name' does not exist in user list
546 * -OR- user to clone from != RS_ACTIVE.
547 * SNMP_ERR_WRONGLENGTH OID length > than local buffer size.
548 * SNMP_ERR_WRONGTYPE ASN_OBJECT_ID is wrong.
551 * XXX: should handle action=UNDO's.
554 write_usmUserCloneFrom(int action,
558 u_char * statP, oid * name, size_t name_len)
560 struct usmUser *uptr, *cloneFrom;
562 if (action == RESERVE1) {
563 if (var_val_type != ASN_OBJECT_ID) {
564 DEBUGMSGTL(("usmUser",
565 "write to usmUserCloneFrom not ASN_OBJECT_ID\n"));
566 return SNMP_ERR_WRONGTYPE;
568 if (var_val_len > USM_LENGTH_OID_MAX * sizeof(oid) ||
569 var_val_len % sizeof(oid) != 0) {
570 DEBUGMSGTL(("usmUser",
571 "write to usmUserCloneFrom: bad length\n"));
572 return SNMP_ERR_WRONGLENGTH;
574 } else if (action == RESERVE2) {
575 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
577 * We don't allow creations here.
579 return SNMP_ERR_INCONSISTENTNAME;
583 * Has the user already been cloned? If so, writes to this variable
584 * are defined to have no effect and to produce no error.
586 if (uptr->cloneFrom != NULL) {
587 return SNMP_ERR_NOERROR;
591 usm_parse_user((oid *) var_val, var_val_len / sizeof(oid));
592 if (cloneFrom == NULL || cloneFrom->userStatus != SNMP_ROW_ACTIVE) {
593 return SNMP_ERR_INCONSISTENTNAME;
595 uptr->cloneFrom = snmp_duplicate_objid((oid *) var_val,
596 var_val_len / sizeof(oid));
597 usm_cloneFrom_user(cloneFrom, uptr);
599 if (usmStatusCheck(uptr) && uptr->userStatus == SNMP_ROW_NOTREADY) {
600 uptr->userStatus = SNMP_ROW_NOTINSERVICE;
604 return SNMP_ERR_NOERROR;
607 /*******************************************************************-o-******
608 * write_usmUserAuthProtocol
612 * *var_val OID of auth transform to set.
616 * *name OID of user upon which to perform set operation.
620 * SNMP_ERR_NOERROR On success.
622 * SNMP_ERR_INCONSISTENTVALUE
623 * SNMP_ERR_NOSUCHNAME
624 * SNMP_ERR_WRONGLENGTH
628 write_usmUserAuthProtocol(int action,
632 u_char * statP, oid * name, size_t name_len)
636 static int resetOnFail;
637 struct usmUser *uptr;
639 if (action == RESERVE1) {
641 if (var_val_type != ASN_OBJECT_ID) {
642 DEBUGMSGTL(("usmUser",
643 "write to usmUserAuthProtocol not ASN_OBJECT_ID\n"));
644 return SNMP_ERR_WRONGTYPE;
646 if (var_val_len > USM_LENGTH_OID_MAX * sizeof(oid) ||
647 var_val_len % sizeof(oid) != 0) {
648 DEBUGMSGTL(("usmUser",
649 "write to usmUserAuthProtocol: bad length\n"));
650 return SNMP_ERR_WRONGLENGTH;
652 } else if (action == RESERVE2) {
653 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
654 return SNMP_ERR_INCONSISTENTNAME;
657 if (uptr->userStatus == RS_ACTIVE
658 || uptr->userStatus == RS_NOTREADY
659 || uptr->userStatus == RS_NOTINSERVICE) {
661 * The authProtocol is already set. It is only legal to CHANGE it
662 * to usmNoAuthProtocol...
665 ((oid *) var_val, var_val_len / sizeof(oid),
667 sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0) {
669 * ... and then only if the privProtocol is equal to
673 (uptr->privProtocol, uptr->privProtocolLen,
675 sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0) {
676 return SNMP_ERR_INCONSISTENTVALUE;
678 optr = uptr->authProtocol;
679 olen = uptr->authProtocolLen;
681 uptr->authProtocol = snmp_duplicate_objid((oid *) var_val,
684 if (uptr->authProtocol == NULL) {
685 return SNMP_ERR_RESOURCEUNAVAILABLE;
687 uptr->authProtocolLen = var_val_len / sizeof(oid);
690 ((oid *) var_val, var_val_len / sizeof(oid),
691 uptr->authProtocol, uptr->authProtocolLen) == 0) {
693 * But it's also okay to set it to the same thing as it
696 return SNMP_ERR_NOERROR;
698 return SNMP_ERR_INCONSISTENTVALUE;
702 * This row is under creation. It's okay to set
703 * usmUserAuthProtocol to any valid authProtocol but it will be
704 * overwritten when usmUserCloneFrom is set (so don't write it if
705 * that has already been set).
709 ((oid *) var_val, var_val_len / sizeof(oid),
711 sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0
712 || snmp_oid_compare((oid *) var_val,
713 var_val_len / sizeof(oid),
714 usmHMACMD5AuthProtocol,
715 sizeof(usmHMACMD5AuthProtocol) /
717 || snmp_oid_compare((oid *) var_val,
718 var_val_len / sizeof(oid),
719 usmHMACSHA1AuthProtocol,
720 sizeof(usmHMACSHA1AuthProtocol) /
722 if (uptr->cloneFrom != NULL) {
723 optr = uptr->authProtocol;
724 olen = uptr->authProtocolLen;
727 snmp_duplicate_objid((oid *) var_val,
728 var_val_len / sizeof(oid));
729 if (uptr->authProtocol == NULL) {
730 return SNMP_ERR_RESOURCEUNAVAILABLE;
732 uptr->authProtocolLen = var_val_len / sizeof(oid);
736 * Unknown authentication protocol.
738 return SNMP_ERR_WRONGVALUE;
741 } else if (action == COMMIT) {
744 } else if (action == FREE || action == UNDO) {
745 if ((uptr = usm_parse_user(name, name_len)) != NULL) {
747 SNMP_FREE(uptr->authProtocol);
748 uptr->authProtocol = optr;
749 uptr->authProtocolLen = olen;
753 return SNMP_ERR_NOERROR;
754 } /* end write_usmUserAuthProtocol() */
756 /*******************************************************************-o-******
757 * write_usmUserAuthKeyChange
761 * *var_val Octet string representing new KeyChange value.
765 * *name OID of user upon which to perform set operation.
769 * SNMP_ERR_NOERR Success.
771 * SNMP_ERR_WRONGLENGTH
772 * SNMP_ERR_NOSUCHNAME
775 * Note: This function handles both the usmUserAuthKeyChange and
776 * usmUserOwnAuthKeyChange objects. We are not passed the name
777 * of the user requseting the keychange, so we leave this to the
778 * calling module to verify when and if we should be called. To
779 * change this would require a change in the mib module API to
780 * pass in the securityName requesting the change.
782 * XXX: should handle action=UNDO's.
785 write_usmUserAuthKeyChange(int action,
789 u_char * statP, oid * name, size_t name_len)
791 struct usmUser *uptr;
792 unsigned char buf[SNMP_MAXBUF_SMALL];
793 size_t buflen = SNMP_MAXBUF_SMALL;
794 const char fnAuthKey[] = "write_usmUserAuthKeyChange";
795 const char fnOwnAuthKey[] = "write_usmUserOwnAuthKeyChange";
797 static unsigned char *oldkey;
798 static size_t oldkeylen;
799 static int resetOnFail;
801 if (name[USM_MIB_LENGTH - 1] == 6) {
804 fname = fnOwnAuthKey;
807 if (action == RESERVE1) {
809 if (var_val_type != ASN_OCTET_STR) {
810 DEBUGMSGTL(("usmUser", "write to %s not ASN_OCTET_STR\n",
812 return SNMP_ERR_WRONGTYPE;
814 if (var_val_len == 0) {
815 return SNMP_ERR_WRONGLENGTH;
817 } else if (action == RESERVE2) {
818 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
819 return SNMP_ERR_INCONSISTENTNAME;
821 if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen,
822 usmHMACMD5AuthProtocol,
823 sizeof(usmHMACMD5AuthProtocol) /
825 if (var_val_len != 0 && var_val_len != 32) {
826 return SNMP_ERR_WRONGLENGTH;
830 (uptr->authProtocol, uptr->authProtocolLen,
831 usmHMACSHA1AuthProtocol,
832 sizeof(usmHMACSHA1AuthProtocol) / sizeof(oid)) == 0) {
833 if (var_val_len != 0 && var_val_len != 40) {
834 return SNMP_ERR_WRONGLENGTH;
838 } else if (action == ACTION) {
839 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
840 return SNMP_ERR_INCONSISTENTNAME;
842 if (uptr->cloneFrom == NULL) {
843 return SNMP_ERR_INCONSISTENTNAME;
845 if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen,
847 sizeof(usmNoAuthProtocol) / sizeof(oid)) ==
850 * "When the value of the corresponding usmUserAuthProtocol is
851 * usmNoAuthProtocol, then a set is successful, but effectively
854 DEBUGMSGTL(("usmUser",
855 "%s: noAuthProtocol keyChange... success!\n",
857 return SNMP_ERR_NOERROR;
863 DEBUGMSGTL(("usmUser", "%s: changing auth key for user %s\n",
864 fname, uptr->secName));
866 if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
867 uptr->authKey, uptr->authKeyLen,
868 var_val, var_val_len,
869 buf, &buflen) != SNMPERR_SUCCESS) {
870 DEBUGMSGTL(("usmUser", "%s: ... failed\n", fname));
871 return SNMP_ERR_GENERR;
873 DEBUGMSGTL(("usmUser", "%s: ... succeeded\n", fname));
875 oldkey = uptr->authKey;
876 oldkeylen = uptr->authKeyLen;
877 memdup(&uptr->authKey, buf, buflen);
878 if (uptr->authKey == NULL) {
879 return SNMP_ERR_RESOURCEUNAVAILABLE;
881 uptr->authKeyLen = buflen;
882 } else if (action == COMMIT) {
885 } else if (action == UNDO) {
886 if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) {
887 SNMP_FREE(uptr->authKey);
888 uptr->authKey = oldkey;
889 uptr->authKeyLen = oldkeylen;
893 return SNMP_ERR_NOERROR;
894 } /* end write_usmUserAuthKeyChange() */
897 write_usmUserPrivProtocol(int action,
901 u_char * statP, oid * name, size_t name_len)
905 static int resetOnFail;
906 struct usmUser *uptr;
908 if (action == RESERVE1) {
910 if (var_val_type != ASN_OBJECT_ID) {
911 DEBUGMSGTL(("usmUser",
912 "write to usmUserPrivProtocol not ASN_OBJECT_ID\n"));
913 return SNMP_ERR_WRONGTYPE;
915 if (var_val_len > USM_LENGTH_OID_MAX * sizeof(oid) ||
916 var_val_len % sizeof(oid) != 0) {
917 DEBUGMSGTL(("usmUser",
918 "write to usmUserPrivProtocol: bad length\n"));
919 return SNMP_ERR_WRONGLENGTH;
921 } else if (action == RESERVE2) {
922 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
923 return SNMP_ERR_INCONSISTENTNAME;
926 if (uptr->userStatus == RS_ACTIVE
927 || uptr->userStatus == RS_NOTREADY
928 || uptr->userStatus == RS_NOTINSERVICE) {
930 * The privProtocol is already set. It is only legal to CHANGE it
931 * to usmNoPrivProtocol.
934 ((oid *) var_val, var_val_len / sizeof(oid),
936 sizeof(usmNoPrivProtocol) / sizeof(oid)) == 0) {
938 optr = uptr->privProtocol;
939 olen = uptr->privProtocolLen;
940 uptr->privProtocol = snmp_duplicate_objid((oid *) var_val,
943 if (uptr->privProtocol == NULL) {
944 return SNMP_ERR_RESOURCEUNAVAILABLE;
946 uptr->privProtocolLen = var_val_len / sizeof(oid);
949 ((oid *) var_val, var_val_len / sizeof(oid),
950 uptr->privProtocol, uptr->privProtocolLen) == 0) {
952 * But it's also okay to set it to the same thing as it
955 return SNMP_ERR_NOERROR;
957 return SNMP_ERR_INCONSISTENTVALUE;
961 * This row is under creation. It's okay to set
962 * usmUserPrivProtocol to any valid privProtocol with the proviso
963 * that if usmUserAuthProtocol is set to usmNoAuthProtocol, it may
964 * only be set to usmNoPrivProtocol. The value will be overwritten
965 * when usmUserCloneFrom is set (so don't write it if that has
968 if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen,
970 sizeof(usmNoAuthProtocol) /
973 ((oid *) var_val, var_val_len / sizeof(oid),
975 sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0) {
976 return SNMP_ERR_INCONSISTENTVALUE;
980 ((oid *) var_val, var_val_len / sizeof(oid),
982 sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0
983 && snmp_oid_compare((oid *) var_val,
984 var_val_len / sizeof(oid),
986 sizeof(usmDESPrivProtocol) /
988 return SNMP_ERR_WRONGVALUE;
992 optr = uptr->privProtocol;
993 olen = uptr->privProtocolLen;
994 uptr->privProtocol = snmp_duplicate_objid((oid *) var_val,
997 if (uptr->privProtocol == NULL) {
998 return SNMP_ERR_RESOURCEUNAVAILABLE;
1000 uptr->privProtocolLen = var_val_len / sizeof(oid);
1002 } else if (action == COMMIT) {
1005 } else if (action == FREE || action == UNDO) {
1006 if ((uptr = usm_parse_user(name, name_len)) != NULL) {
1008 SNMP_FREE(uptr->privProtocol);
1009 uptr->privProtocol = optr;
1010 uptr->privProtocolLen = olen;
1015 return SNMP_ERR_NOERROR;
1016 } /* end write_usmUserPrivProtocol() */
1019 * Note: This function handles both the usmUserPrivKeyChange and
1020 * usmUserOwnPrivKeyChange objects. We are not passed the name
1021 * of the user requseting the keychange, so we leave this to the
1022 * calling module to verify when and if we should be called. To
1023 * change this would require a change in the mib module API to
1024 * pass in the securityName requesting the change.
1028 write_usmUserPrivKeyChange(int action,
1030 u_char var_val_type,
1032 u_char * statP, oid * name, size_t name_len)
1034 struct usmUser *uptr;
1035 unsigned char buf[SNMP_MAXBUF_SMALL];
1036 size_t buflen = SNMP_MAXBUF_SMALL;
1037 const char fnPrivKey[] = "write_usmUserPrivKeyChange";
1038 const char fnOwnPrivKey[] = "write_usmUserOwnPrivKeyChange";
1040 static unsigned char *oldkey;
1041 static size_t oldkeylen;
1042 static int resetOnFail;
1044 if (name[USM_MIB_LENGTH - 1] == 9) {
1047 fname = fnOwnPrivKey;
1050 if (action == RESERVE1) {
1052 if (var_val_type != ASN_OCTET_STR) {
1053 DEBUGMSGTL(("usmUser", "write to %s not ASN_OCTET_STR\n",
1055 return SNMP_ERR_WRONGTYPE;
1057 if (var_val_len == 0) {
1058 return SNMP_ERR_WRONGLENGTH;
1060 } else if (action == RESERVE2) {
1061 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
1062 return SNMP_ERR_INCONSISTENTNAME;
1064 if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen,
1066 sizeof(usmDESPrivProtocol) /
1067 sizeof(oid)) == 0) {
1068 if (var_val_len != 0 && var_val_len != 32) {
1069 return SNMP_ERR_WRONGLENGTH;
1073 } else if (action == ACTION) {
1074 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
1075 return SNMP_ERR_INCONSISTENTNAME;
1077 if (uptr->cloneFrom == NULL) {
1078 return SNMP_ERR_INCONSISTENTNAME;
1080 if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen,
1082 sizeof(usmNoPrivProtocol) / sizeof(oid)) ==
1085 * "When the value of the corresponding usmUserPrivProtocol is
1086 * usmNoPrivProtocol, then a set is successful, but effectively
1089 DEBUGMSGTL(("usmUser",
1090 "%s: noPrivProtocol keyChange... success!\n",
1092 return SNMP_ERR_NOERROR;
1098 DEBUGMSGTL(("usmUser", "%s: changing priv key for user %s\n",
1099 fname, uptr->secName));
1101 if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
1102 uptr->privKey, uptr->privKeyLen,
1103 var_val, var_val_len,
1104 buf, &buflen) != SNMPERR_SUCCESS) {
1105 DEBUGMSGTL(("usmUser", "%s: ... failed\n", fname));
1106 return SNMP_ERR_GENERR;
1108 DEBUGMSGTL(("usmUser", "%s: ... succeeded\n", fname));
1110 oldkey = uptr->privKey;
1111 oldkeylen = uptr->privKeyLen;
1112 memdup(&uptr->privKey, buf, buflen);
1113 if (uptr->privKey == NULL) {
1114 return SNMP_ERR_RESOURCEUNAVAILABLE;
1116 uptr->privKeyLen = buflen;
1117 } else if (action == COMMIT) {
1120 } else if (action == UNDO) {
1121 if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) {
1122 SNMP_FREE(uptr->privKey);
1123 uptr->privKey = oldkey;
1124 uptr->privKeyLen = oldkeylen;
1128 return SNMP_ERR_NOERROR;
1129 } /* end write_usmUserPrivKeyChange() */
1132 write_usmUserPublic(int action,
1134 u_char var_val_type,
1136 u_char * statP, oid * name, size_t name_len)
1138 struct usmUser *uptr = NULL;
1140 if (var_val_type != ASN_OCTET_STR) {
1141 DEBUGMSGTL(("usmUser",
1142 "write to usmUserPublic not ASN_OCTET_STR\n"));
1143 return SNMP_ERR_WRONGTYPE;
1145 if (var_val_len < 0 || var_val_len > 32) {
1146 DEBUGMSGTL(("usmUser", "write to usmUserPublic: bad length\n"));
1147 return SNMP_ERR_WRONGLENGTH;
1149 if (action == COMMIT) {
1151 * don't allow creations here
1153 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
1154 return SNMP_ERR_NOSUCHNAME;
1156 if (uptr->userPublicString)
1157 free(uptr->userPublicString);
1158 uptr->userPublicString = (u_char *) malloc(var_val_len + 1);
1159 if (uptr->userPublicString == NULL) {
1160 return SNMP_ERR_GENERR;
1162 memcpy(uptr->userPublicString, var_val, var_val_len);
1163 uptr->userPublicString[var_val_len] = 0;
1164 DEBUGMSG(("usmUser", "setting public string: %d - %s\n",
1165 var_val_len, uptr->userPublicString));
1167 return SNMP_ERR_NOERROR;
1168 } /* end write_usmUserPublic() */
1171 write_usmUserStorageType(int action,
1173 u_char var_val_type,
1175 u_char * statP, oid * name, size_t name_len)
1177 long long_ret = *((long *) var_val);
1178 static long oldValue;
1179 struct usmUser *uptr;
1180 static int resetOnFail;
1182 if (action == RESERVE1) {
1184 if (var_val_type != ASN_INTEGER) {
1185 DEBUGMSGTL(("usmUser",
1186 "write to usmUserStorageType not ASN_INTEGER\n"));
1187 return SNMP_ERR_WRONGTYPE;
1189 if (var_val_len != sizeof(long)) {
1190 DEBUGMSGTL(("usmUser",
1191 "write to usmUserStorageType: bad length\n"));
1192 return SNMP_ERR_WRONGLENGTH;
1194 if (long_ret < 1 || long_ret > 5) {
1195 return SNMP_ERR_WRONGVALUE;
1197 } else if (action == RESERVE2) {
1198 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
1199 return SNMP_ERR_INCONSISTENTNAME;
1201 if ((long_ret == ST_VOLATILE || long_ret == ST_NONVOLATILE) &&
1202 (uptr->userStorageType == ST_VOLATILE ||
1203 uptr->userStorageType == ST_NONVOLATILE)) {
1204 oldValue = uptr->userStorageType;
1205 uptr->userStorageType = long_ret;
1211 * "Note that any user who employs authentication or privacy must
1212 * allow its secret(s) to be updated and thus cannot be 'readOnly'.
1214 * If an initial set operation tries to set the value to 'readOnly'
1215 * for a user who employs authentication or privacy, then an
1216 * 'inconsistentValue' error must be returned. Note that if the
1217 * value has been previously set (implicit or explicit) to any
1218 * value, then the rules as defined in the StorageType Textual
1221 DEBUGMSGTL(("usmUser",
1222 "long_ret %d uptr->st %d uptr->status %d\n",
1223 long_ret, uptr->userStorageType,
1226 if (long_ret == ST_READONLY &&
1227 uptr->userStorageType != ST_READONLY &&
1228 (uptr->userStatus == RS_ACTIVE ||
1229 uptr->userStatus == RS_NOTINSERVICE)) {
1230 return SNMP_ERR_WRONGVALUE;
1231 } else if (long_ret == ST_READONLY &&
1233 (uptr->privProtocol, uptr->privProtocolLen,
1235 sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0
1236 || snmp_oid_compare(uptr->authProtocol,
1237 uptr->authProtocolLen,
1239 sizeof(usmNoAuthProtocol) /
1240 sizeof(oid)) != 0)) {
1241 return SNMP_ERR_INCONSISTENTVALUE;
1243 return SNMP_ERR_WRONGVALUE;
1246 } else if (action == UNDO || action == FREE) {
1247 if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) {
1248 uptr->userStorageType = oldValue;
1251 return SNMP_ERR_NOERROR;
1252 } /* end write_usmUserStorageType() */
1255 * Return 1 if enough objects have been set up to transition rowStatus to
1256 * notInService(2) or active(1).
1260 usmStatusCheck(struct usmUser *uptr)
1265 if (uptr->cloneFrom == NULL) {
1272 /*******************************************************************-o-******
1273 * write_usmUserStatus
1285 * SNMP_ERR_NOERROR On success.
1287 * SNMP_ERR_INCONSISTENTNAME
1288 * SNMP_ERR_INCONSISTENTVALUE
1289 * SNMP_ERR_WRONGLENGTH
1290 * SNMP_ERR_WRONGTYPE
1293 write_usmUserStatus(int action,
1295 u_char var_val_type,
1297 u_char * statP, oid * name, size_t name_len)
1300 * variables we may use later
1302 static long long_ret;
1303 unsigned char *engineID;
1307 struct usmUser *uptr = NULL;
1309 if (action == RESERVE1) {
1310 if (var_val_type != ASN_INTEGER) {
1311 DEBUGMSGTL(("usmUser",
1312 "write to usmUserStatus not ASN_INTEGER\n"));
1313 return SNMP_ERR_WRONGTYPE;
1315 if (var_val_len != sizeof(long_ret)) {
1316 DEBUGMSGTL(("usmUser",
1317 "write to usmUserStatus: bad length\n"));
1318 return SNMP_ERR_WRONGLENGTH;
1320 long_ret = *((long *) var_val);
1321 if (long_ret == RS_NOTREADY || long_ret < 1 || long_ret > 6) {
1322 return SNMP_ERR_WRONGVALUE;
1326 * See if we can parse the oid for engineID/name first.
1328 if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
1329 &engineID, &engineIDLen, (u_char **) & newName,
1331 return SNMP_ERR_INCONSISTENTNAME;
1334 if (engineIDLen < 5 || engineIDLen > 32 || nameLen < 1
1336 SNMP_FREE(engineID);
1338 return SNMP_ERR_NOCREATION;
1342 * Now see if a user already exists with these index values.
1344 uptr = usm_get_user(engineID, engineIDLen, newName);
1347 if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
1348 SNMP_FREE(engineID);
1350 long_ret = RS_NOTREADY;
1351 return SNMP_ERR_INCONSISTENTVALUE;
1353 SNMP_FREE(engineID);
1356 if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) {
1357 SNMP_FREE(engineID);
1359 return SNMP_ERR_INCONSISTENTVALUE;
1361 if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
1362 if ((uptr = usm_create_user()) == NULL) {
1363 SNMP_FREE(engineID);
1365 return SNMP_ERR_RESOURCEUNAVAILABLE;
1367 uptr->engineID = engineID;
1368 uptr->name = newName;
1369 uptr->secName = strdup(uptr->name);
1370 if (uptr->secName == NULL) {
1371 usm_free_user(uptr);
1372 return SNMP_ERR_RESOURCEUNAVAILABLE;
1374 uptr->engineIDLen = engineIDLen;
1377 * Set status to createAndGo or createAndWait so we can tell
1378 * that this row is under creation.
1381 uptr->userStatus = long_ret;
1384 * Add to the list of users (we will take it off again
1385 * later if something goes wrong).
1390 SNMP_FREE(engineID);
1394 } else if (action == ACTION) {
1395 usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
1396 &engineID, &engineIDLen, (u_char **) & newName,
1398 uptr = usm_get_user(engineID, engineIDLen, newName);
1399 SNMP_FREE(engineID);
1403 if (long_ret == RS_CREATEANDGO || long_ret == RS_ACTIVE) {
1404 if (usmStatusCheck(uptr)) {
1405 uptr->userStatus = RS_ACTIVE;
1407 SNMP_FREE(engineID);
1409 return SNMP_ERR_INCONSISTENTVALUE;
1411 } else if (long_ret == RS_CREATEANDWAIT) {
1412 if (usmStatusCheck(uptr)) {
1413 uptr->userStatus = RS_NOTINSERVICE;
1415 uptr->userStatus = RS_NOTREADY;
1417 } else if (long_ret == RS_NOTINSERVICE) {
1418 if (uptr->userStatus == RS_ACTIVE ||
1419 uptr->userStatus == RS_NOTINSERVICE) {
1420 uptr->userStatus = RS_NOTINSERVICE;
1422 return SNMP_ERR_INCONSISTENTVALUE;
1426 } else if (action == COMMIT) {
1427 usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
1428 &engineID, &engineIDLen, (u_char **) & newName,
1430 uptr = usm_get_user(engineID, engineIDLen, newName);
1431 SNMP_FREE(engineID);
1435 if (long_ret == RS_DESTROY) {
1436 usm_remove_user(uptr);
1437 usm_free_user(uptr);
1440 } else if (action == UNDO || action == FREE) {
1441 usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
1442 &engineID, &engineIDLen, (u_char **) & newName,
1444 uptr = usm_get_user(engineID, engineIDLen, newName);
1445 SNMP_FREE(engineID);
1448 if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
1449 usm_remove_user(uptr);
1450 usm_free_user(uptr);
1454 return SNMP_ERR_NOERROR;
1460 * see if we can parse the oid for engineID/name first
1462 if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
1463 &engineID, &engineIDLen, (u_char **) & newName,
1465 return SNMP_ERR_INCONSISTENTNAME;
1468 * Now see if a user already exists with these index values
1470 uptr = usm_get_user(engineID, engineIDLen, newName);
1473 if (uptr) { /* If so, we set the appropriate value... */
1476 if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
1477 return SNMP_ERR_INCONSISTENTVALUE;
1479 if (long_ret == RS_DESTROY) {
1480 usm_remove_user(uptr);
1481 usm_free_user(uptr);
1483 uptr->userStatus = long_ret;
1486 } else { /* ...else we create a new user */
1488 * check for a valid status column set
1490 if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) {
1493 return SNMP_ERR_INCONSISTENTVALUE;
1495 if (long_ret == RS_DESTROY) {
1497 * destroying a non-existent row is actually legal
1501 return SNMP_ERR_NOERROR;
1505 * generate a new user
1507 if ((uptr = usm_create_user()) == NULL) {
1510 return SNMP_ERR_GENERR;
1514 * copy in the engineID
1516 uptr->engineID = (unsigned char *) malloc(engineIDLen);
1517 if (uptr->engineID == NULL) {
1520 usm_free_user(uptr);
1521 return SNMP_ERR_GENERR;
1523 uptr->engineIDLen = engineIDLen;
1524 memcpy(uptr->engineID, engineID, engineIDLen);
1528 * copy in the name and secname
1530 if ((uptr->name = strdup(newName)) == NULL) {
1532 usm_free_user(uptr);
1533 return SNMP_ERR_GENERR;
1536 if ((uptr->secName = strdup(uptr->name)) == NULL) {
1537 usm_free_user(uptr);
1538 return SNMP_ERR_GENERR;
1542 * set the status of the row based on the request
1544 if (long_ret == RS_CREATEANDGO)
1545 uptr->userStatus = RS_ACTIVE;
1546 else if (long_ret == RS_CREATEANDWAIT)
1547 uptr->userStatus = RS_NOTINSERVICE;
1550 * finally, add it to our list of users
1554 } /* endif -- uptr */
1555 } /* endif -- action==COMMIT */
1557 return SNMP_ERR_NOERROR;
1559 } /* end write_usmUserStatus() */