00001 #include <net-snmp/net-snmp-config.h> 00002 00003 #include <stdio.h> 00004 #include <sys/types.h> 00005 #include <ctype.h> 00006 #include <errno.h> 00007 00008 #ifdef WIN32 00009 #include <net-snmp/library/winpipe.h> 00010 #endif 00011 #if HAVE_STRING_H 00012 #include <string.h> 00013 #else 00014 #include <strings.h> 00015 #endif 00016 #if HAVE_STDLIB_H 00017 #include <stdlib.h> 00018 #endif 00019 #if HAVE_UNISTD_H 00020 #include <unistd.h> 00021 #endif 00022 #if HAVE_SYS_SOCKET_H 00023 #include <sys/socket.h> 00024 #endif 00025 #if HAVE_SYS_UN_H 00026 #include <sys/un.h> 00027 #endif 00028 #if HAVE_IO_H 00029 #include <io.h> 00030 #endif 00031 #if HAVE_FCNTL_H 00032 #include <fcntl.h> 00033 #endif 00034 00035 #if HAVE_DMALLOC_H 00036 #include <dmalloc.h> 00037 #endif 00038 00039 #include <net-snmp/types.h> 00040 #include <net-snmp/output_api.h> 00041 #include <net-snmp/config_api.h> 00042 #include <net-snmp/utilities.h> 00043 00044 #include <net-snmp/library/snmp_transport.h> 00045 #include <net-snmp/library/snmpUnixDomain.h> 00046 #include <net-snmp/library/snmp_api.h> 00047 #include <net-snmp/library/snmp_client.h> 00048 #include <net-snmp/library/snmpCallbackDomain.h> 00049 00050 #ifndef NETSNMP_STREAM_QUEUE_LEN 00051 #define NETSNMP_STREAM_QUEUE_LEN 5 00052 #endif 00053 00054 #ifdef NETSNMP_TRANSPORT_CALLBACK_DOMAIN 00055 00056 static netsnmp_transport_list *trlist = NULL; 00057 00058 static int callback_count = 0; 00059 00060 typedef struct callback_hack_s { 00061 void *orig_transport_data; 00062 netsnmp_pdu *pdu; 00063 } callback_hack; 00064 00065 typedef struct callback_queue_s { 00066 int callback_num; 00067 netsnmp_callback_pass *item; 00068 struct callback_queue_s *next, *prev; 00069 } callback_queue; 00070 00071 callback_queue *thequeue; 00072 00073 static netsnmp_transport * 00074 find_transport_from_callback_num(int num) 00075 { 00076 static netsnmp_transport_list *ptr; 00077 for (ptr = trlist; ptr; ptr = ptr->next) 00078 if (((netsnmp_callback_info *) ptr->transport->data)-> 00079 callback_num == num) 00080 return ptr->transport; 00081 return NULL; 00082 } 00083 00084 static void 00085 callback_debug_pdu(const char *ourstring, netsnmp_pdu *pdu) 00086 { 00087 netsnmp_variable_list *vb; 00088 int i = 1; 00089 DEBUGMSGTL((ourstring, 00090 "PDU: command = %d, errstat = %ld, errindex = %ld\n", 00091 pdu->command, pdu->errstat, pdu->errindex)); 00092 for (vb = pdu->variables; vb; vb = vb->next_variable) { 00093 DEBUGMSGTL((ourstring, " var %d:", i++)); 00094 DEBUGMSGVAR((ourstring, vb)); 00095 DEBUGMSG((ourstring, "\n")); 00096 } 00097 } 00098 00099 void 00100 callback_push_queue(int num, netsnmp_callback_pass *item) 00101 { 00102 callback_queue *newitem = SNMP_MALLOC_TYPEDEF(callback_queue); 00103 callback_queue *ptr; 00104 00105 if (newitem == NULL) 00106 return; 00107 newitem->callback_num = num; 00108 newitem->item = item; 00109 if (thequeue) { 00110 for (ptr = thequeue; ptr && ptr->next; ptr = ptr->next) { 00111 } 00112 ptr->next = newitem; 00113 newitem->prev = ptr; 00114 } else { 00115 thequeue = newitem; 00116 } 00117 DEBUGIF("dump_send_callback_transport") { 00118 callback_debug_pdu("dump_send_callback_transport", item->pdu); 00119 } 00120 } 00121 00122 netsnmp_callback_pass * 00123 callback_pop_queue(int num) 00124 { 00125 netsnmp_callback_pass *cp; 00126 callback_queue *ptr; 00127 00128 for (ptr = thequeue; ptr; ptr = ptr->next) { 00129 if (ptr->callback_num == num) { 00130 if (ptr->prev) { 00131 ptr->prev->next = ptr->next; 00132 } else { 00133 thequeue = ptr->next; 00134 } 00135 if (ptr->next) { 00136 ptr->next->prev = ptr->prev; 00137 } 00138 cp = ptr->item; 00139 SNMP_FREE(ptr); 00140 DEBUGIF("dump_recv_callback_transport") { 00141 callback_debug_pdu("dump_recv_callback_transport", 00142 cp->pdu); 00143 } 00144 return cp; 00145 } 00146 } 00147 return NULL; 00148 } 00149 00150 /* 00151 * Return a string representing the address in data, or else the "far end" 00152 * address if data is NULL. 00153 */ 00154 00155 char * 00156 netsnmp_callback_fmtaddr(netsnmp_transport *t, void *data, int len) 00157 { 00158 char buf[SPRINT_MAX_LEN]; 00159 netsnmp_callback_info *mystuff; 00160 00161 if (!t) 00162 return strdup("callback: unknown"); 00163 00164 mystuff = (netsnmp_callback_info *) t->data; 00165 00166 if (!mystuff) 00167 return strdup("callback: unknown"); 00168 00169 snprintf(buf, SPRINT_MAX_LEN, "callback: %d on fd %d", 00170 mystuff->callback_num, mystuff->pipefds[0]); 00171 return strdup(buf); 00172 } 00173 00174 00175 00176 /* 00177 * You can write something into opaque that will subsequently get passed back 00178 * to your send function if you like. For instance, you might want to 00179 * remember where a PDU came from, so that you can send a reply there... 00180 */ 00181 00182 int 00183 netsnmp_callback_recv(netsnmp_transport *t, void *buf, int size, 00184 void **opaque, int *olength) 00185 { 00186 int rc = -1; 00187 char newbuf[1]; 00188 netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data; 00189 00190 DEBUGMSGTL(("transport_callback", "hook_recv enter\n")); 00191 00192 while (rc < 0) { 00193 #ifdef WIN32 00194 rc = recvfrom(mystuff->pipefds[0], newbuf, 1, 0, NULL, 0); 00195 #else 00196 rc = read(mystuff->pipefds[0], newbuf, 1); 00197 #endif 00198 if (rc < 0 && errno != EINTR) { 00199 break; 00200 } 00201 } 00202 00203 if (mystuff->linkedto) { 00204 /* 00205 * we're the client. We don't need to do anything. 00206 */ 00207 } else { 00208 /* 00209 * malloc the space here, but it's filled in by 00210 * snmp_callback_created_pdu() below 00211 */ 00212 int *returnnum = (int *) calloc(1, sizeof(int)); 00213 *opaque = returnnum; 00214 *olength = sizeof(int); 00215 } 00216 DEBUGMSGTL(("transport_callback", "hook_recv exit\n")); 00217 return rc; 00218 } 00219 00220 00221 00222 int 00223 netsnmp_callback_send(netsnmp_transport *t, void *buf, int size, 00224 void **opaque, int *olength) 00225 { 00226 int from, rc = -1; 00227 netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data; 00228 netsnmp_callback_pass *cp; 00229 00230 /* 00231 * extract the pdu from the hacked buffer 00232 */ 00233 netsnmp_transport *other_side; 00234 callback_hack *ch = (callback_hack *) * opaque; 00235 netsnmp_pdu *pdu = ch->pdu; 00236 *opaque = ch->orig_transport_data; 00237 SNMP_FREE(ch); 00238 00239 DEBUGMSGTL(("transport_callback", "hook_send enter\n")); 00240 00241 cp = SNMP_MALLOC_TYPEDEF(netsnmp_callback_pass); 00242 if (!cp) 00243 return -1; 00244 00245 cp->pdu = snmp_clone_pdu(pdu); 00246 if (cp->pdu->transport_data) { 00247 /* 00248 * not needed and not properly freed later 00249 */ 00250 SNMP_FREE(cp->pdu->transport_data); 00251 } 00252 00253 if (cp->pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE) 00254 cp->pdu->flags ^= UCD_MSG_FLAG_EXPECT_RESPONSE; 00255 00256 /* 00257 * push the sent pdu onto the stack 00258 */ 00259 /* 00260 * AND send a bogus byte to the remote callback receiver's pipe 00261 */ 00262 if (mystuff->linkedto) { 00263 /* 00264 * we're the client, send it to the parent 00265 */ 00266 cp->return_transport_num = mystuff->callback_num; 00267 00268 other_side = find_transport_from_callback_num(mystuff->linkedto); 00269 if (!other_side) { 00270 snmp_free_pdu(cp->pdu); 00271 SNMP_FREE(cp); 00272 return -1; 00273 } 00274 00275 while (rc < 0) { 00276 #ifdef WIN32 00277 rc = sendto(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0, NULL, 0); 00278 #else 00279 rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1], 00280 " ", 1); 00281 #endif 00282 if (rc < 0 && errno != EINTR) { 00283 break; 00284 } 00285 } 00286 callback_push_queue(mystuff->linkedto, cp); 00287 /* 00288 * we don't need the transport data any more 00289 */ 00290 if (*opaque) { 00291 SNMP_FREE(*opaque); 00292 *opaque = NULL; 00293 } 00294 } else { 00295 /* 00296 * we're the server, send it to the person that sent us the request 00297 */ 00298 from = **((int **) opaque); 00299 /* 00300 * we don't need the transport data any more 00301 */ 00302 if (*opaque) { 00303 SNMP_FREE(*opaque); 00304 *opaque = NULL; 00305 } 00306 other_side = find_transport_from_callback_num(from); 00307 if (!other_side) { 00308 snmp_free_pdu(cp->pdu); 00309 SNMP_FREE(cp); 00310 return -1; 00311 } 00312 while (rc < 0) { 00313 #ifdef WIN32 00314 rc = sendto(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0, NULL, 0); 00315 #else 00316 rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1], 00317 " ", 1); 00318 #endif 00319 if (rc < 0 && errno != EINTR) { 00320 break; 00321 } 00322 } 00323 callback_push_queue(from, cp); 00324 } 00325 00326 DEBUGMSGTL(("transport_callback", "hook_send exit\n")); 00327 return 0; 00328 } 00329 00330 00331 00332 int 00333 netsnmp_callback_close(netsnmp_transport *t) 00334 { 00335 int rc; 00336 netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data; 00337 DEBUGMSGTL(("transport_callback", "hook_close enter\n")); 00338 00339 #ifdef WIN32 00340 rc = closesocket(mystuff->pipefds[0]); 00341 rc |= closesocket(mystuff->pipefds[1]); 00342 #else 00343 rc = close(mystuff->pipefds[0]); 00344 rc |= close(mystuff->pipefds[1]); 00345 #endif 00346 00347 rc |= netsnmp_transport_remove_from_list(&trlist, t); 00348 00349 DEBUGMSGTL(("transport_callback", "hook_close exit\n")); 00350 return rc; 00351 } 00352 00353 00354 00355 int 00356 netsnmp_callback_accept(netsnmp_transport *t) 00357 { 00358 DEBUGMSGTL(("transport_callback", "hook_accept enter\n")); 00359 DEBUGMSGTL(("transport_callback", "hook_accept exit\n")); 00360 return 0; 00361 } 00362 00363 00364 00365 /* 00366 * Open a Callback-domain transport for SNMP. Local is TRUE if addr 00367 * is the local address to bind to (i.e. this is a server-type 00368 * session); otherwise addr is the remote address to send things to 00369 * (and we make up a temporary name for the local end of the 00370 * connection). 00371 */ 00372 00373 netsnmp_transport * 00374 netsnmp_callback_transport(int to) 00375 { 00376 00377 netsnmp_transport *t = NULL; 00378 netsnmp_callback_info *mydata; 00379 int rc; 00380 00381 /* 00382 * transport 00383 */ 00384 t = SNMP_MALLOC_TYPEDEF(netsnmp_transport); 00385 if (!t) 00386 return NULL; 00387 00388 /* 00389 * our stuff 00390 */ 00391 mydata = SNMP_MALLOC_TYPEDEF(netsnmp_callback_info); 00392 if (!mydata) 00393 return NULL; 00394 mydata->linkedto = to; 00395 mydata->callback_num = ++callback_count; 00396 mydata->data = NULL; 00397 t->data = mydata; 00398 00399 #ifdef WIN32 00400 rc = create_winpipe_transport(mydata->pipefds); 00401 #else 00402 rc = pipe(mydata->pipefds); 00403 #endif 00404 t->sock = mydata->pipefds[0]; 00405 00406 if (rc) { 00407 SNMP_FREE(mydata); 00408 SNMP_FREE(t); 00409 return NULL; 00410 } 00411 00412 t->f_recv = netsnmp_callback_recv; 00413 t->f_send = netsnmp_callback_send; 00414 t->f_close = netsnmp_callback_close; 00415 t->f_accept = netsnmp_callback_accept; 00416 t->f_fmtaddr = netsnmp_callback_fmtaddr; 00417 00418 netsnmp_transport_add_to_list(&trlist, t); 00419 00420 if (to) 00421 DEBUGMSGTL(("transport_callback", "initialized %d linked to %d\n", 00422 mydata->callback_num, to)); 00423 else 00424 DEBUGMSGTL(("transport_callback", 00425 "initialized master listening on %d\n", 00426 mydata->callback_num)); 00427 return t; 00428 } 00429 00430 int 00431 netsnmp_callback_hook_parse(netsnmp_session * sp, 00432 netsnmp_pdu *pdu, 00433 u_char * packetptr, size_t len) 00434 { 00435 if (SNMP_MSG_RESPONSE == pdu->command || 00436 SNMP_MSG_REPORT == pdu->command) 00437 pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU; 00438 else 00439 pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU); 00440 00441 return SNMP_ERR_NOERROR; 00442 } 00443 00444 int 00445 netsnmp_callback_hook_build(netsnmp_session * sp, 00446 netsnmp_pdu *pdu, u_char * ptk, size_t * len) 00447 { 00448 /* 00449 * very gross hack, as this is passed later to the transport_send 00450 * function 00451 */ 00452 callback_hack *ch = SNMP_MALLOC_TYPEDEF(callback_hack); 00453 if (ch == NULL) 00454 return -1; 00455 DEBUGMSGTL(("transport_callback", "hook_build enter\n")); 00456 ch->pdu = pdu; 00457 ch->orig_transport_data = pdu->transport_data; 00458 pdu->transport_data = ch; 00459 switch (pdu->command) { 00460 case SNMP_MSG_GETBULK: 00461 if (pdu->max_repetitions < 0) { 00462 sp->s_snmp_errno = SNMPERR_BAD_REPETITIONS; 00463 return -1; 00464 } 00465 if (pdu->non_repeaters < 0) { 00466 sp->s_snmp_errno = SNMPERR_BAD_REPEATERS; 00467 return -1; 00468 } 00469 break; 00470 case SNMP_MSG_RESPONSE: 00471 case SNMP_MSG_TRAP: 00472 case SNMP_MSG_TRAP2: 00473 pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE); 00474 /* 00475 * Fallthrough 00476 */ 00477 default: 00478 if (pdu->errstat == SNMP_DEFAULT_ERRSTAT) 00479 pdu->errstat = 0; 00480 if (pdu->errindex == SNMP_DEFAULT_ERRINDEX) 00481 pdu->errindex = 0; 00482 break; 00483 } 00484 00485 /* 00486 * Copy missing values from session defaults 00487 */ 00488 switch (pdu->version) { 00489 #ifndef NETSNMP_DISABLE_SNMPV1 00490 case SNMP_VERSION_1: 00491 #endif 00492 #ifndef NETSNMP_DISABLE_SNMPV2C 00493 case SNMP_VERSION_2c: 00494 #endif 00495 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 00496 if (pdu->community_len == 0) { 00497 if (sp->community_len == 0) { 00498 sp->s_snmp_errno = SNMPERR_BAD_COMMUNITY; 00499 return -1; 00500 } 00501 pdu->community = (u_char *) malloc(sp->community_len); 00502 if (pdu->community == NULL) { 00503 sp->s_snmp_errno = SNMPERR_MALLOC; 00504 return -1; 00505 } 00506 memmove(pdu->community, 00507 sp->community, sp->community_len); 00508 pdu->community_len = sp->community_len; 00509 } 00510 break; 00511 #endif 00512 case SNMP_VERSION_3: 00513 if (pdu->securityNameLen == 0) { 00514 pdu->securityName = (char *)malloc(sp->securityNameLen); 00515 if (pdu->securityName == NULL) { 00516 sp->s_snmp_errno = SNMPERR_MALLOC; 00517 return -1; 00518 } 00519 memmove(pdu->securityName, 00520 sp->securityName, sp->securityNameLen); 00521 pdu->securityNameLen = sp->securityNameLen; 00522 } 00523 if (pdu->securityModel == -1) 00524 pdu->securityModel = sp->securityModel; 00525 if (pdu->securityLevel == 0) 00526 pdu->securityLevel = sp->securityLevel; 00527 /* WHAT ELSE ?? */ 00528 } 00529 *len = 1; 00530 DEBUGMSGTL(("transport_callback", "hook_build exit\n")); 00531 return 1; 00532 } 00533 00534 int 00535 netsnmp_callback_check_packet(u_char * pkt, size_t len) 00536 { 00537 return 1; 00538 } 00539 00540 netsnmp_pdu * 00541 netsnmp_callback_create_pdu(netsnmp_transport *transport, 00542 void *opaque, size_t olength) 00543 { 00544 netsnmp_pdu *pdu; 00545 netsnmp_callback_pass *cp = 00546 callback_pop_queue(((netsnmp_callback_info *) transport->data)-> 00547 callback_num); 00548 if (!cp) 00549 return NULL; 00550 pdu = cp->pdu; 00551 pdu->transport_data = opaque; 00552 pdu->transport_data_length = olength; 00553 if (opaque) /* if created, we're the server */ 00554 *((int *) opaque) = cp->return_transport_num; 00555 SNMP_FREE(cp); 00556 return pdu; 00557 } 00558 00559 netsnmp_session * 00560 netsnmp_callback_open(int attach_to, 00561 int (*return_func) (int op, 00562 netsnmp_session * session, 00563 int reqid, netsnmp_pdu *pdu, 00564 void *magic), 00565 int (*fpre_parse) (netsnmp_session *, 00566 struct netsnmp_transport_s *, 00567 void *, int), 00568 int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, 00569 int)) 00570 { 00571 netsnmp_session callback_sess, *callback_ss; 00572 netsnmp_transport *callback_tr; 00573 00574 callback_tr = netsnmp_callback_transport(attach_to); 00575 snmp_sess_init(&callback_sess); 00576 callback_sess.callback = return_func; 00577 if (attach_to) { 00578 /* 00579 * client 00580 */ 00581 /* 00582 * trysess.community = (u_char *) callback_ss; 00583 */ 00584 } else { 00585 callback_sess.isAuthoritative = SNMP_SESS_AUTHORITATIVE; 00586 } 00587 callback_sess.remote_port = 0; 00588 callback_sess.retries = 0; 00589 callback_sess.timeout = 30000000; 00590 callback_sess.version = SNMP_DEFAULT_VERSION; /* (mostly) bogus */ 00591 callback_ss = snmp_add_full(&callback_sess, callback_tr, 00592 fpre_parse, 00593 netsnmp_callback_hook_parse, fpost_parse, 00594 netsnmp_callback_hook_build, 00595 NULL, 00596 netsnmp_callback_check_packet, 00597 netsnmp_callback_create_pdu); 00598 if (callback_ss) 00599 callback_ss->local_port = 00600 ((netsnmp_callback_info *) callback_tr->data)->callback_num; 00601 return callback_ss; 00602 } 00603 00604 00605 00606 void 00607 netsnmp_clear_callback_list(void) 00608 { 00609 00610 netsnmp_transport_list *list = trlist, *next = NULL; 00611 netsnmp_transport *tr = NULL; 00612 00613 DEBUGMSGTL(("callback_clear", "called netsnmp_callback_clear_list()\n")); 00614 while (list != NULL) { 00615 next = list->next; 00616 tr = list->transport; 00617 00618 if (tr != NULL) { 00619 tr->f_close(tr); 00620 netsnmp_transport_remove_from_list(&trlist, list->transport); 00621 netsnmp_transport_free(list->transport); 00622 } 00623 list = next; 00624 } 00625 trlist = NULL; 00626 00627 } 00628 00629 #endif /* NETSNMP_TRANSPORT_CALLBACK_DOMAIN */
1.5.7.1
Last modified: Tuesday, 23-Dec-2025 17:22:04 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.