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() */