⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snmpusm.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	{
		if ( usm_check_and_update_timeliness (
			secEngineID, *secEngineIDLen,
			boots_uint, time_uint, &error) == -1 )
		{
			return error;
		}
	}

#ifdef							LCD_TIME_SYNC_OPT	
	/* 
	 * Cache the unauthenticated time to use in case we don't have
	 * anything better - this guess will be no worse than (0,0)
	 * that we normally use.
	 */
        else 
        {
		set_enginetime(secEngineID, *secEngineIDLen, 
			 			boots_uint, time_uint, FALSE);
        }
#endif							/* LCD_TIME_SYNC_OPT */


	/* 
	 * If needed, decrypt the scoped PDU.
	 */
	if (secLevel == SNMP_SEC_LEVEL_AUTHPRIV)
	{
		remaining = wholeMsgLen - (data_ptr - wholeMsg);

		if ((value_ptr = asn_parse_sequence (data_ptr, &remaining,
			&type_value,
			(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
			"encrypted sPDU")) == NULL)
		{
			DEBUGMSGTL(("usm","%s\n",
				"Failed while parsing encrypted sPDU."));
			if (snmp_increment_statistic
						(STAT_SNMPINASNPARSEERRS)==0)
			{
				DEBUGMSGTL(("usm","%s\n",
					"Failed increment statistic."));
			}
			return SNMPERR_USM_PARSEERROR;
		}

		end_of_overhead = value_ptr;

                /* 
                 * XOR the salt with the last (iv_length) bytes
                 * of the priv_key to obtain the IV.
                 */
                for (i = 0; i < (int)iv_length; i++)
                  iv[i] = salt[i] ^ user->privKey[iv_length + i];
                
		if (sc_decrypt (
			 user->privProtocol,	user->privProtocolLen,
			 user->privKey,		user->privKeyLen,
			 iv,			iv_length,
			 value_ptr,		remaining,
			*scopedPdu,		scopedPduLen) 
							!= SNMP_ERR_NOERROR)
		{
			DEBUGMSGTL(("usm","%s\n", "Failed decryption."));
			if (snmp_increment_statistic
					(STAT_USMSTATSDECRYPTIONERRORS)==0)
			{
				DEBUGMSGTL(("usm","%s\n",
					"Failed increment statistic."));
			}
			return SNMPERR_USM_DECRYPTIONERROR;
		}

#ifdef SNMP_TESTING_CODE
		if ( debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
			dump_chunk("usm/dump", "Decrypted chunk:",
						*scopedPdu, *scopedPduLen);
			dump_chunk("usm/dump", "IV + Encrypted form:",
						salt, salt_length);
			dump_chunk("usm/dump", NULL,
						value_ptr, remaining);
		}
#endif
	}

	/* 
	 * sPDU is plaintext.
	 */
	else
	{
		*scopedPdu	= data_ptr;
		*scopedPduLen	= wholeMsgLen - (data_ptr - wholeMsg);
		end_of_overhead	= data_ptr;

	}  /* endif -- PDU decryption */


	/* 
	 * Calculate the biggest sPDU for the response (i.e., whole - ovrhd).
	 *
	 * FIX  Correct? 
	 */
	*maxSizeResponse = maxMsgSize - (int)
				((u_long)end_of_overhead - (u_long)wholeMsg);


	DEBUGMSGTL(("usm","USM processing completed.\n"));

	return SNMPERR_SUCCESS;

}  /* end usm_process_in_msg() */

void
init_usm(void) {
  snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG,
                         init_usm_post_config, NULL);
}

/* 
 * initializations for the USM.
 *
 * Should be called after the configuration files have been read.
 *
 * Set "arbitrary" portion of salt to a random number.
 */
int
init_usm_post_config(int majorid, int minorid, void *serverarg,
                     void *clientarg) {
  size_t	salt_integer_len = sizeof(salt_integer);

  initialUser = usm_create_initial_user("initial", usmHMACMD5AuthProtocol,
                                        USM_LENGTH_OID_TRANSFORM,
                                        usmDESPrivProtocol,
                                        USM_LENGTH_OID_TRANSFORM);
  SNMP_FREE(initialUser->engineID);
  initialUser->engineIDLen = 0;

  if ( sc_random((u_char *) &salt_integer, &salt_integer_len) != SNMPERR_SUCCESS )
  {
	DEBUGMSGTL(("usm","sc_random() failed: using time() as salt.\n"));
	salt_integer	 = (u_int) time(NULL);
	salt_integer_len = sizeof(salt_integer);
  }

  noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol,
                                        USM_LENGTH_OID_TRANSFORM,
                                        usmDESPrivProtocol,
                                        USM_LENGTH_OID_TRANSFORM);
  SNMP_FREE(noNameUser->engineID);
  noNameUser->engineIDLen = 0;

  return SNMPERR_SUCCESS;
}  /* end init_usm_post_config() */
 

/* 
 * Local storage (LCD) of the default user list.
 */
static struct usmUser *userList=NULL;

struct usmUser *
usm_get_userList(void)
{
  return userList;
}



/*******************************************************************-o-******
 * usm_check_secLevel
 *
 * Parameters:
 *	 level
 *	*user
 *      
 * Returns:
 *	0	On success,
 *	-1	Otherwise.
 *
 * Checks that a given security level is valid for a given user.
 */
int
usm_check_secLevel(int level, struct usmUser *user)
{

  if ( level == SNMP_SEC_LEVEL_AUTHPRIV
	&& (snmp_oid_compare(user->privProtocol, user->privProtocolLen,
		usmNoPrivProtocol, sizeof(usmNoPrivProtocol)/sizeof(oid))==0) )
  {
    return 1;
  } 
  if ( (level == SNMP_SEC_LEVEL_AUTHPRIV || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
	&& (snmp_oid_compare(user->authProtocol, user->authProtocolLen,
		usmNoAuthProtocol, sizeof(usmNoAuthProtocol)/sizeof(oid))==0) )
  {
    return 1;
  }

  return 0;

}  /* end usm_check_secLevel() */




/*******************************************************************-o-******
 * usm_check_secLevel_vs_protocols
 *
 * Parameters:
 *	 level
 *	*authProtocol
 *	 authProtocolLen
 *	*privProtocol
 *	 privProtocolLen
 *      
 * Returns:
 *	0	On success,
 *	-1	Otherwise.
 *
 * Same as above but with explicitly named transform types instead of taking
 * from the usmUser structure.
 */
int
usm_check_secLevel_vs_protocols(int level,
	oid *authProtocol, u_int authProtocolLen,
	oid *privProtocol, u_int privProtocolLen)
{

  if ( level == SNMP_SEC_LEVEL_AUTHPRIV
	&& (snmp_oid_compare(privProtocol, privProtocolLen, usmNoPrivProtocol,
              			sizeof(usmNoPrivProtocol)/sizeof(oid))==0) )
  {
    return 1;
  }
  if ( (level == SNMP_SEC_LEVEL_AUTHPRIV || level == SNMP_SEC_LEVEL_AUTHNOPRIV)
	&& (snmp_oid_compare(authProtocol, authProtocolLen, usmNoAuthProtocol,
              			sizeof(usmNoAuthProtocol)/sizeof(oid))==0) )
  {
    return 1;
  }

  return 0;

}  /* end usm_check_secLevel_vs_protocols() */


/* usm_update_engine_time(): Updates engine_time for all registered users. 
 * This function would be useful for systems that start up with default time
 * settings and then update their timing reference using NTP at a later stage
 */
void usm_update_engine_time(void) {

  struct usmUser *ptr;
  long            boots_long;
  long            time_long;

  boots_long = snmpv3_local_snmpEngineBoots();
  time_long  = snmpv3_local_snmpEngineTime();

  for (ptr = userList; ptr != NULL; ptr = ptr->next) {
    set_enginetime( ptr->engineID, ptr->engineIDLen, 
                    boots_long, time_long, TRUE );
  }
}


/* usm_get_user(): Returns a user from userList based on the engineID,
   engineIDLen and name of the requested user. */

struct usmUser *
usm_get_user(u_char *engineID, size_t engineIDLen, char *name)
{
  DEBUGMSGTL(("usm","getting user %s\n", name));
  return usm_get_user_from_list(engineID, engineIDLen, name, userList, 1);
}

struct usmUser *
usm_get_user_from_list(u_char *engineID, size_t engineIDLen,
                       char *name, struct usmUser *puserList, int use_default)
{
  struct usmUser *ptr;
  char noName[] = "";
  if (name == NULL)
    name = noName;
  for (ptr = puserList; ptr != NULL; ptr = ptr->next) {
    if (!strcmp(ptr->name, name) &&
        ptr->engineIDLen == engineIDLen &&
        ((ptr->engineID == NULL && engineID == NULL) ||
         (ptr->engineID != NULL && engineID != NULL &&
          memcmp(ptr->engineID, engineID, engineIDLen) == 0)))
      return ptr;
  }
  /* return "" user used to facilitate engineID discovery */
  if (use_default && !strcmp(name, "")) return noNameUser;
  /* this next line may be vestigial from when the draft used 'initial'
     to discover engineID, also did not remove creation if 'inital' user
     -gsm 2/6/99 */
  if (use_default && !strcmp(name, "initial")) return initialUser;
  return NULL;
}

/* usm_add_user(): Add's a user to the userList, sorted by the
   engineIDLength then the engineID then the name length then the name
   to facilitate getNext calls on a usmUser table which is indexed by
   these values.

   Note: userList must not be NULL (obviously), as thats a rather trivial
   addition and is left to the API user.

   returns the head of the list (which could change due to this add).
*/

struct usmUser *
usm_add_user(struct usmUser *user)
{
  struct usmUser *uptr;
  uptr = usm_add_user_to_list(user, userList);
  if (uptr != NULL)
    userList = uptr;
  return uptr;
}

struct usmUser *
usm_add_user_to_list(struct usmUser *user,
                                     struct usmUser *puserList)
{
  struct usmUser *nptr, *pptr;

  /* loop through puserList till we find the proper, sorted place to
     insert the new user */
  for (nptr = puserList, pptr = NULL; nptr != NULL;
       pptr = nptr, nptr = nptr->next) {
    if (nptr->engineIDLen > user->engineIDLen)
      break;

    if (user->engineID == NULL && nptr->engineID != NULL)
      break;
    
    if (nptr->engineIDLen == user->engineIDLen &&
        (nptr->engineID != NULL && user->engineID != NULL &&
         memcmp(nptr->engineID, user->engineID, user->engineIDLen) > 0))
      break;

    if (!(nptr->engineID == NULL && user->engineID != NULL)) {
      if (nptr->engineIDLen == user->engineIDLen &&
          ((nptr->engineID == NULL && user->engineID == NULL) ||
           memcmp(nptr->engineID, user->engineID, user->engineIDLen) == 0) &&
          strlen(nptr->name) > strlen(user->name))
        break;

      if (nptr->engineIDLen == user->engineIDLen &&
          ((nptr->engineID == NULL && user->engineID == NULL) ||
           memcmp(nptr->engineID, user->engineID, user->engineIDLen) == 0) &&
          strlen(nptr->name) == strlen(user->name) &&
          strcmp(nptr->name, user->name) > 0)
        break;

      if (nptr->engineIDLen == user->engineIDLen &&
          ((nptr->engineID == NULL && user->engineID == NULL) ||
           memcmp(nptr->engineID, user->engineID, user->engineIDLen) == 0) &&
          strlen(nptr->name) == strlen(user->name) &&
          strcmp(nptr->name, user->name) == 0)
        /* the user is an exact match of a previous entry.  Bail */
        return NULL;
    }
  }

  /* nptr should now point to the user that we need to add ourselves
     in front of, and pptr should be our new 'prev'. */

  /* change our pointers */
  user->prev = pptr;
  user->next = nptr;

  /* change the next's prev pointer */
  if (user->next)
    user->next->prev = user;

  /* change the prev's next pointer */
  if (user->prev)
    user->prev->next = user;

  /* rewind to the head of the list and return it (since the new head
     could be us, we need to notify the above routine who the head now is. */
  for(pptr = user; pptr->prev != NULL; pptr = pptr->prev);
  return pptr;
}

/* usm_remove_user(): finds and removes a user from a list */
struct usmUser *
usm_remove_user(struct usmUser *user)
{
  return usm_remove_user_from_list(user, &userList);
}

struct usmUser *
usm_remove_user_from_list(struct usmUser *user,
                                          struct usmUser **ppuserList)
{
  struct usmUser *nptr, *pptr;

  /* NULL pointers aren't allowed */
  if (ppuserList == NULL)
    return NULL;

  /* find the user in the list */
  for (nptr = *ppuserList, pptr = NULL; nptr != NULL;
       pptr = nptr, nptr = nptr->next) {
    if (nptr == user)
      break;
  }

  if (nptr) {
    /* remove the user from the linked list */
    if (pptr) {
      pptr->next = nptr->next;
    }
    if (nptr->next) {
      nptr->next->prev = pptr;
    }
  } else {
    /* user didn't exit */
    return NULL;
  }
  if (nptr == *ppuserList) /* we're the head of the list, need to change
                            the head to the next user */
    *ppuserList = nptr->next;
  return *ppuserList;
}  /* end usm_remove_user_from_list() */




/* usm_free_user():  calls free() on all needed parts of struct usmUser and
   the user himself.

   Note: This should *not* be called on an object in a list (IE,
   remove it from the list first, and set next and prev to NULL), but
   will try to reconnect the list pieces again if it is called this
   way.  If called on the head of the list, the entire list will be
   lost. */
struct usmUser *
usm_free_user(struct usmUser *user)
{
  if (user == NULL)
    return NULL;

  SNMP_FREE(user->engineID);
  SNMP_FREE(user->name);
  SNMP_FREE(user->secName);
  SNMP_FREE(user->cloneFrom);
  SNMP_FREE(user->userPublicString);
  SNMP_FREE(user->authProtocol);
  SNMP_FREE(user->privProtocol);

  if (user->authKey != NULL) {
    SNMP_ZERO(user->authKey, user->authKeyLen);
    SNMP_FREE(user->authKey);
  }

  if (user->privKey != NULL) {
    SNMP_ZERO(user->privKey, user->privKeyLen);
    SNMP_FREE(user->privKey);
  }


  /* FIX  Why not put this check *first?*
   */
  if (user->prev != NULL) { /* ack, this shouldn't happen */
    user->prev->next = user->next;
  }
  if (user->next != NULL) {
    user->next->prev = user->prev;
    if (user->prev != NULL) /* ack this is really bad, because it means
                              we'll loose the head of some structure tree */
      DEBUGMSGTL(("usm","Severe: Asked to free 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -