00001 /* 00002 * table.c 00003 */ 00004 00005 #include <config.h> 00006 00007 #if HAVE_STRING_H 00008 #include <string.h> 00009 #else 00010 #include <strings.h> 00011 #endif 00012 #include <assert.h> 00013 00014 #include "mibincl.h" 00015 #include "tools.h" 00016 #include "snmp_agent.h" 00017 #include "table.h" 00018 00019 #if HAVE_DMALLOC_H 00020 #include <dmalloc.h> 00021 #endif 00022 00023 00024 mib_handler * 00025 get_table_handler(table_registration_info * tabreq) 00026 { 00027 mib_handler *ret = NULL; 00028 00029 if (!tabreq) { 00030 snmp_log(LOG_INFO, "get_table_handler(NULL) called\n"); 00031 return NULL; 00032 } 00033 00034 ret = create_handler("table", table_helper_handler); 00035 if (ret) { 00036 ret->myvoid = (void *) tabreq; 00037 tabreq->number_indexes = count_varbinds(tabreq->indexes); 00038 } 00039 return ret; 00040 } 00041 00042 00043 int 00044 register_table(handler_registration * reginfo, 00045 table_registration_info * tabreq) 00046 { 00047 inject_handler(reginfo, get_table_handler(tabreq)); 00048 return register_handler(reginfo); 00049 } 00050 00051 static void 00052 table_helper_cleanup(agent_request_info * reqinfo, request_info * request, 00053 int status) 00054 { 00055 00056 set_request_error(reqinfo, request, status); 00057 if (request->parent_data) { 00058 snmp_free_varbind(((table_request_info *) request->parent_data)-> 00059 indexes); 00060 free(request->parent_data); 00061 request->parent_data = NULL; 00062 } 00063 } 00064 00065 00066 unsigned int 00067 closest_column(unsigned int current, column_info * valid_columns) 00068 { 00069 unsigned int closest = 0; 00070 char done = 0; 00071 char idx; 00072 assert(valid_columns != NULL); 00073 00074 do { 00075 00076 if (valid_columns->isRange) { 00077 00078 if (current < valid_columns->details.range[0]) { 00079 if (valid_columns->details.range[0] < closest) { 00080 closest = valid_columns->details.range[0]; 00081 } 00082 } else if (current <= valid_columns->details.range[1]) { 00083 closest = current; 00084 done = 1; /* can not get any closer! */ 00085 } 00086 00087 } /* range */ 00088 else { /* list */ 00089 00090 if (current < valid_columns->details.list[0]) { 00091 if (valid_columns->details.list[0] < closest) 00092 closest = valid_columns->details.list[0]; 00093 continue; 00094 } 00095 00096 if (current > 00097 valid_columns->details.list[valid_columns->list_count]) 00098 continue; /* not in list range. */ 00099 00100 for (idx = 0; idx < valid_columns->list_count; ++idx) { 00101 if (current == valid_columns->details.list[idx]) { 00102 closest = current; 00103 done = 1; /* can not get any closer! */ 00104 break; /* for */ 00105 } else if (current < valid_columns->details.list[idx]) { 00106 if (valid_columns->details.list[idx] < closest) 00107 closest = valid_columns->details.list[idx]; 00108 break; /* list should be sorted */ 00109 } 00110 } /* for */ 00111 00112 } /* list */ 00113 00114 valid_columns = valid_columns->next; 00115 00116 } while (!done && valid_columns); 00117 00118 return closest; 00119 } 00120 00121 int 00122 table_helper_handler(mib_handler * handler, 00123 handler_registration * reginfo, 00124 agent_request_info * reqinfo, request_info * requests) 00125 { 00126 00127 request_info *request; 00128 00129 table_registration_info *tbl_info; 00130 int oid_index_pos = reginfo->rootoid_len + 2; 00131 int oid_column_pos = reginfo->rootoid_len + 1; 00132 int tmp_idx, tmp_len; 00133 int incomplete, out_of_range; 00134 int status = SNMP_ERR_NOERROR, need_processing = 0; 00135 oid *tmp_name; 00136 table_request_info *tbl_req_info; 00137 struct variable_list *vb; 00138 00139 tbl_info = (table_registration_info *) handler->myvoid; 00140 00141 if ((!handler->myvoid) || (!tbl_info->indexes)) { 00142 snmp_log(LOG_INFO, "improperly registered table found\n"); 00143 00144 /* 00145 * XXX-rks: unregister table? 00146 */ 00147 return SNMP_ERR_GENERR; 00148 } 00149 00150 /* 00151 * * if the agent request info has a state reference, then * this is a 00152 * later pass of a set request and we can * skip all the lookup stuff. 00153 */ 00154 if (reqinfo->state_reference) { 00155 if (MODE_IS_SET(reqinfo->mode)) { 00156 return call_next_handler(handler, reginfo, reqinfo, requests); 00157 } else { 00158 #warning "XXX-rks: memory leak. add cleanup handler?" 00159 reqinfo->state_reference = NULL; 00160 } 00161 } 00162 00163 00164 /* 00165 * loop through requests 00166 */ 00167 00168 DEBUGMSGTL(("helper:table", "Got request:\n")); 00169 for (request = requests; request; request = request->next) { 00170 struct variable_list *var = request->requestvb; 00171 00172 assert(request->parent_data == NULL); 00173 00174 DEBUGMSGTL(("helper:table", " oid:")); 00175 DEBUGMSGOID(("helper:table", var->name, var->name_length)); 00176 DEBUGMSG(("helper:table", "\n")); 00177 00178 if (request->status) 00179 continue; 00180 ++need_processing; 00181 00182 /* 00183 * this should probably be handled further up 00184 */ 00185 if ((reqinfo->mode == MODE_GET) && (var->type != ASN_NULL)) { /* valid 00186 * request 00187 * if 00188 * ASN_NULL 00189 */ 00190 DEBUGMSGTL(("helper:table", 00191 " GET var type is not ASN_NULL\n")); 00192 set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE); 00193 continue; 00194 } 00195 00196 /* 00197 * check to make sure its in table range 00198 */ 00199 00200 out_of_range = 0; 00201 /* 00202 * if our root oid i > var->name and this is not a GETNEXT, 00203 */ 00204 /* 00205 * then the oid is out of range 00206 */ 00207 if (snmp_oid_compare(reginfo->rootoid, reginfo->rootoid_len, 00208 var->name, reginfo->rootoid_len) > 0) { 00209 if (reqinfo->mode == MODE_GETNEXT) { 00210 if (var->name != var->name_loc) 00211 free(var->name); 00212 snmp_set_var_objid(var, reginfo->rootoid, 00213 reginfo->rootoid_len); 00214 } else { 00215 DEBUGMSGTL(("helper:table", " oid is out of range.\n")); 00216 out_of_range = 1; 00217 } 00218 } 00219 /* 00220 * if var->name is longer than the root, make sure it is 00221 */ 00222 /* 00223 * table.1 (table.ENTRY). 00224 */ 00225 else if ((var->name_length > reginfo->rootoid_len) && 00226 (var->name[reginfo->rootoid_len] != 1)) { 00227 if ((var->name[reginfo->rootoid_len] < 1) && 00228 (reqinfo->mode == MODE_GETNEXT)) { 00229 var->name[reginfo->rootoid_len] = 1; 00230 var->name_length = reginfo->rootoid_len; 00231 } else { 00232 out_of_range = 1; 00233 DEBUGMSGTL(("helper:table", " oid is out of range.\n")); 00234 } 00235 } 00236 /* 00237 * if it is not in range, then remove it from the request list 00238 */ 00239 /* 00240 * because we can't process it. If the request is not a GETNEXT 00241 */ 00242 /* 00243 * then set the error to NOSUCHOBJECT so nobody else wastes time 00244 */ 00245 /* 00246 * trying to process it. 00247 */ 00248 if (out_of_range) { 00249 DEBUGMSGTL(("helper:table", " Not processed.\n")); 00250 if (reqinfo->mode != MODE_GETNEXT) { 00251 table_helper_cleanup(reqinfo, request, 00252 SNMP_ERR_NOSUCHNAME); 00253 } 00254 continue; 00255 } 00256 00257 00258 /* 00259 * Check column ranges; set-up to pull out indexes from OID. 00260 */ 00261 00262 incomplete = 0; 00263 tbl_req_info = SNMP_MALLOC_TYPEDEF(table_request_info); 00264 tbl_req_info->indexes = snmp_clone_varbind(tbl_info->indexes); 00265 tbl_req_info->number_indexes = 0; /* none yet */ 00266 if (var->name_length > oid_column_pos) { 00267 if (var->name[oid_column_pos] < tbl_info->min_column) { 00268 /* 00269 * fix column, truncate useless index info 00270 */ 00271 var->name_length = oid_column_pos; 00272 tbl_req_info->colnum = tbl_info->min_column; 00273 } else if (var->name[oid_column_pos] > tbl_info->max_column) { 00274 /* 00275 * this is out of range... remove from requests, free 00276 * memory 00277 */ 00278 DEBUGMSGTL(("helper:table", 00279 " oid is out of range. Not processed.\n")); 00280 if (reqinfo->mode != MODE_GETNEXT) { 00281 table_helper_cleanup(reqinfo, request, 00282 SNMP_ERR_NOSUCHNAME); 00283 } 00284 continue; 00285 } 00286 /* 00287 * use column verification 00288 */ 00289 else if (tbl_info->valid_columns) { 00290 tbl_req_info->colnum = 00291 closest_column(var->name[oid_column_pos], 00292 tbl_info->valid_columns); 00293 if (tbl_req_info->colnum == 0) 00294 continue; 00295 if (tbl_req_info->colnum != var->name[oid_column_pos]) { 00296 /* 00297 * different column! truncate useless index info 00298 */ 00299 var->name_length = oid_column_pos; 00300 } 00301 } 00302 /* 00303 * var->name_length may have changed - check again 00304 */ 00305 if (var->name_length <= oid_column_pos) { /* none available */ 00306 tbl_req_info->index_oid_len = 0; 00307 } else { 00308 tbl_req_info->colnum = var->name[oid_column_pos]; 00309 tbl_req_info->index_oid_len = 00310 var->name_length - oid_index_pos; 00311 assert(tbl_req_info->index_oid_len < MAX_OID_LEN); 00312 memcpy(tbl_req_info->index_oid, &var->name[oid_index_pos], 00313 tbl_req_info->index_oid_len * sizeof(oid)); 00314 tmp_name = tbl_req_info->index_oid; 00315 } 00316 } 00317 if (tbl_req_info->index_oid_len == 0) { 00318 incomplete = 1; 00319 tmp_len = -1; 00320 } else 00321 tmp_len = tbl_req_info->index_oid_len; 00322 00323 00324 /* 00325 * for each index type, try to extract the index from var->name 00326 */ 00327 00328 for (tmp_idx = 0, vb = tbl_req_info->indexes; 00329 tmp_idx < tbl_info->number_indexes; 00330 ++tmp_idx, vb = vb->next_variable) { 00331 if (incomplete && tmp_len) { 00332 /* 00333 * incomplete/illegal OID, set up dummy 0 to parse 00334 */ 00335 DEBUGMSGTL(("helper:table", 00336 " oid indexes not complete.\n")); 00337 /* 00338 * no sense in trying anymore if this is a GET/SET. 00339 */ 00340 if (reqinfo->mode != MODE_GETNEXT) { 00341 table_helper_cleanup(reqinfo, requests, 00342 SNMP_ERR_NOSUCHNAME); 00343 } 00344 tmp_len = 0; 00345 tmp_name = (oid *) & tmp_len; 00346 } 00347 /* 00348 * try and parse current index 00349 */ 00350 if (parse_one_oid_index(&tmp_name, &tmp_len, 00351 vb, 1) != SNMPERR_SUCCESS) { 00352 incomplete = 1; 00353 tmp_len = -1; /* is this necessary? Better safe than 00354 * sorry */ 00355 } else { 00356 /* 00357 * do not count incomplete indexes 00358 */ 00359 if (incomplete) 00360 continue; 00361 ++tbl_req_info->number_indexes; /* got one ok */ 00362 if (tmp_len <= 0) { 00363 incomplete = 1; 00364 tmp_len = -1; /* is this necessary? Better safe 00365 * than sorry */ 00366 } 00367 } 00368 } /* for loop */ 00369 00370 00371 /* 00372 * do we have sufficent index info to continue? 00373 */ 00374 00375 if ((reqinfo->mode != MODE_GETNEXT) && 00376 ((tbl_req_info->number_indexes != tbl_info->number_indexes) || 00377 (tmp_len != -1))) { 00378 table_helper_cleanup(reqinfo, request, SNMP_ERR_NOSUCHNAME); 00379 } 00380 00381 DEBUGIF("helper:table") { 00382 int count; 00383 char buf[SPRINT_MAX_LEN]; 00384 DEBUGMSGTL(("helper:table", " column: %d, indexes: %d\n", 00385 tbl_req_info->colnum, 00386 tbl_req_info->number_indexes)); 00387 for (vb = tbl_req_info->indexes, count = 0; 00388 vb && count < tbl_info->number_indexes; 00389 count++, vb = vb->next_variable) { 00390 sprint_by_type(buf, vb, 0, 0, 0); 00391 DEBUGMSGTL(("helper:table", 00392 " index: type=%d, value=%s\n", vb->type, 00393 buf)); 00394 } 00395 } 00396 00397 /* 00398 * save table_req_info 00399 */ 00400 request->parent_data = (void *) tbl_req_info; 00401 00402 } /* for each request */ 00403 00404 00405 /* 00406 * * call our child access function 00407 */ 00408 if (need_processing) 00409 status = call_next_handler(handler, reginfo, reqinfo, requests); 00410 00411 return status; 00412 } 00413 00414 int 00415 table_build_oid(handler_registration * reginfo, 00416 request_info * reqinfo, table_request_info * table_info) 00417 { 00418 oid tmpoid[MAX_OID_LEN]; 00419 struct variable_list *var; 00420 00421 if (!reginfo || !reqinfo || !table_info) 00422 return SNMPERR_GENERR; 00423 00424 memcpy(tmpoid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); 00425 tmpoid[reginfo->rootoid_len] = 1; /* .Entry */ 00426 tmpoid[reginfo->rootoid_len + 1] = table_info->colnum; /* .column 00427 */ 00428 00429 var = reqinfo->requestvb; 00430 if (build_oid(&var->name, &var->name_length, 00431 tmpoid, reginfo->rootoid_len + 2, table_info->indexes) 00432 != SNMPERR_SUCCESS) 00433 return SNMPERR_GENERR; 00434 00435 return SNMPERR_SUCCESS; 00436 } 00437 00438 int 00439 table_build_oid_from_index(handler_registration * reginfo, 00440 request_info * reqinfo, 00441 table_request_info * table_info) 00442 { 00443 oid tmpoid[MAX_OID_LEN]; 00444 struct variable_list *var; 00445 int len; 00446 00447 if (!reginfo || !reqinfo || !table_info) 00448 return SNMPERR_GENERR; 00449 00450 var = reqinfo->requestvb; 00451 len = reginfo->rootoid_len; 00452 memcpy(tmpoid, reginfo->rootoid, len * sizeof(oid)); 00453 tmpoid[len++] = 1; /* .Entry */ 00454 tmpoid[len++] = table_info->colnum; /* .column */ 00455 memcpy(&tmpoid[len], table_info->index_oid, 00456 table_info->index_oid_len * sizeof(oid)); 00457 len += table_info->index_oid_len; 00458 snmp_clone_mem((void **) &var->name, tmpoid, len * sizeof(oid)); 00459 var->name_length = len; 00460 00461 return SNMPERR_SUCCESS; 00462 } 00463 00464 int 00465 table_build_result(handler_registration * reginfo, 00466 request_info * reqinfo, 00467 table_request_info * table_info, u_char type, 00468 u_char * result, size_t result_len) 00469 { 00470 00471 struct variable_list *var; 00472 00473 if (!reqinfo || !table_info) 00474 return SNMPERR_GENERR; 00475 00476 var = reqinfo->requestvb; 00477 00478 if (var->name != var->name_loc) 00479 free(var->name); 00480 var->name = NULL; 00481 00482 if (table_build_oid(reginfo, reqinfo, table_info) != SNMPERR_SUCCESS) 00483 return SNMPERR_GENERR; 00484 00485 snmp_set_var_typed_value(var, type, result, result_len); 00486 00487 return SNMPERR_SUCCESS; 00488 } 00489 00490 int 00491 update_variable_list_from_index(table_request_info * tri) 00492 { 00493 return parse_oid_indexes(tri->index_oid, tri->index_oid_len, 00494 tri->indexes); 00495 } 00496 00497 int 00498 update_indexes_from_variable_list(table_request_info * tri) 00499 { 00500 return build_oid_noalloc(tri->index_oid, sizeof(tri->index_oid), 00501 &tri->index_oid_len, NULL, 0, tri->indexes); 00502 } 00503 00504 /* 00505 * checks the original request against the current data being passed in if 00506 * its greater than the request oid but less than the current valid 00507 * return, set the current valid return to the new value. 00508 * 00509 * returns 1 if outvar was replaced with the oid from newvar (success). 00510 * returns 0 if not. 00511 */ 00512 int 00513 check_getnext_reply(request_info * request, 00514 oid * prefix, 00515 size_t prefix_len, 00516 struct variable_list *newvar, 00517 struct variable_list **outvar) 00518 { 00519 static oid myname[MAX_OID_LEN]; 00520 static int myname_len; 00521 00522 build_oid_noalloc(myname, MAX_OID_LEN, &myname_len, 00523 prefix, prefix_len, newvar); 00524 /* 00525 * is the build of the new indexes less than our current result 00526 */ 00527 if ((!(*outvar) || snmp_oid_compare(myname + prefix_len, 00528 myname_len - prefix_len, 00529 (*outvar)->name, 00530 (*outvar)->name_length) < 0)) { 00531 /* 00532 * and greater than the requested oid 00533 */ 00534 if (snmp_oid_compare(myname, myname_len, 00535 request->requestvb->name, 00536 request->requestvb->name_length) > 0) { 00537 /* 00538 * the new result must be better than the old 00539 */ 00540 if (!*outvar) 00541 *outvar = snmp_clone_varbind(newvar); 00542 snmp_set_var_objid(*outvar, myname, myname_len); 00543 00544 return 1; 00545 } 00546 } 00547 return 0; 00548 }
Last modified: Wednesday, 01-Aug-2018 04:41:28 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.