usmUser.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:53k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * usmUser.c
  3.  */
  4. #include <net-snmp/net-snmp-config.h>
  5. #include <stdlib.h>
  6. #if HAVE_STRING_H
  7. #include <string.h>
  8. #else
  9. #include <strings.h>
  10. #endif
  11. #if HAVE_WINSOCK_H
  12. #include <winsock.h>
  13. #endif
  14. #include <net-snmp/net-snmp-includes.h>
  15. #include <net-snmp/agent/net-snmp-agent-includes.h>
  16. #include "util_funcs.h"
  17. #include "usmUser.h"
  18. int usmStatusCheck(struct usmUser *uptr);
  19. struct variable4 usmUser_variables[] = {
  20.     {USMUSERSPINLOCK, ASN_INTEGER, RWRITE, var_usmUser, 1, {1}},
  21.     {USMUSERSECURITYNAME, ASN_OCTET_STR, RONLY, var_usmUser, 3, {2, 1, 3}},
  22.     {USMUSERCLONEFROM, ASN_OBJECT_ID, RWRITE, var_usmUser, 3, {2, 1, 4}},
  23.     {USMUSERAUTHPROTOCOL, ASN_OBJECT_ID, RWRITE, var_usmUser, 3,
  24.      {2, 1, 5}},
  25.     {USMUSERAUTHKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
  26.      {2, 1, 6}},
  27.     {USMUSEROWNAUTHKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
  28.      {2, 1, 7}},
  29.     {USMUSERPRIVPROTOCOL, ASN_OBJECT_ID, RWRITE, var_usmUser, 3,
  30.      {2, 1, 8}},
  31.     {USMUSERPRIVKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
  32.      {2, 1, 9}},
  33.     {USMUSEROWNPRIVKEYCHANGE, ASN_OCTET_STR, RWRITE, var_usmUser, 3,
  34.      {2, 1, 10}},
  35.     {USMUSERPUBLIC, ASN_OCTET_STR, RWRITE, var_usmUser, 3, {2, 1, 11}},
  36.     {USMUSERSTORAGETYPE, ASN_INTEGER, RWRITE, var_usmUser, 3, {2, 1, 12}},
  37.     {USMUSERSTATUS, ASN_INTEGER, RWRITE, var_usmUser, 3, {2, 1, 13}},
  38. };
  39. oid             usmUser_variables_oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 2 };
  40. /*
  41.  * needed for the write_ functions to find the start of the index 
  42.  */
  43. #define USM_MIB_LENGTH 12
  44. static unsigned int usmUserSpinLock = 0;
  45. void
  46. init_usmUser(void)
  47. {
  48.     REGISTER_MIB("snmpv3/usmUser", usmUser_variables, variable4,
  49.                  usmUser_variables_oid);
  50. }
  51. void
  52. init_register_usmUser_context(const char *contextName) {
  53.     register_mib_context("snmpv3/usmUser",
  54.                          (struct variable *) usmUser_variables,
  55.                          sizeof(struct variable4),
  56.                          sizeof(usmUser_variables)/sizeof(struct variable4),
  57.                          usmUser_variables_oid,
  58.                          sizeof(usmUser_variables_oid)/sizeof(oid),
  59.                          DEFAULT_MIB_PRIORITY, 0, 0, NULL,
  60.                          contextName, -1, 0);
  61. }
  62. /*******************************************************************-o-******
  63.  * usm_generate_OID
  64.  *
  65.  * Parameters:
  66.  * *prefix (I) OID prefix to the usmUser table entry.
  67.  *  prefixLen (I)
  68.  * *uptr (I) Pointer to a user in the user list.
  69.  * *length (O) Length of generated index OID.
  70.  *      
  71.  * Returns:
  72.  * Pointer to the OID index for the user (uptr)  -OR-
  73.  * NULL on failure.
  74.  *
  75.  *
  76.  * Generate the index OID for a given usmUser name.  'length' is set to
  77.  * the length of the index OID.
  78.  *
  79.  * Index OID format is:
  80.  *
  81.  *    <...prefix>.<engineID_length>.<engineID>.<user_name_length>.<user_name>
  82.  */
  83. oid            *
  84. usm_generate_OID(oid * prefix, size_t prefixLen, struct usmUser *uptr,
  85.                  size_t * length)
  86. {
  87.     oid            *indexOid;
  88.     int             i;
  89.     *length = 2 + uptr->engineIDLen + strlen(uptr->name) + prefixLen;
  90.     indexOid = (oid *) malloc(*length * sizeof(oid));
  91.     if (indexOid) {
  92.         memmove(indexOid, prefix, prefixLen * sizeof(oid));
  93.         indexOid[prefixLen] = uptr->engineIDLen;
  94.         for (i = 0; i < (int) uptr->engineIDLen; i++)
  95.             indexOid[prefixLen + 1 + i] = (oid) uptr->engineID[i];
  96.         indexOid[prefixLen + uptr->engineIDLen + 1] = strlen(uptr->name);
  97.         for (i = 0; i < (int) strlen(uptr->name); i++)
  98.             indexOid[prefixLen + uptr->engineIDLen + 2 + i] =
  99.                 (oid) uptr->name[i];
  100.     }
  101.     return indexOid;
  102. }                               /* end usm_generate_OID() */
  103. /*
  104.  * usm_parse_oid(): parses an index to the usmTable to break it down into
  105.  * a engineID component and a name component.  The results are stored in:
  106.  * 
  107.  * **engineID:   a newly malloced string.
  108.  * *engineIDLen: The length of the malloced engineID string above.
  109.  * **name:       a newly malloced string.
  110.  * *nameLen:     The length of the malloced name string above.
  111.  * 
  112.  * returns 1 if an error is encountered, or 0 if successful.
  113.  */
  114. int
  115. usm_parse_oid(oid * oidIndex, size_t oidLen,
  116.               unsigned char **engineID, size_t * engineIDLen,
  117.               unsigned char **name, size_t * nameLen)
  118. {
  119.     int             nameL;
  120.     int             engineIDL;
  121.     int             i;
  122.     /*
  123.      * first check the validity of the oid 
  124.      */
  125.     if ((oidLen <= 0) || (!oidIndex)) {
  126.         DEBUGMSGTL(("usmUser",
  127.                     "parse_oid: null oid or zero length oid passed inn"));
  128.         return 1;
  129.     }
  130.     engineIDL = *oidIndex;      /* initial engineID length */
  131.     if ((int) oidLen < engineIDL + 2) {
  132.         DEBUGMSGTL(("usmUser",
  133.                     "parse_oid: invalid oid length: less than the engineIDLenn"));
  134.         return 1;
  135.     }
  136.     nameL = oidIndex[engineIDL + 1];    /* the initial name length */
  137.     if ((int) oidLen != engineIDL + nameL + 2) {
  138.         DEBUGMSGTL(("usmUser",
  139.                     "parse_oid: invalid oid length: length is not exactn"));
  140.         return 1;
  141.     }
  142.     /*
  143.      * its valid, malloc the space and store the results 
  144.      */
  145.     if (engineID == NULL || name == NULL) {
  146.         DEBUGMSGTL(("usmUser",
  147.                     "parse_oid: null storage pointer passed in.n"));
  148.         return 1;
  149.     }
  150.     *engineID = (unsigned char *) malloc(engineIDL);
  151.     if (*engineID == NULL) {
  152.         DEBUGMSGTL(("usmUser",
  153.                     "parse_oid: malloc of the engineID failedn"));
  154.         return 1;
  155.     }
  156.     *engineIDLen = engineIDL;
  157.     *name = (unsigned char *) malloc(nameL + 1);
  158.     if (*name == NULL) {
  159.         DEBUGMSGTL(("usmUser", "parse_oid: malloc of the name failedn"));
  160.         free(*engineID);
  161.         return 1;
  162.     }
  163.     *nameLen = nameL;
  164.     for (i = 0; i < engineIDL; i++) {
  165.         if (oidIndex[i + 1] > 255) {
  166.             goto UPO_parse_error;
  167.         }
  168.         engineID[0][i] = (unsigned char) oidIndex[i + 1];
  169.     }
  170.     for (i = 0; i < nameL; i++) {
  171.         if (oidIndex[i + 2 + engineIDL] > 255) {
  172.           UPO_parse_error:
  173.             free(*engineID);
  174.             free(*name);
  175.             return 1;
  176.         }
  177.         name[0][i] = (unsigned char) oidIndex[i + 2 + engineIDL];
  178.     }
  179.     name[0][nameL] = 0;
  180.     return 0;
  181. }                               /* end usm_parse_oid() */
  182. /*******************************************************************-o-******
  183.  * usm_parse_user
  184.  *
  185.  * Parameters:
  186.  * *name Complete OID indexing a given usmUser entry.
  187.  *  name_length
  188.  *      
  189.  * Returns:
  190.  * Pointer to a usmUser  -OR-
  191.  * NULL if name does not convert to a usmUser.
  192.  * 
  193.  * Convert an (full) OID and return a pointer to a matching user in the
  194.  * user list if one exists.
  195.  */
  196. struct usmUser *
  197. usm_parse_user(oid * name, size_t name_len)
  198. {
  199.     struct usmUser *uptr;
  200.     char           *newName;
  201.     u_char         *engineID;
  202.     size_t          nameLen, engineIDLen;
  203.     /*
  204.      * get the name and engineID out of the incoming oid 
  205.      */
  206.     if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
  207.                       &engineID, &engineIDLen, (u_char **) & newName,
  208.                       &nameLen))
  209.         return NULL;
  210.     /*
  211.      * Now see if a user exists with these index values 
  212.      */
  213.     uptr = usm_get_user(engineID, engineIDLen, newName);
  214.     free(engineID);
  215.     free(newName);
  216.     return uptr;
  217. }                               /* end usm_parse_user() */
  218. /*******************************************************************-o-******
  219.  * var_usmUser
  220.  *
  221.  * Parameters:
  222.  *   *vp    (I)     Variable-binding associated with this action.
  223.  *   *name    (I/O)   Input name requested, output name found.
  224.  *   *length  (I/O)   Length of input and output oid's.
  225.  *    exact   (I)     TRUE if an exact match was requested.
  226.  *   *var_len (O)     Length of variable or 0 if function returned.
  227.  * (**write_method)   Hook to name a write method (UNUSED).
  228.  *      
  229.  * Returns:
  230.  * Pointer to (char *) containing related data of length 'length'
  231.  *   (May be NULL.)
  232.  *
  233.  *
  234.  * Call-back function passed to the agent in order to return information
  235.  * for the USM MIB tree.
  236.  *
  237.  *
  238.  * If this invocation is not for USMUSERSPINLOCK, lookup user name
  239.  * in the usmUser list.
  240.  *
  241.  * If the name does not match any user and the request
  242.  * is for an exact match, -or- if the usmUser list is empty, create a 
  243.  * new list entry.
  244.  *
  245.  * Finally, service the given USMUSER* var-bind.  A NULL user generally
  246.  * results in a NULL return value.
  247.  */
  248. u_char         *
  249. var_usmUser(struct variable * vp,
  250.             oid * name,
  251.             size_t * length,
  252.             int exact, size_t * var_len, WriteMethod ** write_method)
  253. {
  254.     struct usmUser *uptr = NULL, *nptr, *pptr;
  255.     int             i, rtest, result;
  256.     oid            *indexOid;
  257.     size_t          len;
  258.     /*
  259.      * variables we may use later 
  260.      */
  261.     static long     long_ret;
  262.     static u_char   string[1];
  263.     static oid      objid[2];   /* for .0.0 */
  264.     *write_method = 0;          /* assume it isnt writable for the time being */
  265.     *var_len = sizeof(long_ret);        /* assume an integer and change later if not */
  266.     if (vp->magic != USMUSERSPINLOCK) {
  267.         oid             newname[MAX_OID_LEN];
  268.         len = (*length < vp->namelen) ? *length : vp->namelen;
  269.         rtest = snmp_oid_compare(name, len, vp->name, len);
  270.         if (rtest > 0 ||
  271.             /*
  272.              * (rtest == 0 && !exact && (int) vp->namelen+1 < (int) *length) || 
  273.              */
  274.             (exact == 1 && rtest != 0)) {
  275.             if (var_len)
  276.                 *var_len = 0;
  277.             return 0;
  278.         }
  279.         memset(newname, 0, sizeof(newname));
  280.         if (((int) *length) <= (int) vp->namelen || rtest == -1) {
  281.             /*
  282.              * oid is not within our range yet 
  283.              */
  284.             /*
  285.              * need to fail if not exact 
  286.              */
  287.             uptr = usm_get_userList();
  288.         } else {
  289.             for (nptr = usm_get_userList(), pptr = NULL, uptr = NULL;
  290.                  nptr != NULL; pptr = nptr, nptr = nptr->next) {
  291.                 indexOid =
  292.                     usm_generate_OID(vp->name, vp->namelen, nptr, &len);
  293.                 result = snmp_oid_compare(name, *length, indexOid, len);
  294.                 DEBUGMSGTL(("usmUser", "Checking user: %s - ",
  295.                             nptr->name));
  296.                 for (i = 0; i < (int) nptr->engineIDLen; i++) {
  297.                     DEBUGMSG(("usmUser", " %x", nptr->engineID[i]));
  298.                 }
  299.                 DEBUGMSG(("usmUser", " - %d n  -> OID: ", result));
  300.                 DEBUGMSGOID(("usmUser", indexOid, len));
  301.                 DEBUGMSG(("usmUser", "n"));
  302.                 free(indexOid);
  303.                 if (exact) {
  304.                     if (result == 0) {
  305.                         uptr = nptr;
  306.                     }
  307.                 } else {
  308.                     if (result == 0) {
  309.                         /*
  310.                          * found an exact match.  Need the next one for !exact 
  311.                          */
  312.                         uptr = nptr->next;
  313.                     } else if (result == -1) {
  314.                         uptr = nptr;
  315.                         break;
  316.                     }
  317.                 }
  318.             }
  319.         }                       /* endif -- name <= vp->name */
  320.         /*
  321.          * if uptr is NULL and exact we need to continue for creates 
  322.          */
  323.         if (uptr == NULL && !exact)
  324.             return (NULL);
  325.         if (uptr) {
  326.             indexOid = usm_generate_OID(vp->name, vp->namelen, uptr, &len);
  327.             *length = len;
  328.             memmove(name, indexOid, len * sizeof(oid));
  329.             DEBUGMSGTL(("usmUser", "Found user: %s - ", uptr->name));
  330.             for (i = 0; i < (int) uptr->engineIDLen; i++) {
  331.                 DEBUGMSG(("usmUser", " %x", uptr->engineID[i]));
  332.             }
  333.             DEBUGMSG(("usmUser", "n  -> OID: "));
  334.             DEBUGMSGOID(("usmUser", indexOid, len));
  335.             DEBUGMSG(("usmUser", "n"));
  336.             free(indexOid);
  337.         }
  338.     } else {
  339.         if (header_generic(vp, name, length, exact, var_len, write_method))
  340.             return 0;
  341.     }                           /* endif -- vp->magic != USMUSERSPINLOCK */
  342.     switch (vp->magic) {
  343.     case USMUSERSPINLOCK:
  344.         *write_method = write_usmUserSpinLock;
  345.         long_ret = usmUserSpinLock;
  346.         return (unsigned char *) &long_ret;
  347.     case USMUSERSECURITYNAME:
  348.         if (uptr) {
  349.             *var_len = strlen(uptr->secName);
  350.             return (unsigned char *) uptr->secName;
  351.         }
  352.         return NULL;
  353.     case USMUSERCLONEFROM:
  354.         *write_method = write_usmUserCloneFrom;
  355.         if (uptr) {
  356.             objid[0] = 0;       /* "When this object is read, the ZeroDotZero OID */
  357.             objid[1] = 0;       /*  is returned." */
  358.             *var_len = sizeof(oid) * 2;
  359.             return (unsigned char *) objid;
  360.         }
  361.         return NULL;
  362.     case USMUSERAUTHPROTOCOL:
  363.         *write_method = write_usmUserAuthProtocol;
  364.         if (uptr) {
  365.             *var_len = uptr->authProtocolLen * sizeof(oid);
  366.             return (u_char *) uptr->authProtocol;
  367.         }
  368.         return NULL;
  369.     case USMUSERAUTHKEYCHANGE:
  370.     case USMUSEROWNAUTHKEYCHANGE:
  371.         /*
  372.          * we treat these the same, and let the calling module
  373.          * distinguish between them 
  374.          */
  375.         *write_method = write_usmUserAuthKeyChange;
  376.         if (uptr) {
  377.             *string = 0;        /* always return a NULL string */
  378.             *var_len = 0;
  379.             return string;
  380.         }
  381.         return NULL;
  382.     case USMUSERPRIVPROTOCOL:
  383.         *write_method = write_usmUserPrivProtocol;
  384.         if (uptr) {
  385.             *var_len = uptr->privProtocolLen * sizeof(oid);
  386.             return (u_char *) uptr->privProtocol;
  387.         }
  388.         return NULL;
  389.     case USMUSERPRIVKEYCHANGE:
  390.     case USMUSEROWNPRIVKEYCHANGE:
  391.         /*
  392.          * we treat these the same, and let the calling module
  393.          * distinguish between them 
  394.          */
  395.         *write_method = write_usmUserPrivKeyChange;
  396.         if (uptr) {
  397.             *string = 0;        /* always return a NULL string */
  398.             *var_len = 0;
  399.             return string;
  400.         }
  401.         return NULL;
  402.     case USMUSERPUBLIC:
  403.         *write_method = write_usmUserPublic;
  404.         if (uptr) {
  405.             if (uptr->userPublicString) {
  406.                 *var_len = strlen((char *) uptr->userPublicString);
  407.                 return uptr->userPublicString;
  408.             }
  409.             *string = 0;
  410.             *var_len = 0;       /* return an empty string if the public
  411.                                  * string hasn't been defined yet */
  412.             return string;
  413.         }
  414.         return NULL;
  415.     case USMUSERSTORAGETYPE:
  416.         *write_method = write_usmUserStorageType;
  417.         if (uptr) {
  418.             long_ret = uptr->userStorageType;
  419.             return (unsigned char *) &long_ret;
  420.         }
  421.         return NULL;
  422.     case USMUSERSTATUS:
  423.         *write_method = write_usmUserStatus;
  424.         if (uptr) {
  425.             long_ret = uptr->userStatus;
  426.             return (unsigned char *) &long_ret;
  427.         }
  428.         return NULL;
  429.     default:
  430.         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_usmUsern",
  431.                     vp->magic));
  432.     }
  433.     return 0;
  434. }                               /* end var_usmUser() */
  435. /*
  436.  * write_usmUserSpinLock(): called when a set is performed on the
  437.  * usmUserSpinLock object 
  438.  */
  439. int
  440. write_usmUserSpinLock(int action,
  441.                       u_char * var_val,
  442.                       u_char var_val_type,
  443.                       size_t var_val_len,
  444.                       u_char * statP, oid * name, size_t name_len)
  445. {
  446.     /*
  447.      * variables we may use later 
  448.      */
  449.     static long     long_ret;
  450.     if (var_val_type != ASN_INTEGER) {
  451.         DEBUGMSGTL(("usmUser",
  452.                     "write to usmUserSpinLock not ASN_INTEGERn"));
  453.         return SNMP_ERR_WRONGTYPE;
  454.     }
  455.     if (var_val_len > sizeof(long_ret)) {
  456.         DEBUGMSGTL(("usmUser", "write to usmUserSpinLock: bad lengthn"));
  457.         return SNMP_ERR_WRONGLENGTH;
  458.     }
  459.     long_ret = *((long *) var_val);
  460.     if (long_ret != (long) usmUserSpinLock)
  461.         return SNMP_ERR_INCONSISTENTVALUE;
  462.     if (action == COMMIT) {
  463.         if (usmUserSpinLock == 2147483647)
  464.             usmUserSpinLock = 0;
  465.         else
  466.             usmUserSpinLock++;
  467.     }
  468.     return SNMP_ERR_NOERROR;
  469. }                               /* end write_usmUserSpinLock() */
  470. /*******************************************************************-o-******
  471.  * write_usmUserCloneFrom
  472.  *
  473.  * Parameters:
  474.  *  action
  475.  * *var_val
  476.  *  var_val_type
  477.  *  var_val_len
  478.  * *statP (UNUSED)
  479.  * *name OID of user to clone from.
  480.  *  name_len
  481.  *      
  482.  * Returns:
  483.  * SNMP_ERR_NOERROR On success  -OR-  If user exists
  484.  *   and has already been cloned.
  485.  * SNMP_ERR_GENERR Local function call failures.
  486.  * SNMP_ERR_INCONSISTENTNAME 'name' does not exist in user list
  487.  *   -OR-  user to clone from != RS_ACTIVE.
  488.  * SNMP_ERR_WRONGLENGTH OID length > than local buffer size.
  489.  * SNMP_ERR_WRONGTYPE ASN_OBJECT_ID is wrong.
  490.  *
  491.  *
  492.  * XXX:  should handle action=UNDO's.
  493.  */
  494. int
  495. write_usmUserCloneFrom(int action,
  496.                        u_char * var_val,
  497.                        u_char var_val_type,
  498.                        size_t var_val_len,
  499.                        u_char * statP, oid * name, size_t name_len)
  500. {
  501.     struct usmUser *uptr, *cloneFrom;
  502.     if (action == RESERVE1) {
  503.         if (var_val_type != ASN_OBJECT_ID) {
  504.             DEBUGMSGTL(("usmUser",
  505.                         "write to usmUserCloneFrom not ASN_OBJECT_IDn"));
  506.             return SNMP_ERR_WRONGTYPE;
  507.         }
  508.         if (var_val_len > USM_LENGTH_OID_MAX * sizeof(oid) ||
  509.             var_val_len % sizeof(oid) != 0) {
  510.             DEBUGMSGTL(("usmUser",
  511.                         "write to usmUserCloneFrom: bad lengthn"));
  512.             return SNMP_ERR_WRONGLENGTH;
  513.         }
  514.     } else if (action == RESERVE2) {
  515.         if ((uptr = usm_parse_user(name, name_len)) == NULL) {
  516.             /*
  517.              * We don't allow creations here.  
  518.              */
  519.             return SNMP_ERR_INCONSISTENTNAME;
  520.         }
  521.         /*
  522.          * Has the user already been cloned?  If so, writes to this variable
  523.          * are defined to have no effect and to produce no error.  
  524.          */
  525.         if (uptr->cloneFrom != NULL) {
  526.             return SNMP_ERR_NOERROR;
  527.         }
  528.         cloneFrom =
  529.             usm_parse_user((oid *) var_val, var_val_len / sizeof(oid));
  530.         if (cloneFrom == NULL || cloneFrom->userStatus != SNMP_ROW_ACTIVE) {
  531.             return SNMP_ERR_INCONSISTENTNAME;
  532.         }
  533.         uptr->cloneFrom = snmp_duplicate_objid((oid *) var_val,
  534.                                                var_val_len / sizeof(oid));
  535.         usm_cloneFrom_user(cloneFrom, uptr);
  536.         if (usmStatusCheck(uptr) && uptr->userStatus == SNMP_ROW_NOTREADY) {
  537.             uptr->userStatus = SNMP_ROW_NOTINSERVICE;
  538.         }
  539.     }
  540.     return SNMP_ERR_NOERROR;
  541. }
  542. /*******************************************************************-o-******
  543.  * write_usmUserAuthProtocol
  544.  *
  545.  * Parameters:
  546.  *  action
  547.  * *var_val OID of auth transform to set.
  548.  *  var_val_type
  549.  *  var_val_len
  550.  * *statP
  551.  * *name OID of user upon which to perform set operation.
  552.  *  name_len
  553.  *      
  554.  * Returns:
  555.  * SNMP_ERR_NOERROR On success.
  556.  * SNMP_ERR_GENERR
  557.  * SNMP_ERR_INCONSISTENTVALUE
  558.  * SNMP_ERR_NOSUCHNAME
  559.  * SNMP_ERR_WRONGLENGTH
  560.  * SNMP_ERR_WRONGTYPE
  561.  */
  562. int
  563. write_usmUserAuthProtocol(int action,
  564.                           u_char * var_val,
  565.                           u_char var_val_type,
  566.                           size_t var_val_len,
  567.                           u_char * statP, oid * name, size_t name_len)
  568. {
  569.     static oid     *optr;
  570.     static size_t   olen;
  571.     static int      resetOnFail;
  572.     struct usmUser *uptr;
  573.     if (action == RESERVE1) {
  574.         resetOnFail = 0;
  575.         if (var_val_type != ASN_OBJECT_ID) {
  576.             DEBUGMSGTL(("usmUser",
  577.                         "write to usmUserAuthProtocol not ASN_OBJECT_IDn"));
  578.             return SNMP_ERR_WRONGTYPE;
  579.         }
  580.         if (var_val_len > USM_LENGTH_OID_MAX * sizeof(oid) ||
  581.             var_val_len % sizeof(oid) != 0) {
  582.             DEBUGMSGTL(("usmUser",
  583.                         "write to usmUserAuthProtocol: bad lengthn"));
  584.             return SNMP_ERR_WRONGLENGTH;
  585.         }
  586.     } else if (action == RESERVE2) {
  587.         if ((uptr = usm_parse_user(name, name_len)) == NULL) {
  588.             return SNMP_ERR_INCONSISTENTNAME;
  589.         }
  590.         if (uptr->userStatus == RS_ACTIVE
  591.             || uptr->userStatus == RS_NOTREADY
  592.             || uptr->userStatus == RS_NOTINSERVICE) {
  593.             /*
  594.              * The authProtocol is already set.  It is only legal to CHANGE it
  595.              * to usmNoAuthProtocol...  
  596.              */
  597.             if (snmp_oid_compare
  598.                 ((oid *) var_val, var_val_len / sizeof(oid),
  599.                  usmNoAuthProtocol,
  600.                  sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0) {
  601.                 /*
  602.                  * ... and then only if the privProtocol is equal to
  603.                  * usmNoPrivProtocol.  
  604.                  */
  605.                 if (snmp_oid_compare
  606.                     (uptr->privProtocol, uptr->privProtocolLen,
  607.                      usmNoPrivProtocol,
  608.                      sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0) {
  609.                     return SNMP_ERR_INCONSISTENTVALUE;
  610.                 }
  611.                 optr = uptr->authProtocol;
  612.                 olen = uptr->authProtocolLen;
  613.                 resetOnFail = 1;
  614.                 uptr->authProtocol = snmp_duplicate_objid((oid *) var_val,
  615.                                                           var_val_len /
  616.                                                           sizeof(oid));
  617.                 if (uptr->authProtocol == NULL) {
  618.                     return SNMP_ERR_RESOURCEUNAVAILABLE;
  619.                 }
  620.                 uptr->authProtocolLen = var_val_len / sizeof(oid);
  621.             } else
  622.                 if (snmp_oid_compare
  623.                     ((oid *) var_val, var_val_len / sizeof(oid),
  624.                      uptr->authProtocol, uptr->authProtocolLen) == 0) {
  625.                 /*
  626.                  * But it's also okay to set it to the same thing as it
  627.                  * currently is.  
  628.                  */
  629.                 return SNMP_ERR_NOERROR;
  630.             } else {
  631.                 return SNMP_ERR_INCONSISTENTVALUE;
  632.             }
  633.         } else {
  634.             /*
  635.              * This row is under creation.  It's okay to set
  636.              * usmUserAuthProtocol to any valid authProtocol but it will be
  637.              * overwritten when usmUserCloneFrom is set (so don't write it if
  638.              * that has already been set).  
  639.              */
  640.             if (snmp_oid_compare
  641.                 ((oid *) var_val, var_val_len / sizeof(oid),
  642.                  usmNoAuthProtocol,
  643.                  sizeof(usmNoAuthProtocol) / sizeof(oid)) == 0
  644. #ifndef DISABLE_MD5
  645.                 || snmp_oid_compare((oid *) var_val,
  646.                                     var_val_len / sizeof(oid),
  647.                                     usmHMACMD5AuthProtocol,
  648.                                     sizeof(usmHMACMD5AuthProtocol) /
  649.                                     sizeof(oid)) == 0
  650. #endif
  651.                 || snmp_oid_compare((oid *) var_val,
  652.                                     var_val_len / sizeof(oid),
  653.                                     usmHMACSHA1AuthProtocol,
  654.                                     sizeof(usmHMACSHA1AuthProtocol) /
  655.                                     sizeof(oid)) == 0) {
  656.                 if (uptr->cloneFrom != NULL) {
  657.                     optr = uptr->authProtocol;
  658.                     olen = uptr->authProtocolLen;
  659.                     resetOnFail = 1;
  660.                     uptr->authProtocol =
  661.                         snmp_duplicate_objid((oid *) var_val,
  662.                                              var_val_len / sizeof(oid));
  663.                     if (uptr->authProtocol == NULL) {
  664.                         return SNMP_ERR_RESOURCEUNAVAILABLE;
  665.                     }
  666.                     uptr->authProtocolLen = var_val_len / sizeof(oid);
  667.                 }
  668.             } else {
  669.                 /*
  670.                  * Unknown authentication protocol.  
  671.                  */
  672.                 return SNMP_ERR_WRONGVALUE;
  673.             }
  674.         }
  675.     } else if (action == COMMIT) {
  676.         SNMP_FREE(optr);
  677.         optr = NULL;
  678.     } else if (action == FREE || action == UNDO) {
  679.         if ((uptr = usm_parse_user(name, name_len)) != NULL) {
  680.             if (resetOnFail) {
  681.                 SNMP_FREE(uptr->authProtocol);
  682.                 uptr->authProtocol = optr;
  683.                 uptr->authProtocolLen = olen;
  684.             }
  685.         }
  686.     }
  687.     return SNMP_ERR_NOERROR;
  688. }                               /* end write_usmUserAuthProtocol() */
  689. /*******************************************************************-o-******
  690.  * write_usmUserAuthKeyChange
  691.  *
  692.  * Parameters:
  693.  *  action
  694.  * *var_val Octet string representing new KeyChange value.
  695.  *  var_val_type
  696.  *  var_val_len
  697.  * *statP (UNUSED)
  698.  * *name OID of user upon which to perform set operation.
  699.  *  name_len
  700.  *      
  701.  * Returns:
  702.  * SNMP_ERR_NOERR Success.
  703.  * SNMP_ERR_WRONGTYPE
  704.  * SNMP_ERR_WRONGLENGTH
  705.  * SNMP_ERR_NOSUCHNAME
  706.  * SNMP_ERR_GENERR
  707.  *
  708.  * Note: This function handles both the usmUserAuthKeyChange and
  709.  *       usmUserOwnAuthKeyChange objects.  We are not passed the name
  710.  *       of the user requseting the keychange, so we leave this to the
  711.  *       calling module to verify when and if we should be called.  To
  712.  *       change this would require a change in the mib module API to
  713.  *       pass in the securityName requesting the change.
  714.  *
  715.  * XXX:  should handle action=UNDO's.
  716.  */
  717. int
  718. write_usmUserAuthKeyChange(int action,
  719.                            u_char * var_val,
  720.                            u_char var_val_type,
  721.                            size_t var_val_len,
  722.                            u_char * statP, oid * name, size_t name_len)
  723. {
  724.     struct usmUser *uptr;
  725.     unsigned char   buf[SNMP_MAXBUF_SMALL];
  726.     size_t          buflen = SNMP_MAXBUF_SMALL;
  727.     const char      fnAuthKey[] = "write_usmUserAuthKeyChange";
  728.     const char      fnOwnAuthKey[] = "write_usmUserOwnAuthKeyChange";
  729.     const char     *fname;
  730.     static unsigned char *oldkey;
  731.     static size_t   oldkeylen;
  732.     static int      resetOnFail;
  733.     if (name[USM_MIB_LENGTH - 1] == 6) {
  734.         fname = fnAuthKey;
  735.     } else {
  736.         fname = fnOwnAuthKey;
  737.     }
  738.     if (action == RESERVE1) {
  739.         resetOnFail = 0;
  740.         if (var_val_type != ASN_OCTET_STR) {
  741.             DEBUGMSGTL(("usmUser", "write to %s not ASN_OCTET_STRn",
  742.                         fname));
  743.             return SNMP_ERR_WRONGTYPE;
  744.         }
  745.         if (var_val_len == 0) {
  746.             return SNMP_ERR_WRONGLENGTH;
  747.         }
  748.     } else if (action == RESERVE2) {
  749.         if ((uptr = usm_parse_user(name, name_len)) == NULL) {
  750.             return SNMP_ERR_INCONSISTENTNAME;
  751.         } else {
  752. #ifndef DISABLE_MD5
  753.             if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen,
  754.                                  usmHMACMD5AuthProtocol,
  755.                                  sizeof(usmHMACMD5AuthProtocol) /
  756.                                  sizeof(oid)) == 0) {
  757.                 if (var_val_len != 0 && var_val_len != 32) {
  758.                     return SNMP_ERR_WRONGLENGTH;
  759.                 }
  760.             } else
  761. #endif
  762.                 if (snmp_oid_compare
  763.                     (uptr->authProtocol, uptr->authProtocolLen,
  764.                      usmHMACSHA1AuthProtocol,
  765.                      sizeof(usmHMACSHA1AuthProtocol) / sizeof(oid)) == 0) {
  766.                 if (var_val_len != 0 && var_val_len != 40) {
  767.                     return SNMP_ERR_WRONGLENGTH;
  768.                 }
  769.             }
  770.         }
  771.     } else if (action == ACTION) {
  772.         if ((uptr = usm_parse_user(name, name_len)) == NULL) {
  773.             return SNMP_ERR_INCONSISTENTNAME;
  774.         }
  775.         if (uptr->cloneFrom == NULL) {
  776.             return SNMP_ERR_INCONSISTENTNAME;
  777.         }
  778.         if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen,
  779.                              usmNoAuthProtocol,
  780.                              sizeof(usmNoAuthProtocol) / sizeof(oid)) ==
  781.             0) {
  782.             /*
  783.              * "When the value of the corresponding usmUserAuthProtocol is
  784.              * usmNoAuthProtocol, then a set is successful, but effectively
  785.              * is a no-op."  
  786.              */
  787.             DEBUGMSGTL(("usmUser",
  788.                         "%s: noAuthProtocol keyChange... success!n",
  789.                         fname));
  790.             return SNMP_ERR_NOERROR;
  791.         }
  792.         /*
  793.          * Change the key.  
  794.          */
  795.         DEBUGMSGTL(("usmUser", "%s: changing auth key for user %sn",
  796.                     fname, uptr->secName));
  797.         if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
  798.                              uptr->authKey, uptr->authKeyLen,
  799.                              var_val, var_val_len,
  800.                              buf, &buflen) != SNMPERR_SUCCESS) {
  801.             DEBUGMSGTL(("usmUser", "%s: ... failedn", fname));
  802.             return SNMP_ERR_GENERR;
  803.         }
  804.         DEBUGMSGTL(("usmUser", "%s: ... succeededn", fname));
  805.         resetOnFail = 1;
  806.         oldkey = uptr->authKey;
  807.         oldkeylen = uptr->authKeyLen;
  808.         memdup(&uptr->authKey, buf, buflen);
  809.         if (uptr->authKey == NULL) {
  810.             return SNMP_ERR_RESOURCEUNAVAILABLE;
  811.         }
  812.         uptr->authKeyLen = buflen;
  813.     } else if (action == COMMIT) {
  814.         SNMP_FREE(oldkey);
  815.         oldkey = NULL;
  816.     } else if (action == UNDO) {
  817.         if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) {
  818.             SNMP_FREE(uptr->authKey);
  819.             uptr->authKey = oldkey;
  820.             uptr->authKeyLen = oldkeylen;
  821.         }
  822.     }
  823.     return SNMP_ERR_NOERROR;
  824. }                               /* end write_usmUserAuthKeyChange() */
  825. int
  826. write_usmUserPrivProtocol(int action,
  827.                           u_char * var_val,
  828.                           u_char var_val_type,
  829.                           size_t var_val_len,
  830.                           u_char * statP, oid * name, size_t name_len)
  831. {
  832.     static oid     *optr;
  833.     static size_t   olen;
  834.     static int      resetOnFail;
  835.     struct usmUser *uptr;
  836.     if (action == RESERVE1) {
  837.         resetOnFail = 0;
  838.         if (var_val_type != ASN_OBJECT_ID) {
  839.             DEBUGMSGTL(("usmUser",
  840.                         "write to usmUserPrivProtocol not ASN_OBJECT_IDn"));
  841.             return SNMP_ERR_WRONGTYPE;
  842.         }
  843.         if (var_val_len > USM_LENGTH_OID_MAX * sizeof(oid) ||
  844.             var_val_len % sizeof(oid) != 0) {
  845.             DEBUGMSGTL(("usmUser",
  846.                         "write to usmUserPrivProtocol: bad lengthn"));
  847.             return SNMP_ERR_WRONGLENGTH;
  848.         }
  849.     } else if (action == RESERVE2) {
  850.         if ((uptr = usm_parse_user(name, name_len)) == NULL) {
  851.             return SNMP_ERR_INCONSISTENTNAME;
  852.         }
  853.         if (uptr->userStatus == RS_ACTIVE
  854.             || uptr->userStatus == RS_NOTREADY
  855.             || uptr->userStatus == RS_NOTINSERVICE) {
  856.             /*
  857.              * The privProtocol is already set.  It is only legal to CHANGE it
  858.              * to usmNoPrivProtocol.  
  859.              */
  860.             if (snmp_oid_compare
  861.                 ((oid *) var_val, var_val_len / sizeof(oid),
  862.                  usmNoPrivProtocol,
  863.                  sizeof(usmNoPrivProtocol) / sizeof(oid)) == 0) {
  864.                 resetOnFail = 1;
  865.                 optr = uptr->privProtocol;
  866.                 olen = uptr->privProtocolLen;
  867.                 uptr->privProtocol = snmp_duplicate_objid((oid *) var_val,
  868.                                                           var_val_len /
  869.                                                           sizeof(oid));
  870.                 if (uptr->privProtocol == NULL) {
  871.                     return SNMP_ERR_RESOURCEUNAVAILABLE;
  872.                 }
  873.                 uptr->privProtocolLen = var_val_len / sizeof(oid);
  874.             } else
  875.                 if (snmp_oid_compare
  876.                     ((oid *) var_val, var_val_len / sizeof(oid),
  877.                      uptr->privProtocol, uptr->privProtocolLen) == 0) {
  878.                 /*
  879.                  * But it's also okay to set it to the same thing as it
  880.                  * currently is.  
  881.                  */
  882.                 return SNMP_ERR_NOERROR;
  883.             } else {
  884.                 return SNMP_ERR_INCONSISTENTVALUE;
  885.             }
  886.         } else {
  887.             /*
  888.              * This row is under creation.  It's okay to set
  889.              * usmUserPrivProtocol to any valid privProtocol with the proviso
  890.              * that if usmUserAuthProtocol is set to usmNoAuthProtocol, it may
  891.              * only be set to usmNoPrivProtocol.  The value will be overwritten
  892.              * when usmUserCloneFrom is set (so don't write it if that has
  893.              * already been set).  
  894.              */
  895.             if (snmp_oid_compare(uptr->authProtocol, uptr->authProtocolLen,
  896.                                  usmNoAuthProtocol,
  897.                                  sizeof(usmNoAuthProtocol) /
  898.                                  sizeof(oid)) == 0) {
  899.                 if (snmp_oid_compare
  900.                     ((oid *) var_val, var_val_len / sizeof(oid),
  901.                      usmNoPrivProtocol,
  902.                      sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0) {
  903.                     return SNMP_ERR_INCONSISTENTVALUE;
  904.                 }
  905.             } else {
  906.                 if (snmp_oid_compare
  907.                     ((oid *) var_val, var_val_len / sizeof(oid),
  908.                      usmNoPrivProtocol,
  909.                      sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0
  910. #ifndef DISABLE_DES
  911.                     && snmp_oid_compare((oid *) var_val,
  912.                                         var_val_len / sizeof(oid),
  913.                                         usmDESPrivProtocol,
  914.                                         sizeof(usmDESPrivProtocol) /
  915.                                         sizeof(oid) != 0)
  916. #endif
  917.                     && snmp_oid_compare((oid *) var_val,
  918.                                         var_val_len / sizeof(oid),
  919.                                         usmAESPrivProtocol,
  920.                                         sizeof(usmAESPrivProtocol) /
  921.                                         sizeof(oid) != 0)) {
  922.                     return SNMP_ERR_WRONGVALUE;
  923.                 }
  924.             }
  925.             resetOnFail = 1;
  926.             optr = uptr->privProtocol;
  927.             olen = uptr->privProtocolLen;
  928.             uptr->privProtocol = snmp_duplicate_objid((oid *) var_val,
  929.                                                       var_val_len /
  930.                                                       sizeof(oid));
  931.             if (uptr->privProtocol == NULL) {
  932.                 return SNMP_ERR_RESOURCEUNAVAILABLE;
  933.             }
  934.             uptr->privProtocolLen = var_val_len / sizeof(oid);
  935.         }
  936.     } else if (action == COMMIT) {
  937.         SNMP_FREE(optr);
  938.         optr = NULL;
  939.     } else if (action == FREE || action == UNDO) {
  940.         if ((uptr = usm_parse_user(name, name_len)) != NULL) {
  941.             if (resetOnFail) {
  942.                 SNMP_FREE(uptr->privProtocol);
  943.                 uptr->privProtocol = optr;
  944.                 uptr->privProtocolLen = olen;
  945.             }
  946.         }
  947.     }
  948.     return SNMP_ERR_NOERROR;
  949. }                               /* end write_usmUserPrivProtocol() */
  950. /*
  951.  * Note: This function handles both the usmUserPrivKeyChange and
  952.  *       usmUserOwnPrivKeyChange objects.  We are not passed the name
  953.  *       of the user requseting the keychange, so we leave this to the
  954.  *       calling module to verify when and if we should be called.  To
  955.  *       change this would require a change in the mib module API to
  956.  *       pass in the securityName requesting the change.
  957.  *
  958.  */
  959. int
  960. write_usmUserPrivKeyChange(int action,
  961.                            u_char * var_val,
  962.                            u_char var_val_type,
  963.                            size_t var_val_len,
  964.                            u_char * statP, oid * name, size_t name_len)
  965. {
  966.     struct usmUser *uptr;
  967.     unsigned char   buf[SNMP_MAXBUF_SMALL];
  968.     size_t          buflen = SNMP_MAXBUF_SMALL;
  969.     const char      fnPrivKey[] = "write_usmUserPrivKeyChange";
  970.     const char      fnOwnPrivKey[] = "write_usmUserOwnPrivKeyChange";
  971.     const char     *fname;
  972.     static unsigned char *oldkey;
  973.     static size_t   oldkeylen;
  974.     static int      resetOnFail;
  975.     if (name[USM_MIB_LENGTH - 1] == 9) {
  976.         fname = fnPrivKey;
  977.     } else {
  978.         fname = fnOwnPrivKey;
  979.     }
  980.     if (action == RESERVE1) {
  981.         resetOnFail = 0;
  982.         if (var_val_type != ASN_OCTET_STR) {
  983.             DEBUGMSGTL(("usmUser", "write to %s not ASN_OCTET_STRn",
  984.                         fname));
  985.             return SNMP_ERR_WRONGTYPE;
  986.         }
  987.         if (var_val_len == 0) {
  988.             return SNMP_ERR_WRONGLENGTH;
  989.         }
  990.     } else if (action == RESERVE2) {
  991.         if ((uptr = usm_parse_user(name, name_len)) == NULL) {
  992.             return SNMP_ERR_INCONSISTENTNAME;
  993.         } else {
  994. #ifndef DISABLE_DES
  995.             if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen,
  996.                                  usmDESPrivProtocol,
  997.                                  sizeof(usmDESPrivProtocol) /
  998.                                  sizeof(oid)) == 0) {
  999.                 if (var_val_len != 0 && var_val_len != 32) {
  1000.                     return SNMP_ERR_WRONGLENGTH;
  1001.                 }
  1002.             }
  1003. #endif
  1004.             if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen,
  1005.                                  usmAESPrivProtocol,
  1006.                                  sizeof(usmAESPrivProtocol) /
  1007.                                  sizeof(oid)) == 0) {
  1008.                 if (var_val_len != 0 && var_val_len != 32) {
  1009.                     return SNMP_ERR_WRONGLENGTH;
  1010.                 }
  1011.             }
  1012.         }
  1013.     } else if (action == ACTION) {
  1014.         if ((uptr = usm_parse_user(name, name_len)) == NULL) {
  1015.             return SNMP_ERR_INCONSISTENTNAME;
  1016.         }
  1017.         if (uptr->cloneFrom == NULL) {
  1018.             return SNMP_ERR_INCONSISTENTNAME;
  1019.         }
  1020.         if (snmp_oid_compare(uptr->privProtocol, uptr->privProtocolLen,
  1021.                              usmNoPrivProtocol,
  1022.                              sizeof(usmNoPrivProtocol) / sizeof(oid)) ==
  1023.             0) {
  1024.             /*
  1025.              * "When the value of the corresponding usmUserPrivProtocol is
  1026.              * usmNoPrivProtocol, then a set is successful, but effectively
  1027.              * is a no-op."  
  1028.              */
  1029.             DEBUGMSGTL(("usmUser",
  1030.                         "%s: noPrivProtocol keyChange... success!n",
  1031.                         fname));
  1032.             return SNMP_ERR_NOERROR;
  1033.         }
  1034.         /*
  1035.          * Change the key. 
  1036.          */
  1037.         DEBUGMSGTL(("usmUser", "%s: changing priv key for user %sn",
  1038.                     fname, uptr->secName));
  1039.         if (decode_keychange(uptr->authProtocol, uptr->authProtocolLen,
  1040.                              uptr->privKey, uptr->privKeyLen,
  1041.                              var_val, var_val_len,
  1042.                              buf, &buflen) != SNMPERR_SUCCESS) {
  1043.             DEBUGMSGTL(("usmUser", "%s: ... failedn", fname));
  1044.             return SNMP_ERR_GENERR;
  1045.         }
  1046.         DEBUGMSGTL(("usmUser", "%s: ... succeededn", fname));
  1047.         resetOnFail = 1;
  1048.         oldkey = uptr->privKey;
  1049.         oldkeylen = uptr->privKeyLen;
  1050.         memdup(&uptr->privKey, buf, buflen);
  1051.         if (uptr->privKey == NULL) {
  1052.             return SNMP_ERR_RESOURCEUNAVAILABLE;
  1053.         }
  1054.         uptr->privKeyLen = buflen;
  1055.     } else if (action == COMMIT) {
  1056.         SNMP_FREE(oldkey);
  1057.         oldkey = NULL;
  1058.     } else if (action == UNDO) {
  1059.         if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) {
  1060.             SNMP_FREE(uptr->privKey);
  1061.             uptr->privKey = oldkey;
  1062.             uptr->privKeyLen = oldkeylen;
  1063.         }
  1064.     }
  1065.     return SNMP_ERR_NOERROR;
  1066. }                               /* end write_usmUserPrivKeyChange() */
  1067. int
  1068. write_usmUserPublic(int action,
  1069.                     u_char * var_val,
  1070.                     u_char var_val_type,
  1071.                     size_t var_val_len,
  1072.                     u_char * statP, oid * name, size_t name_len)
  1073. {
  1074.     struct usmUser *uptr = NULL;
  1075.     if (var_val_type != ASN_OCTET_STR) {
  1076.         DEBUGMSGTL(("usmUser",
  1077.                     "write to usmUserPublic not ASN_OCTET_STRn"));
  1078.         return SNMP_ERR_WRONGTYPE;
  1079.     }
  1080.     if (var_val_len < 0 || var_val_len > 32) {
  1081.         DEBUGMSGTL(("usmUser", "write to usmUserPublic: bad lengthn"));
  1082.         return SNMP_ERR_WRONGLENGTH;
  1083.     }
  1084.     if (action == COMMIT) {
  1085.         /*
  1086.          * don't allow creations here 
  1087.          */
  1088.         if ((uptr = usm_parse_user(name, name_len)) == NULL) {
  1089.             return SNMP_ERR_NOSUCHNAME;
  1090.         }
  1091.         if (uptr->userPublicString)
  1092.             free(uptr->userPublicString);
  1093.         uptr->userPublicString = (u_char *) malloc(var_val_len + 1);
  1094.         if (uptr->userPublicString == NULL) {
  1095.             return SNMP_ERR_GENERR;
  1096.         }
  1097.         memcpy(uptr->userPublicString, var_val, var_val_len);
  1098.         uptr->userPublicString[var_val_len] = 0;
  1099.         DEBUGMSG(("usmUser", "setting public string: %d - %sn",
  1100.                   var_val_len, uptr->userPublicString));
  1101.     }
  1102.     return SNMP_ERR_NOERROR;
  1103. }                               /* end write_usmUserPublic() */
  1104. int
  1105. write_usmUserStorageType(int action,
  1106.                          u_char * var_val,
  1107.                          u_char var_val_type,
  1108.                          size_t var_val_len,
  1109.                          u_char * statP, oid * name, size_t name_len)
  1110. {
  1111.     long            long_ret = *((long *) var_val);
  1112.     static long     oldValue;
  1113.     struct usmUser *uptr;
  1114.     static int      resetOnFail;
  1115.     if (action == RESERVE1) {
  1116.         resetOnFail = 0;
  1117.         if (var_val_type != ASN_INTEGER) {
  1118.             DEBUGMSGTL(("usmUser",
  1119.                         "write to usmUserStorageType not ASN_INTEGERn"));
  1120.             return SNMP_ERR_WRONGTYPE;
  1121.         }
  1122.         if (var_val_len != sizeof(long)) {
  1123.             DEBUGMSGTL(("usmUser",
  1124.                         "write to usmUserStorageType: bad lengthn"));
  1125.             return SNMP_ERR_WRONGLENGTH;
  1126.         }
  1127.         if (long_ret < 1 || long_ret > 5) {
  1128.             return SNMP_ERR_WRONGVALUE;
  1129.         }
  1130.     } else if (action == RESERVE2) {
  1131.         if ((uptr = usm_parse_user(name, name_len)) == NULL) {
  1132.             return SNMP_ERR_INCONSISTENTNAME;
  1133.         }
  1134.         if ((long_ret == ST_VOLATILE || long_ret == ST_NONVOLATILE) &&
  1135.             (uptr->userStorageType == ST_VOLATILE ||
  1136.              uptr->userStorageType == ST_NONVOLATILE)) {
  1137.             oldValue = uptr->userStorageType;
  1138.             uptr->userStorageType = long_ret;
  1139.             resetOnFail = 1;
  1140.         } else {
  1141.             /*
  1142.              * From RFC2574:
  1143.              * 
  1144.              * "Note that any user who employs authentication or privacy must
  1145.              * allow its secret(s) to be updated and thus cannot be 'readOnly'.
  1146.              * 
  1147.              * If an initial set operation tries to set the value to 'readOnly'
  1148.              * for a user who employs authentication or privacy, then an
  1149.              * 'inconsistentValue' error must be returned.  Note that if the
  1150.              * value has been previously set (implicit or explicit) to any
  1151.              * value, then the rules as defined in the StorageType Textual
  1152.              * Convention apply.  
  1153.              */
  1154.             DEBUGMSGTL(("usmUser",
  1155.                         "long_ret %d uptr->st %d uptr->status %dn",
  1156.                         long_ret, uptr->userStorageType,
  1157.                         uptr->userStatus));
  1158.             if (long_ret == ST_READONLY &&
  1159.                 uptr->userStorageType != ST_READONLY &&
  1160.                 (uptr->userStatus == RS_ACTIVE ||
  1161.                  uptr->userStatus == RS_NOTINSERVICE)) {
  1162.                 return SNMP_ERR_WRONGVALUE;
  1163.             } else if (long_ret == ST_READONLY &&
  1164.                        (snmp_oid_compare
  1165.                         (uptr->privProtocol, uptr->privProtocolLen,
  1166.                          usmNoPrivProtocol,
  1167.                          sizeof(usmNoPrivProtocol) / sizeof(oid)) != 0
  1168.                         || snmp_oid_compare(uptr->authProtocol,
  1169.                                             uptr->authProtocolLen,
  1170.                                             usmNoAuthProtocol,
  1171.                                             sizeof(usmNoAuthProtocol) /
  1172.                                             sizeof(oid)) != 0)) {
  1173.                 return SNMP_ERR_INCONSISTENTVALUE;
  1174.             } else {
  1175.                 return SNMP_ERR_WRONGVALUE;
  1176.             }
  1177.         }
  1178.     } else if (action == UNDO || action == FREE) {
  1179.         if ((uptr = usm_parse_user(name, name_len)) != NULL && resetOnFail) {
  1180.             uptr->userStorageType = oldValue;
  1181.         }
  1182.     }
  1183.     return SNMP_ERR_NOERROR;
  1184. }                               /* end write_usmUserStorageType() */
  1185. /*
  1186.  * Return 1 if enough objects have been set up to transition rowStatus to
  1187.  * notInService(2) or active(1).  
  1188.  */
  1189. int
  1190. usmStatusCheck(struct usmUser *uptr)
  1191. {
  1192.     if (uptr == NULL) {
  1193.         return 0;
  1194.     } else {
  1195.         if (uptr->cloneFrom == NULL) {
  1196.             return 0;
  1197.         }
  1198.     }
  1199.     return 1;
  1200. }
  1201. /*******************************************************************-o-******
  1202.  * write_usmUserStatus
  1203.  *
  1204.  * Parameters:
  1205.  *  action
  1206.  * *var_val
  1207.  *  var_val_type
  1208.  *  var_val_len
  1209.  * *statP
  1210.  * *name
  1211.  *  name_len
  1212.  *      
  1213.  * Returns:
  1214.  * SNMP_ERR_NOERROR On success.
  1215.  * SNMP_ERR_GENERR
  1216.  * SNMP_ERR_INCONSISTENTNAME
  1217.  * SNMP_ERR_INCONSISTENTVALUE
  1218.  * SNMP_ERR_WRONGLENGTH
  1219.  * SNMP_ERR_WRONGTYPE
  1220.  */
  1221. int
  1222. write_usmUserStatus(int action,
  1223.                     u_char * var_val,
  1224.                     u_char var_val_type,
  1225.                     size_t var_val_len,
  1226.                     u_char * statP, oid * name, size_t name_len)
  1227. {
  1228.     /*
  1229.      * variables we may use later 
  1230.      */
  1231.     static long     long_ret;
  1232.     unsigned char  *engineID;
  1233.     size_t          engineIDLen;
  1234.     char           *newName;
  1235.     size_t          nameLen;
  1236.     struct usmUser *uptr = NULL;
  1237.     if (action == RESERVE1) {
  1238.         if (var_val_type != ASN_INTEGER) {
  1239.             DEBUGMSGTL(("usmUser",
  1240.                         "write to usmUserStatus not ASN_INTEGERn"));
  1241.             return SNMP_ERR_WRONGTYPE;
  1242.         }
  1243.         if (var_val_len != sizeof(long_ret)) {
  1244.             DEBUGMSGTL(("usmUser",
  1245.                         "write to usmUserStatus: bad lengthn"));
  1246.             return SNMP_ERR_WRONGLENGTH;
  1247.         }
  1248.         long_ret = *((long *) var_val);
  1249.         if (long_ret == RS_NOTREADY || long_ret < 1 || long_ret > 6) {
  1250.             return SNMP_ERR_WRONGVALUE;
  1251.         }
  1252.         /*
  1253.          * See if we can parse the oid for engineID/name first.  
  1254.          */
  1255.         if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
  1256.                           &engineID, &engineIDLen, (u_char **) & newName,
  1257.                           &nameLen)) {
  1258.             return SNMP_ERR_INCONSISTENTNAME;
  1259.         }
  1260.         if (engineIDLen < 5 || engineIDLen > 32 || nameLen < 1
  1261.             || nameLen > 32) {
  1262.             SNMP_FREE(engineID);
  1263.             SNMP_FREE(newName);
  1264.             return SNMP_ERR_NOCREATION;
  1265.         }
  1266.         /*
  1267.          * Now see if a user already exists with these index values. 
  1268.          */
  1269.         uptr = usm_get_user(engineID, engineIDLen, newName);
  1270.         if (uptr != NULL) {
  1271.             if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
  1272.                 SNMP_FREE(engineID);
  1273.                 SNMP_FREE(newName);
  1274.                 long_ret = RS_NOTREADY;
  1275.                 return SNMP_ERR_INCONSISTENTVALUE;
  1276.             }
  1277.             SNMP_FREE(engineID);
  1278.             SNMP_FREE(newName);
  1279.         } else {
  1280.             if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) {
  1281.                 SNMP_FREE(engineID);
  1282.                 SNMP_FREE(newName);
  1283.                 return SNMP_ERR_INCONSISTENTVALUE;
  1284.             }
  1285.             if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
  1286.                 if ((uptr = usm_create_user()) == NULL) {
  1287.                     SNMP_FREE(engineID);
  1288.                     SNMP_FREE(newName);
  1289.                     return SNMP_ERR_RESOURCEUNAVAILABLE;
  1290.                 }
  1291.                 uptr->engineID = engineID;
  1292.                 uptr->name = newName;
  1293.                 uptr->secName = strdup(uptr->name);
  1294.                 if (uptr->secName == NULL) {
  1295.                     usm_free_user(uptr);
  1296.                     return SNMP_ERR_RESOURCEUNAVAILABLE;
  1297.                 }
  1298.                 uptr->engineIDLen = engineIDLen;
  1299.                 /*
  1300.                  * Set status to createAndGo or createAndWait so we can tell
  1301.                  * that this row is under creation.  
  1302.                  */
  1303.                 uptr->userStatus = long_ret;
  1304.                 /*
  1305.                  * Add to the list of users (we will take it off again
  1306.                  * later if something goes wrong).  
  1307.                  */
  1308.                 usm_add_user(uptr);
  1309.             } else {
  1310.                 SNMP_FREE(engineID);
  1311.                 SNMP_FREE(newName);
  1312.             }
  1313.         }
  1314.     } else if (action == ACTION) {
  1315.         usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
  1316.                       &engineID, &engineIDLen, (u_char **) & newName,
  1317.                       &nameLen);
  1318.         uptr = usm_get_user(engineID, engineIDLen, newName);
  1319.         SNMP_FREE(engineID);
  1320.         SNMP_FREE(newName);
  1321.         if (uptr != NULL) {
  1322.             if (long_ret == RS_CREATEANDGO || long_ret == RS_ACTIVE) {
  1323.                 if (usmStatusCheck(uptr)) {
  1324.                     uptr->userStatus = RS_ACTIVE;
  1325.                 } else {
  1326.                     SNMP_FREE(engineID);
  1327.                     SNMP_FREE(newName);
  1328.                     return SNMP_ERR_INCONSISTENTVALUE;
  1329.                 }
  1330.             } else if (long_ret == RS_CREATEANDWAIT) {
  1331.                 if (usmStatusCheck(uptr)) {
  1332.                     uptr->userStatus = RS_NOTINSERVICE;
  1333.                 } else {
  1334.                     uptr->userStatus = RS_NOTREADY;
  1335.                 }
  1336.             } else if (long_ret == RS_NOTINSERVICE) {
  1337.                 if (uptr->userStatus == RS_ACTIVE ||
  1338.                     uptr->userStatus == RS_NOTINSERVICE) {
  1339.                     uptr->userStatus = RS_NOTINSERVICE;
  1340.                 } else {
  1341.                     return SNMP_ERR_INCONSISTENTVALUE;
  1342.                 }
  1343.             }
  1344.         }
  1345.     } else if (action == COMMIT) {
  1346.         usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
  1347.                       &engineID, &engineIDLen, (u_char **) & newName,
  1348.                       &nameLen);
  1349.         uptr = usm_get_user(engineID, engineIDLen, newName);
  1350.         SNMP_FREE(engineID);
  1351.         SNMP_FREE(newName);
  1352.         if (uptr != NULL) {
  1353.             if (long_ret == RS_DESTROY) {
  1354.                 usm_remove_user(uptr);
  1355.                 usm_free_user(uptr);
  1356.             }
  1357.         }
  1358.     } else if (action == UNDO || action == FREE) {
  1359.         usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
  1360.                       &engineID, &engineIDLen, (u_char **) & newName,
  1361.                       &nameLen);
  1362.         uptr = usm_get_user(engineID, engineIDLen, newName);
  1363.         SNMP_FREE(engineID);
  1364.         SNMP_FREE(newName);
  1365.         if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
  1366.             usm_remove_user(uptr);
  1367.             usm_free_user(uptr);
  1368.         }
  1369.     }
  1370.     return SNMP_ERR_NOERROR;
  1371. }
  1372. #if 0
  1373.     /*
  1374.      * see if we can parse the oid for engineID/name first 
  1375.      */
  1376. if (usm_parse_oid(&name[USM_MIB_LENGTH], name_len - USM_MIB_LENGTH,
  1377.                   &engineID, &engineIDLen, (u_char **) & newName,
  1378.                   &nameLen))
  1379.     return SNMP_ERR_INCONSISTENTNAME;
  1380.     /*
  1381.      * Now see if a user already exists with these index values 
  1382.      */
  1383. uptr = usm_get_user(engineID, engineIDLen, newName);
  1384. if (uptr) {                     /* If so, we set the appropriate value... */
  1385.     free(engineID);
  1386.     free(newName);
  1387.     if (long_ret == RS_CREATEANDGO || long_ret == RS_CREATEANDWAIT) {
  1388.         return SNMP_ERR_INCONSISTENTVALUE;
  1389.     }
  1390.     if (long_ret == RS_DESTROY) {
  1391.         usm_remove_user(uptr);
  1392.         usm_free_user(uptr);
  1393.     } else {
  1394.         uptr->userStatus = long_ret;
  1395.     }
  1396. } else {                        /* ...else we create a new user */
  1397.     /*
  1398.      * check for a valid status column set 
  1399.      */
  1400.     if (long_ret == RS_ACTIVE || long_ret == RS_NOTINSERVICE) {
  1401.         free(engineID);
  1402.         free(newName);
  1403.         return SNMP_ERR_INCONSISTENTVALUE;
  1404.     }
  1405.     if (long_ret == RS_DESTROY) {
  1406.         /*
  1407.          * destroying a non-existent row is actually legal 
  1408.          */
  1409.         free(engineID);
  1410.         free(newName);
  1411.         return SNMP_ERR_NOERROR;
  1412.     }
  1413.     /*
  1414.      * generate a new user 
  1415.      */
  1416.     if ((uptr = usm_create_user()) == NULL) {
  1417.         free(engineID);
  1418.         free(newName);
  1419.         return SNMP_ERR_GENERR;
  1420.     }
  1421.     /*
  1422.      * copy in the engineID 
  1423.      */
  1424.     uptr->engineID = (unsigned char *) malloc(engineIDLen);
  1425.     if (uptr->engineID == NULL) {
  1426.         free(engineID);
  1427.         free(newName);
  1428.         usm_free_user(uptr);
  1429.         return SNMP_ERR_GENERR;
  1430.     }
  1431.     uptr->engineIDLen = engineIDLen;
  1432.     memcpy(uptr->engineID, engineID, engineIDLen);
  1433.     free(engineID);
  1434.     /*
  1435.      * copy in the name and secname 
  1436.      */
  1437.     if ((uptr->name = strdup(newName)) == NULL) {
  1438.         free(newName);
  1439.         usm_free_user(uptr);
  1440.         return SNMP_ERR_GENERR;
  1441.     }
  1442.     free(newName);
  1443.     if ((uptr->secName = strdup(uptr->name)) == NULL) {
  1444.         usm_free_user(uptr);
  1445.         return SNMP_ERR_GENERR;
  1446.     }
  1447.     /*
  1448.      * set the status of the row based on the request 
  1449.      */
  1450.     if (long_ret == RS_CREATEANDGO)
  1451.         uptr->userStatus = RS_ACTIVE;
  1452.     else if (long_ret == RS_CREATEANDWAIT)
  1453.         uptr->userStatus = RS_NOTINSERVICE;
  1454.     /*
  1455.      * finally, add it to our list of users 
  1456.      */
  1457.     usm_add_user(uptr);
  1458. }                               /* endif -- uptr */
  1459. }                               /* endif -- action==COMMIT */
  1460. return SNMP_ERR_NOERROR;
  1461. }                               /* end write_usmUserStatus() */
  1462. #endif