1 //==========================================================================
3 // ./agent/current/src/mibgroup/snmpv3/usmUser.c
6 //==========================================================================
7 //####ECOSGPLCOPYRIGHTBEGIN####
8 // -------------------------------------------
9 // This file is part of eCos, the Embedded Configurable Operating System.
10 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
35 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36 // at http://sources.redhat.com/ecos/ecos-license/
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //####UCDSNMPCOPYRIGHTBEGIN####
41 // -------------------------------------------
43 // Portions of this software may have been derived from the UCD-SNMP
44 // project, <http://ucd-snmp.ucdavis.edu/> from the University of
45 // California at Davis, which was originally based on the Carnegie Mellon
46 // University SNMP implementation. Portions of this software are therefore
47 // covered by the appropriate copyright disclaimers included herein.
49 // The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2"
50 // -------------------------------------------
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
56 // Author(s): Andrew.Lunn@ascom.ch, Manu.Sharma@ascom.com
59 // Purpose: Port of UCD-SNMP distribution to eCos.
63 //####DESCRIPTIONEND####
65 //==========================================================================
66 /********************************************************************
67 Copyright 1989, 1991, 1992 by Carnegie Mellon University
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
74 Permission to use, copy, modify and distribute this software and its
75 documentation for any purpose and without fee is hereby granted,
76 provided that the above copyright notice appears in all copies and
77 that both that copyright notice and this permission notice appear in
78 supporting documentation, and that the name of CMU and The Regents of
79 the University of California not be used in advertising or publicity
80 pertaining to distribution of the software without specific written
83 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85 WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU OR
86 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91 *********************************************************************/
98 #ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
115 #include "read_config.h"
116 #include "agent_read_config.h"
117 //#include "util_funcs.h"
118 #include "keytools.h"
123 #include "transform_oids.h"
125 struct variable4 usmUser_variables[] = {
126 { USMUSERSPINLOCK , ASN_INTEGER , RWRITE, var_usmUser, 1, { 1 } },
127 { USMUSERSECURITYNAME , ASN_OCTET_STR , RONLY , var_usmUser, 3, { 2,1,3 } },
128 { USMUSERCLONEFROM , ASN_OBJECT_ID , RWRITE, var_usmUser, 3, { 2,1,4 } },
129 { USMUSERAUTHPROTOCOL , ASN_OBJECT_ID , RWRITE, var_usmUser, 3, { 2,1,5 } },
130 { USMUSERAUTHKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,6 } },
131 { USMUSEROWNAUTHKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,7 } },
132 { USMUSERPRIVPROTOCOL , ASN_OBJECT_ID , RWRITE, var_usmUser, 3, { 2,1,8 } },
133 { USMUSERPRIVKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,9 } },
134 { USMUSEROWNPRIVKEYCHANGE, ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,10 } },
135 { USMUSERPUBLIC , ASN_OCTET_STR , RWRITE, var_usmUser, 3, { 2,1,11 } },
136 { USMUSERSTORAGETYPE , ASN_INTEGER , RWRITE, var_usmUser, 3, { 2,1,12 } },
137 { USMUSERSTATUS , ASN_INTEGER , RWRITE, var_usmUser, 3, { 2,1,13 } },
141 oid usmUser_variables_oid[] = {1,3,6,1,6,3,15,1,2};
144 /* needed for the write_ functions to find the start of the index */
145 #define USM_MIB_LENGTH 12
147 static unsigned int usmUserSpinLock=0;
152 snmpd_register_config_handler("usmUser",
153 usm_parse_config_usmUser, NULL, NULL);
154 snmpd_register_config_handler("createUser",
155 usm_parse_create_usmUser, NULL,
156 "username (MD5|SHA) passphrase [DES] [passphrase]");
158 /* we need to be called back later */
159 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
160 usm_store_users, NULL);
162 REGISTER_MIB("snmpv3/usmUser", usmUser_variables, variable4,
163 usmUser_variables_oid);
167 /*******************************************************************-o-******
171 * *prefix (I) OID prefix to the usmUser table entry.
173 * *uptr (I) Pointer to a user in the user list.
174 * *length (O) Length of generated index OID.
177 * Pointer to the OID index for the user (uptr) -OR-
181 * Generate the index OID for a given usmUser name. 'length' is set to
182 * the length of the index OID.
184 * Index OID format is:
186 * <...prefix>.<engineID_length>.<engineID>.<user_name_length>.<user_name>
189 usm_generate_OID(oid *prefix, size_t prefixLen, struct usmUser *uptr,
195 *length = 2 + uptr->engineIDLen + strlen(uptr->name) + prefixLen;
196 indexOid = (oid *) malloc(*length * sizeof(oid));
198 memmove(indexOid, prefix, prefixLen * sizeof (oid));
200 indexOid[prefixLen] = uptr->engineIDLen;
201 for(i = 0; i < (int)uptr->engineIDLen; i++)
202 indexOid[prefixLen+1+i] = (oid) uptr->engineID[i];
204 indexOid[prefixLen + uptr->engineIDLen + 1] = strlen(uptr->name);
205 for(i = 0; i < (int)strlen(uptr->name); i++)
206 indexOid[prefixLen + uptr->engineIDLen + 2 + i] = (oid) uptr->name[i];
210 } /* end usm_generate_OID() */
212 /* usm_parse_oid(): parses an index to the usmTable to break it down into
213 a engineID component and a name component. The results are stored in:
215 **engineID: a newly malloced string.
216 *engineIDLen: The length of the malloced engineID string above.
217 **name: a newly malloced string.
218 *nameLen: The length of the malloced name string above.
220 returns 1 if an error is encountered, or 0 if successful.
223 usm_parse_oid(oid *oidIndex, size_t oidLen,
224 unsigned char **engineID, size_t *engineIDLen,
225 unsigned char **name, size_t *nameLen)
231 /* first check the validity of the oid */
232 if ((oidLen <= 0) || (!oidIndex)) {
233 DEBUGMSGTL(("usmUser","parse_oid: null oid or zero length oid passed in\n"));
236 engineIDL = *oidIndex; /* initial engineID length */
237 if ((int)oidLen < engineIDL + 2) {
238 DEBUGMSGTL(("usmUser","parse_oid: invalid oid length: less than the engineIDLen\n"));
241 nameL = oidIndex[engineIDL+1]; /* the initial name length */
242 if ((int)oidLen != engineIDL + nameL + 2) {
243 DEBUGMSGTL(("usmUser","parse_oid: invalid oid length: length is not exact\n"));
247 /* its valid, malloc the space and store the results */
248 if (engineID == NULL || name == NULL) {
249 DEBUGMSGTL(("usmUser","parse_oid: null storage pointer passed in.\n"));
253 *engineID = (unsigned char *) malloc(engineIDL);
254 if (*engineID == NULL) {
255 DEBUGMSGTL(("usmUser","parse_oid: malloc of the engineID failed\n"));
258 *engineIDLen = engineIDL;
260 *name = (unsigned char *) malloc(nameL+1);
262 DEBUGMSGTL(("usmUser","parse_oid: malloc of the name failed\n"));
268 for(i = 0; i < engineIDL; i++) {
269 if (oidIndex[i+1] > 255) {
270 goto UPO_parse_error;
272 engineID[0][i] = (unsigned char) oidIndex[i+1];
275 for(i = 0; i < nameL; i++) {
276 if (oidIndex[i+2+engineIDL] > 255) {
282 name[0][i] = (unsigned char) oidIndex[i+2+engineIDL];
288 } /* end usm_parse_oid() */
290 /*******************************************************************-o-******
294 * *name Complete OID indexing a given usmUser entry.
298 * Pointer to a usmUser -OR-
299 * NULL if name does not convert to a usmUser.
301 * Convert an (full) OID and return a pointer to a matching user in the
302 * user list if one exists.
305 usm_parse_user(oid *name, size_t name_len)
307 struct usmUser *uptr;
311 size_t nameLen, engineIDLen;
313 /* get the name and engineID out of the incoming oid */
314 if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len-USM_MIB_LENGTH,
315 &engineID, &engineIDLen, (u_char **)&newName, &nameLen))
318 /* Now see if a user exists with these index values */
319 uptr = usm_get_user(engineID, engineIDLen, newName);
325 } /* end usm_parse_user() */
327 /*******************************************************************-o-******
331 * *vp (I) Variable-binding associated with this action.
332 * *name (I/O) Input name requested, output name found.
333 * *length (I/O) Length of input and output oid's.
334 * exact (I) TRUE if an exact match was requested.
335 * *var_len (O) Length of variable or 0 if function returned.
336 * (**write_method) Hook to name a write method (UNUSED).
339 * Pointer to (char *) containing related data of length 'length'
343 * Call-back function passed to the agent in order to return information
344 * for the USM MIB tree.
347 * If this invocation is not for USMUSERSPINLOCK, lookup user name
348 * in the usmUser list.
350 * If the name does not match any user and the request
351 * is for an exact match, -or- if the usmUser list is empty, create a
354 * Finally, service the given USMUSER* var-bind. A NULL user generally
355 * results in a NULL return value.
364 WriteMethod **write_method)
366 struct usmUser *uptr=NULL, *nptr, *pptr;
367 int i, rtest, result;
371 /* variables we may use later */
372 static long long_ret;
373 static u_char string[1];
374 static oid objid[2]; /* for .0.0 */
376 *write_method = 0; /* assume it isnt writable for the time being */
377 *var_len = sizeof(long_ret); /* assume an integer and change later if not */
379 if (vp->magic != USMUSERSPINLOCK) {
380 oid newname[MAX_OID_LEN];
381 len = (*length < vp->namelen) ? *length : vp->namelen;
382 rtest = snmp_oid_compare(name, len, vp->name, len);
384 /* (rtest == 0 && !exact && (int) vp->namelen+1 < (int) *length) || */
385 (exact == 1 && rtest != 0)) {
390 memset(newname, 0, sizeof(newname));
391 if (((int) *length) <= (int) vp->namelen || rtest == -1) {
392 /* oid is not within our range yet */
393 /* need to fail if not exact */
394 uptr = usm_get_userList();
397 for(nptr = usm_get_userList(), pptr = NULL, uptr = NULL; nptr != NULL;
398 pptr = nptr, nptr = nptr->next) {
399 indexOid = usm_generate_OID(vp->name, vp->namelen, nptr, &len);
400 result = snmp_oid_compare(name, *length, indexOid, len);
401 DEBUGMSGTL(("usmUser", "Checking user: %s - ", nptr->name));
402 for(i = 0; i < (int)nptr->engineIDLen; i++) {
403 DEBUGMSG(("usmUser", " %x",nptr->engineID[i]));
405 DEBUGMSG(("usmUser"," - %d \n -> OID: ", result));
406 DEBUGMSGOID(("usmUser", indexOid, len));
407 DEBUGMSG(("usmUser","\n"));
417 /* found an exact match. Need the next one for !exact */
419 } else if (result == 1) {
424 } /* endif -- name <= vp->name */
426 /* if uptr is NULL and exact we need to continue for creates */
427 if (uptr == NULL && !exact)
431 indexOid = usm_generate_OID(vp->name, vp->namelen, uptr, &len);
433 memmove(name, indexOid, len*sizeof(oid));
434 DEBUGMSGTL(("usmUser", "Found user: %s - ", uptr->name));
435 for(i = 0; i < (int)uptr->engineIDLen; i++) {
436 DEBUGMSG(("usmUser", " %x",uptr->engineID[i]));
438 DEBUGMSG(("usmUser","\n -> OID: "));
439 DEBUGMSGOID(("usmUser", indexOid, len));
440 DEBUGMSG(("usmUser","\n"));
445 if (header_generic(vp,name,length,exact,var_len,write_method))
447 } /* endif -- vp->magic != USMUSERSPINLOCK */
450 case USMUSERSPINLOCK:
451 *write_method = write_usmUserSpinLock;
452 long_ret = usmUserSpinLock;
453 return (unsigned char *) &long_ret;
455 case USMUSERSECURITYNAME:
457 *var_len = strlen(uptr->secName);
458 return (unsigned char *) uptr->secName;
462 case USMUSERCLONEFROM:
463 *write_method = write_usmUserCloneFrom;
465 objid[0] = 0; /* "When this object is read, the ZeroDotZero OID */
466 objid[1] = 0; /* is returned." */
467 *var_len = sizeof(oid)*2;
468 return (unsigned char *) objid;
472 case USMUSERAUTHPROTOCOL:
473 *write_method = write_usmUserAuthProtocol;
475 *var_len = uptr->authProtocolLen*sizeof(oid);
476 return (u_char *)uptr->authProtocol;
480 case USMUSERAUTHKEYCHANGE:
481 case USMUSEROWNAUTHKEYCHANGE:
483 /* we treat these the same, and let the calling module
484 distinguish between them */
485 *write_method = write_usmUserAuthKeyChange;
487 *string = 0; /* always return a NULL string */
493 case USMUSERPRIVPROTOCOL:
494 *write_method = write_usmUserPrivProtocol;
496 *var_len = uptr->privProtocolLen*sizeof(oid);
497 return (u_char *)uptr->privProtocol;
501 case USMUSERPRIVKEYCHANGE:
502 case USMUSEROWNPRIVKEYCHANGE:
503 /* we treat these the same, and let the calling module
504 distinguish between them */
505 *write_method = write_usmUserPrivKeyChange;
507 *string = 0; /* always return a NULL string */
514 *write_method = write_usmUserPublic;
516 if (uptr->userPublicString) {
517 *var_len = strlen((char *)uptr->userPublicString);
518 return uptr->userPublicString;
521 *var_len = 0; /* return an empty string if the public
522 string hasn't been defined yet */
527 case USMUSERSTORAGETYPE:
528 *write_method = write_usmUserStorageType;
530 long_ret = uptr->userStorageType;
531 return (unsigned char *) &long_ret;
536 *write_method = write_usmUserStatus;
538 long_ret = uptr->userStatus;
539 return (unsigned char *) &long_ret;
544 DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_usmUser\n", vp->magic));
548 } /* end var_usmUser() */
550 /* write_usmUserSpinLock(): called when a set is performed on the
551 usmUserSpinLock object */
553 write_usmUserSpinLock(
562 /* variables we may use later */
563 static long long_ret;
565 if (var_val_type != ASN_INTEGER){
566 DEBUGMSGTL(("usmUser","write to usmUserSpinLock not ASN_INTEGER\n"));
567 return SNMP_ERR_WRONGTYPE;
569 if (var_val_len > sizeof(long_ret)){
570 DEBUGMSGTL(("usmUser","write to usmUserSpinLock: bad length\n"));
571 return SNMP_ERR_WRONGLENGTH;
573 long_ret = *((long *) var_val);
575 if (long_ret != (long)usmUserSpinLock)
576 return SNMP_ERR_INCONSISTENTVALUE;
578 if (action == COMMIT) {
579 if (usmUserSpinLock == 2147483647) {
585 return SNMP_ERR_NOERROR;
586 } /* end write_usmUserSpinLock() */
588 /*******************************************************************-o-******
589 * write_usmUserCloneFrom
597 * *name OID of user to clone from.
601 * SNMP_ERR_NOERROR On success -OR- If user exists
602 * and has already been cloned.
603 * SNMP_ERR_GENERR Local function call failures.
604 * SNMP_ERR_INCONSISTENTNAME 'name' does not exist in user list
605 * -OR- user to clone from != RS_ACTIVE.
606 * SNMP_ERR_WRONGLENGTH OID length > than local buffer size.
607 * SNMP_ERR_WRONGTYPE ASN_OBJECT_ID is wrong.
610 * XXX: should handle action=UNDO's.
613 write_usmUserCloneFrom(
622 /* variables we may use later */
623 static oid objid[USM_LENGTH_OID_MAX], *oidptr;
624 struct usmUser *uptr, *cloneFrom;
627 if (var_val_type != ASN_OBJECT_ID){
628 DEBUGMSGTL(("usmUser","write to usmUserCloneFrom not ASN_OBJECT_ID\n"));
629 return SNMP_ERR_WRONGTYPE;
631 if (var_val_len > sizeof(objid)){
632 DEBUGMSGTL(("usmUser","write to usmUserCloneFrom: bad length\n"));
633 return SNMP_ERR_WRONGLENGTH;
635 if (action == COMMIT){
636 /* parse the clonefrom objid */
637 size = var_val_len/sizeof(oid);
638 memcpy(objid, var_val, var_val_len);
640 if ((uptr = usm_parse_user(name, name_len)) == NULL)
641 /* We don't allow creations here */
642 return SNMP_ERR_INCONSISTENTNAME;
644 /* have the user already been cloned? If so, second cloning is
645 not allowed, but does not generate an error */
647 return SNMP_ERR_NOERROR;
649 /* does the cloneFrom user exist? */
650 if ((cloneFrom = usm_parse_user(objid, size)) == NULL)
651 /* We don't allow creations here */
652 return SNMP_ERR_INCONSISTENTNAME;
655 if (cloneFrom->userStatus != RS_ACTIVE)
656 return SNMP_ERR_INCONSISTENTNAME;
658 /* set the cloneFrom OID */
659 if ((oidptr = snmp_duplicate_objid(objid, size/sizeof(oid))) == NULL)
660 return SNMP_ERR_GENERR;
662 /* do the actual cloning */
665 free(uptr->cloneFrom);
666 uptr->cloneFrom = oidptr;
668 usm_cloneFrom_user(cloneFrom, uptr);
670 } /* endif: action == COMMIT */
672 return SNMP_ERR_NOERROR;
675 } /* end write_usmUserCloneFrom() */
677 /*******************************************************************-o-******
678 * write_usmUserAuthProtocol
682 * *var_val OID of auth transform to set.
686 * *name OID of user upon which to perform set operation.
690 * SNMP_ERR_NOERROR On success.
692 * SNMP_ERR_INCONSISTENTVALUE
693 * SNMP_ERR_NOSUCHNAME
694 * SNMP_ERR_WRONGLENGTH
698 write_usmUserAuthProtocol(
707 /* variables we may use later */
708 static oid objid[USM_LENGTH_OID_MAX];
710 struct usmUser *uptr;
713 if (var_val_type != ASN_OBJECT_ID){
714 DEBUGMSGTL(("usmUser","write to usmUserAuthProtocol not ASN_OBJECT_ID\n"));
715 return SNMP_ERR_WRONGTYPE;
717 if (var_val_len > sizeof(objid)){
718 DEBUGMSGTL(("usmUser","write to usmUserAuthProtocol: bad length\n"));
719 return SNMP_ERR_WRONGLENGTH;
721 if (action == COMMIT){
722 size = var_val_len/sizeof(oid);
723 memcpy(objid, var_val, var_val_len);
725 /* don't allow creations here */
726 if ((uptr = usm_parse_user(name, name_len)) == NULL)
727 return SNMP_ERR_NOSUCHNAME;
729 /* check the objid for validity */
730 /* only allow sets to perform a change to usmNoAuthProtocol */
731 if (snmp_oid_compare(objid, size, usmNoAuthProtocol,
732 sizeof(usmNoAuthProtocol)/sizeof(oid)) != 0)
733 return SNMP_ERR_INCONSISTENTVALUE;
735 /* if the priv protocol is not usmNoPrivProtocol, we can't change */
736 if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen, usmNoPrivProtocol,
737 sizeof(usmNoPrivProtocol)/sizeof(oid)) != 0)
738 return SNMP_ERR_INCONSISTENTVALUE;
740 /* finally, we can do it */
741 optr = uptr->authProtocol;
742 if ((uptr->authProtocol = snmp_duplicate_objid(objid, size))
744 uptr->authProtocol = optr;
745 return SNMP_ERR_GENERR;
748 uptr->authProtocolLen = size;
750 return SNMP_ERR_NOERROR;
751 } /* end write_usmUserAuthProtocol() */
753 /*******************************************************************-o-******
754 * write_usmUserAuthKeyChange
758 * *var_val Octet string representing new KeyChange value.
762 * *name OID of user upon which to perform set operation.
766 * SNMP_ERR_NOERR Success.
768 * SNMP_ERR_WRONGLENGTH
769 * SNMP_ERR_NOSUCHNAME
772 * Note: This function handles both the usmUserAuthKeyChange and
773 * usmUserOwnAuthKeyChange objects. We are not passed the name
774 * of the user requseting the keychange, so we leave this to the
775 * calling module to verify when and if we should be called. To
776 * change this would require a change in the mib module API to
777 * pass in the securityName requesting the change.
779 * XXX: should handle action=UNDO's.
782 write_usmUserAuthKeyChange(
791 static unsigned char string[SNMP_MAXBUF_SMALL];
792 struct usmUser *uptr;
793 unsigned char buf[SNMP_MAXBUF_SMALL];
794 size_t buflen = SNMP_MAXBUF_SMALL;
796 char fnAuthKey[] = "write_usmUserAuthKeyChange",
797 fnOwnAuthKey[] = "write_usmUserOwnAuthKeyChange",
800 if (name[USM_MIB_LENGTH-1] == 6)
803 fname = fnOwnAuthKey;
805 if (var_val_type != ASN_OCTET_STR) {
806 DEBUGMSGTL(("usmUser","write to %s not ASN_OCTET_STR\n", fname));
807 return SNMP_ERR_WRONGTYPE;
810 if (var_val_len > sizeof(string)) {
811 DEBUGMSGTL(("usmUser","write to %s: bad length\n", fname));
812 return SNMP_ERR_WRONGLENGTH;
815 if (action == COMMIT) {
816 /* don't allow creations here */
817 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
818 return SNMP_ERR_NOSUCHNAME;
821 /* Change the key. */
822 DEBUGMSGTL(("usmUser","%s: changing auth key for user %s\n", fname, uptr->secName));
824 if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
825 uptr->authKey, uptr->authKeyLen,
826 var_val, var_val_len,
827 buf, &buflen) != SNMPERR_SUCCESS) {
828 DEBUGMSGTL(("usmUser","%s: ... failed\n", fname));
829 return SNMP_ERR_GENERR;
831 DEBUGMSGTL(("usmUser","%s: ... succeeded\n", fname));
832 SNMP_FREE(uptr->authKey);
833 memdup(&uptr->authKey, buf, buflen);
834 uptr->authKeyLen = buflen;
837 return SNMP_ERR_NOERROR;
838 } /* end write_usmUserAuthKeyChange() */
841 write_usmUserPrivProtocol(
850 /* variables we may use later */
851 static oid objid[USM_LENGTH_OID_MAX];
853 struct usmUser *uptr;
856 if (var_val_type != ASN_OBJECT_ID){
857 DEBUGMSGTL(("usmUser","write to usmUserPrivProtocol not ASN_OBJECT_ID\n"));
858 return SNMP_ERR_WRONGTYPE;
860 if (var_val_len > sizeof(objid)){
861 DEBUGMSGTL(("usmUser","write to usmUserPrivProtocol: bad length\n"));
862 return SNMP_ERR_WRONGLENGTH;
864 if (action == COMMIT){
865 size = var_val_len/sizeof(oid);
866 memcpy(objid, var_val, var_val_len);
868 /* don't allow creations here */
869 if ((uptr = usm_parse_user(name, name_len)) == NULL)
870 return SNMP_ERR_NOSUCHNAME;
872 /* check the objid for validity */
873 /* only allow sets to perform a change to usmNoPrivProtocol */
874 if (snmp_oid_compare(objid, size, usmNoPrivProtocol,
875 sizeof(usmNoPrivProtocol)/sizeof(oid)) != 0)
876 return SNMP_ERR_INCONSISTENTVALUE;
878 /* finally, we can do it */
879 optr = uptr->privProtocol;
880 if ((uptr->privProtocol = snmp_duplicate_objid(objid, size))
882 uptr->privProtocol = optr;
883 return SNMP_ERR_GENERR;
886 uptr->privProtocolLen = size;
888 return SNMP_ERR_NOERROR;
889 } /* end write_usmUserPrivProtocol() */
892 * Note: This function handles both the usmUserPrivKeyChange and
893 * usmUserOwnPrivKeyChange objects. We are not passed the name
894 * of the user requseting the keychange, so we leave this to the
895 * calling module to verify when and if we should be called. To
896 * change this would require a change in the mib module API to
897 * pass in the securityName requesting the change.
901 write_usmUserPrivKeyChange(
910 static unsigned char string[SNMP_MAXBUF_SMALL];
911 struct usmUser *uptr;
912 unsigned char buf[SNMP_MAXBUF_SMALL];
913 size_t buflen = SNMP_MAXBUF_SMALL;
915 char fnPrivKey[] = "write_usmUserPrivKeyChange",
916 fnOwnPrivKey[] = "write_usmUserOwnPrivKeyChange",
919 if (name[USM_MIB_LENGTH-1] == 9)
922 fname = fnOwnPrivKey;
924 if (var_val_type != ASN_OCTET_STR) {
925 DEBUGMSGTL(("usmUser","write to %s not ASN_OCTET_STR\n", fname));
926 return SNMP_ERR_WRONGTYPE;
929 if (var_val_len > sizeof(string)) {
930 DEBUGMSGTL(("usmUser","write to %s: bad length\n", fname));
931 return SNMP_ERR_WRONGLENGTH;
934 if (action == COMMIT) {
935 /* don't allow creations here */
936 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
937 return SNMP_ERR_NOSUCHNAME;
940 /* Change the key. */
941 DEBUGMSGTL(("usmUser","%s: changing priv key for user %s\n", fname, uptr->secName));
943 if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
944 uptr->privKey, uptr->privKeyLen,
945 var_val, var_val_len,
946 buf, &buflen) != SNMPERR_SUCCESS) {
947 DEBUGMSGTL(("usmUser","%s: ... failed\n", fname));
948 return SNMP_ERR_GENERR;
950 DEBUGMSGTL(("usmUser","%s: ... succeeded\n", fname));
951 SNMP_FREE(uptr->privKey);
952 memdup(&uptr->privKey, buf, buflen);
953 uptr->privKeyLen = buflen;
956 return SNMP_ERR_NOERROR;
957 } /* end write_usmUserPrivKeyChange() */
969 /* variables we may use later */
970 static unsigned char string[SNMP_MAXBUF];
972 struct usmUser *uptr;
974 if (var_val_type != ASN_OCTET_STR){
975 DEBUGMSGTL(("usmUser","write to usmUserPublic not ASN_OCTET_STR\n"));
976 return SNMP_ERR_WRONGTYPE;
978 if (var_val_len > sizeof(string)){
979 DEBUGMSGTL(("usmUser","write to usmUserPublic: bad length\n"));
980 return SNMP_ERR_WRONGLENGTH;
982 if (action == COMMIT) {
983 /* don't allow creations here */
984 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
985 return SNMP_ERR_NOSUCHNAME;
987 if (uptr->userPublicString)
988 free(uptr->userPublicString);
989 uptr->userPublicString = (u_char *) malloc(var_val_len+1);
990 if (uptr->userPublicString == NULL) {
991 return SNMP_ERR_GENERR;
993 memcpy(uptr->userPublicString, var_val, var_val_len);
994 uptr->userPublicString[var_val_len] = 0;
995 DEBUGMSG(("usmUser", "setting public string: %d - %s\n", var_val_len,
996 uptr->userPublicString));
998 return SNMP_ERR_NOERROR;
999 } /* end write_usmUserPublic() */
1002 write_usmUserStorageType(
1005 u_char var_val_type,
1011 /* variables we may use later */
1012 static long long_ret;
1013 struct usmUser *uptr;
1015 if (var_val_type != ASN_INTEGER){
1016 DEBUGMSGTL(("usmUser","write to usmUserStorageType not ASN_INTEGER\n"));
1017 return SNMP_ERR_WRONGTYPE;
1019 if (var_val_len > sizeof(long_ret)){
1020 DEBUGMSGTL(("usmUser","write to usmUserStorageType: bad length\n"));
1021 return SNMP_ERR_WRONGLENGTH;
1023 if (action == COMMIT){
1024 /* don't allow creations here */
1025 if ((uptr = usm_parse_user(name, name_len)) == NULL) {
1026 return SNMP_ERR_NOSUCHNAME;
1028 long_ret = *((long *) var_val);
1029 if ((long_ret == ST_VOLATILE || long_ret == ST_NONVOLATILE) &&
1030 (uptr->userStorageType == ST_VOLATILE ||
1031 uptr->userStorageType == ST_NONVOLATILE))
1032 uptr->userStorageType = long_ret;
1034 return SNMP_ERR_INCONSISTENTVALUE;
1036 return SNMP_ERR_NOERROR;
1037 } /* end write_usmUserStorageType() */
1039 /*******************************************************************-o-******
1040 * write_usmUserStatus
1052 * SNMP_ERR_NOERROR On success.
1054 * SNMP_ERR_INCONSISTENTNAME
1055 * SNMP_ERR_INCONSISTENTVALUE
1056 * SNMP_ERR_WRONGLENGTH
1057 * SNMP_ERR_WRONGTYPE
1060 write_usmUserStatus(
1063 u_char var_val_type,
1069 /* variables we may use later */
1070 static long long_ret;
1071 unsigned char *engineID;
1075 struct usmUser *uptr;
1077 if (var_val_type != ASN_INTEGER){
1078 DEBUGMSGTL(("usmUser","write to usmUserStatus not ASN_INTEGER\n"));
1079 return SNMP_ERR_WRONGTYPE;
1081 if (var_val_len > sizeof(long_ret)){
1082 DEBUGMSGTL(("usmUser","write to usmUserStatus: bad length\n"));
1083 return SNMP_ERR_WRONGLENGTH;
1085 if (action == COMMIT){
1086 long_ret = *((long *) var_val);
1088 /* ditch illegal values now */
1089 /* notReady can not be used, but the return error code is not mentioned */
1090 if (long_ret == RS_NOTREADY || long_ret < 1 || long_ret > 6)
1091 return SNMP_ERR_INCONSISTENTVALUE;
1093 /* see if we can parse the oid for engineID/name first */
1094 if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len-USM_MIB_LENGTH,
1095 &engineID, &engineIDLen, (u_char **)&newName, &nameLen))
1096 return SNMP_ERR_INCONSISTENTNAME;
1098 /* Now see if a user already exists with these index values */
1099 uptr = usm_get_user(engineID, engineIDLen, newName);
1102 if (uptr) { /* If so, we set the appropriate value... */
1105 if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
1106 return SNMP_ERR_INCONSISTENTVALUE;
1108 if (long_ret == RS_DESTROY) {
1109 usm_remove_user(uptr);
1110 usm_free_user(uptr);
1112 uptr->userStatus = long_ret;
1115 } else { /* ...else we create a new user */
1116 /* check for a valid status column set */
1117 if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) {
1120 return SNMP_ERR_INCONSISTENTVALUE;
1122 if (long_ret == RS_DESTROY) {
1123 /* destroying a non-existent row is actually legal */
1126 return SNMP_ERR_NOERROR;
1129 /* generate a new user */
1130 if ((uptr = usm_create_user()) == NULL) {
1133 return SNMP_ERR_GENERR;
1136 /* copy in the engineID */
1138 (unsigned char *) malloc(engineIDLen);
1139 if (uptr->engineID == NULL) {
1142 usm_free_user(uptr);
1143 return SNMP_ERR_GENERR;
1145 uptr->engineIDLen = engineIDLen;
1146 memcpy(uptr->engineID, engineID, engineIDLen);
1149 /* copy in the name and secname */
1150 if ((uptr->name = strdup(newName)) == NULL) {
1152 usm_free_user(uptr);
1153 return SNMP_ERR_GENERR;
1156 if ((uptr->secName = strdup(uptr->name)) == NULL) {
1157 usm_free_user(uptr);
1158 return SNMP_ERR_GENERR;
1161 /* set the status of the row based on the request */
1162 if (long_ret == RS_CREATEANDGO)
1163 uptr->userStatus = RS_ACTIVE;
1164 else if (long_ret == RS_CREATEANDWAIT)
1165 uptr->userStatus = RS_NOTINSERVICE;
1167 /* finally, add it to our list of users */
1170 } /* endif -- uptr */
1171 } /* endif -- action==COMMIT */
1173 return SNMP_ERR_NOERROR;
1175 } /* end write_usmUserStatus() */
1177 #endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */