📄 snmp_agent.c
字号:
allDone = TRUE; /* Check for some content */
for ( var_ptr = asp->start;
var_ptr != asp->end->next_variable;
var_ptr = var_ptr->next_variable ) {
/* XXX: we don't know the size of the next
OID, so assume the maximum length */
if ( var_ptr->type != SNMP_ENDOFMIBVIEW )
{
var_ptr2 = snmp_add_null_var(asp->pdu, var_ptr->name, MAX_OID_LEN);
for ( i=var_ptr->name_length ; i<MAX_OID_LEN ; i++)
var_ptr2->name[i] = 0;
var_ptr2->name_length = var_ptr->name_length;
allDone = FALSE;
}
}
if ( allDone )
break;
asp->start = asp->end->next_variable;
while ( asp->end->next_variable != NULL )
asp->end = asp->end->next_variable;
status = handle_next_pass( asp );
if ( status != SNMP_ERR_NOERROR )
break;
if ( asp->outstanding_requests != NULL )
return 1;
}
break;
case SNMP_MSG_SET:
/*
* SETS require 3-4 passes through the var_op_list. The first two
* passes verify that all types, lengths, and values are valid
* and may reserve resources and the third does the set and a
* fourth executes any actions. Then the identical GET RESPONSE
* packet is returned.
* If either of the first two passes returns an error, another
* pass is made so that any reserved resources can be freed.
* If the third pass returns an error, another pass is made so that
* any changes can be reversed.
* If the fourth pass (or any of the error handling passes)
* return an error, we'd rather not know about it!
*/
if ( asp->mode == RESERVE1 ) {
snmp_increment_statistic(STAT_SNMPINSETREQUESTS);
asp->rw = WRITE;
status = handle_next_pass( asp );
if ( status != SNMP_ERR_NOERROR )
asp->mode = FREE;
else
asp->mode = RESERVE2;
if ( asp->outstanding_requests != NULL )
return 1;
}
if ( asp->mode == RESERVE2 ) {
status = handle_next_pass( asp );
if ( status != SNMP_ERR_NOERROR )
asp->mode = FREE;
else
asp->mode = ACTION;
if ( asp->outstanding_requests != NULL )
return 1;
}
if ( asp->mode == ACTION ) {
status = handle_next_pass( asp );
if ( status != SNMP_ERR_NOERROR )
asp->mode = UNDO;
else
asp->mode = COMMIT;
if ( asp->outstanding_requests != NULL )
return 1;
}
if ( asp->mode == COMMIT ) {
status = handle_next_pass( asp );
if ( status != SNMP_ERR_NOERROR ) {
status = SNMP_ERR_COMMITFAILED;
asp->mode = FINISHED_FAILURE;
}
else
asp->mode = FINISHED_SUCCESS;
if ( asp->outstanding_requests != NULL )
return 1;
}
if ( asp->mode == UNDO ) {
if (handle_next_pass( asp ) != SNMP_ERR_NOERROR )
status = SNMP_ERR_UNDOFAILED;
asp->mode = FINISHED_FAILURE;
break;
}
if ( asp->mode == FREE ) {
(void) handle_next_pass( asp );
break;
}
break;
case SNMP_MSG_RESPONSE:
snmp_increment_statistic(STAT_SNMPINGETRESPONSES);
free( asp );
return 0;
case SNMP_MSG_TRAP:
case SNMP_MSG_TRAP2:
snmp_increment_statistic(STAT_SNMPINTRAPS);
free( asp );
return 0;
default:
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
free( asp );
return 0;
}
if ( asp->outstanding_requests != NULL ) {
asp->status = status;
asp->next = agent_session_list;
agent_session_list = asp;
}
else {
/*
* May need to "dumb down" a SET error status for a
* v1 query. See RFC2576 - section 4.3
*/
if (( asp->pdu->command == SNMP_MSG_SET ) &&
( asp->pdu->version == SNMP_VERSION_1 )) {
switch ( status ) {
case SNMP_ERR_WRONGVALUE:
case SNMP_ERR_WRONGENCODING:
case SNMP_ERR_WRONGTYPE:
case SNMP_ERR_WRONGLENGTH:
case SNMP_ERR_INCONSISTENTVALUE:
status = SNMP_ERR_BADVALUE;
break;
case SNMP_ERR_NOACCESS:
case SNMP_ERR_NOTWRITABLE:
case SNMP_ERR_NOCREATION:
case SNMP_ERR_INCONSISTENTNAME:
case SNMP_ERR_AUTHORIZATIONERROR:
status = SNMP_ERR_NOSUCHNAME;
break;
case SNMP_ERR_RESOURCEUNAVAILABLE:
case SNMP_ERR_COMMITFAILED:
case SNMP_ERR_UNDOFAILED:
status = SNMP_ERR_GENERR;
break;
}
}
/*
* Similarly we may need to "dumb down" v2 exception
* types to throw an error for a v1 query.
* See RFC2576 - section 4.1.2.3
*/
if (( asp->pdu->command != SNMP_MSG_SET ) &&
( asp->pdu->version == SNMP_VERSION_1 )) {
for ( var_ptr = asp->pdu->variables, i=0 ;
var_ptr != NULL ;
var_ptr = var_ptr->next_variable, i++ ) {
switch ( var_ptr->type ) {
case SNMP_NOSUCHOBJECT:
case SNMP_NOSUCHINSTANCE:
case SNMP_ENDOFMIBVIEW:
case ASN_COUNTER64:
status = SNMP_ERR_NOSUCHNAME;
asp->pdu->errindex=i;
break;
}
}
}
if ( status == SNMP_ERR_NOERROR ) {
snmp_increment_statistic_by(
(asp->pdu->command == SNMP_MSG_SET ?
STAT_SNMPINTOTALSETVARS : STAT_SNMPINTOTALREQVARS ),
count_varbinds( asp->pdu ));
}
else {
/*
* Use a copy of the original request
* to report failures.
*/
i = asp->pdu->errindex;
snmp_free_pdu( asp->pdu );
asp->pdu = snmp_clone_pdu( pdu );
asp->pdu->errindex = i;
}
asp->pdu->command = SNMP_MSG_RESPONSE;
asp->pdu->errstat = status;
snmp_send( asp->session, asp->pdu );
snmp_increment_statistic(STAT_SNMPOUTPKTS);
snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES);
free( asp );
}
return 1;
}
int
handle_next_pass(struct agent_snmp_session *asp)
{
int status;
struct snmp_pdu *pdu = asp->pdu;
struct request_list *req_p, *next_req;
if ( asp->outstanding_requests != NULL )
return SNMP_ERR_NOERROR;
status = handle_var_list( asp );
if ( asp->outstanding_requests != NULL ) {
if ( status == SNMP_ERR_NOERROR ) {
/* Send out any subagent requests */
for ( req_p = asp->outstanding_requests ;
req_p != NULL ; req_p = req_p->next_request ) {
snmp_async_send( req_p->session, req_p->pdu,
req_p->callback, req_p->cb_data );
}
asp->pdu = snmp_clone_pdu( pdu );
asp->pdu->variables = pdu->variables;
pdu->variables = NULL;
}
else {
/* discard outstanding requests */
for ( req_p = asp->outstanding_requests ;
req_p != NULL ; req_p = next_req ) {
next_req = req_p->next_request;
free( req_p );
}
asp->outstanding_requests = NULL;
}
}
return status;
}
int
handle_var_list(struct agent_snmp_session *asp)
{
struct variable_list *varbind_ptr;
u_char statType;
u_char *statP;
size_t statLen;
u_short acl;
WriteMethod *write_method;
AddVarMethod *add_method;
int noSuchObject = TRUE;
int count, view;
count = 0;
varbind_ptr = asp->start;
if ( !varbind_ptr ) {
return SNMP_ERR_NOERROR;
}
while (1) {
count++;
statp_loop:
statP = getStatPtr( varbind_ptr->name,
&varbind_ptr->name_length,
&statType, &statLen, &acl,
asp->exact, &write_method, asp->pdu, &noSuchObject);
if (statP == NULL && (asp->rw != WRITE || write_method == NULL)) {
/* Careful -- if the varbind was lengthy, it will have
allocated some memory. */
snmp_set_var_value(varbind_ptr, NULL, 0);
varbind_ptr->val.integer = NULL;
varbind_ptr->val_len = 0;
if ( asp->exact ) {
if ( noSuchObject == TRUE ){
statType = SNMP_NOSUCHOBJECT;
} else {
statType = SNMP_NOSUCHINSTANCE;
}
} else {
statType = SNMP_ENDOFMIBVIEW;
}
if (asp->pdu->version == SNMP_VERSION_1) {
asp->pdu->errstat = SNMP_ERR_NOSUCHNAME;
asp->pdu->errindex = count;
return SNMP_ERR_NOSUCHNAME;
}
else if (asp->rw == WRITE) {
asp->pdu->errstat =
( noSuchObject ? SNMP_ERR_NOTWRITABLE
: SNMP_ERR_NOCREATION );
asp->pdu->errindex = count;
return asp->pdu->errstat;
}
else
varbind_ptr->type = statType;
}
/* Delegated variables should be added to the
relevant outgoing request */
else if ( IS_DELEGATED(statType)) {
add_method = (AddVarMethod*)statP;
statType = (*add_method)( asp, varbind_ptr );
}
/* GETNEXT/GETBULK should just skip inaccessible entries */
else if ((view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
asp->pdu, varbind_ptr->type))
&& !asp->exact) {
if (view != 5) send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
goto statp_loop;
}
/* Other access problems are permanent */
else if (( asp->rw == WRITE && !(acl & 2)) || view) {
if (asp->pdu->version == SNMP_VERSION_1 || asp->rw != WRITE) {
if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE))
DEBUGMSGTL(("snmp_agent", " >> noSuchName (read-only)\n"));
ERROR_MSG("read-only");
statType = SNMP_ERR_NOSUCHNAME;
}
else {
if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE))
DEBUGMSGTL(("snmp_agent", " >> notWritable\n"));
ERROR_MSG("Not Writable");
statType = SNMP_ERR_NOTWRITABLE;
}
asp->pdu->errstat = statType;
asp->pdu->errindex = count;
send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
return statType;
}
else {
/* dump verbose info */
if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE) && statP)
dump_var(varbind_ptr->name, varbind_ptr->name_length,
statType, statP, statLen);
/* FINALLY we can act on SET requests ....*/
if ( asp->rw == WRITE ) {
if ( write_method != NULL ) {
statType = (*write_method)(asp->mode,
varbind_ptr->val.string,
varbind_ptr->type,
varbind_ptr->val_len, statP,
varbind_ptr->name,
varbind_ptr->name_length);
if (statType != SNMP_ERR_NOERROR) {
asp->pdu->errstat = statType;
asp->pdu->errindex = count;
return statType;
}
}
else {
if (!goodValue(varbind_ptr->type, varbind_ptr->val_len,
statType, statLen)){
if (asp->pdu->version == SNMP_VERSION_1)
statType = SNMP_ERR_BADVALUE;
else
statType = SNMP_ERR_WRONGTYPE; /* poor approximation */
asp->pdu->errstat = statType;
asp->pdu->errindex = count;
return statType;
}
/* actually do the set if necessary */
if (asp->mode == COMMIT)
setVariable(varbind_ptr->val.string, varbind_ptr->type,
varbind_ptr->val_len, statP, statLen);
}
}
/* ... or save the results from assorted GETs */
else {
snmp_set_var_value(varbind_ptr, statP, statLen);
varbind_ptr->type = statType;
}
}
if ( varbind_ptr == asp->end )
return SNMP_ERR_NOERROR;
varbind_ptr = varbind_ptr->next_variable;
if ( asp->mode == RESERVE1 )
snmp_vars_inc++;
}
}
static int
goodValue(u_char inType,
size_t inLen,
u_char actualType,
size_t actualLen)
{
if (inLen > actualLen)
return FALSE;
return (inType == actualType);
}
static void
setVariable(u_char *var_val,
u_char var_val_type,
size_t var_val_len,
u_char *statP,
size_t statLen)
{
size_t buffersize = 1000;
switch(var_val_type){
case ASN_INTEGER:
asn_parse_int(var_val, &buffersize, &var_val_type, (long *)statP, statLen);
break;
case ASN_COUNTER:
case ASN_GAUGE:
case ASN_TIMETICKS:
asn_parse_unsigned_int(var_val, &buffersize, &var_val_type, (u_long *)statP, statLen);
break;
case ASN_COUNTER64:
asn_parse_unsigned_int64(var_val, &buffersize, &var_val_type,
(struct counter64 *)statP, statLen);
break;
case ASN_OCTET_STR:
case ASN_IPADDRESS:
case ASN_OPAQUE:
case ASN_NSAP:
asn_parse_string(var_val, &buffersize, &var_val_type, statP, &statLen);
break;
case ASN_OBJECT_ID:
asn_parse_objid(var_val, &buffersize, &var_val_type, (oid *)statP, &statLen);
break;
case ASN_BIT_STR:
asn_parse_bitstring(var_val, &buffersize, &var_val_type, statP, &statLen);
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -