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
00152
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
00178
00179
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
00206
00207 } else {
00208
00209
00210
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
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
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
00258
00259
00260
00261
00262 if (mystuff->linkedto) {
00263
00264
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
00289
00290 if (*opaque) {
00291 SNMP_FREE(*opaque);
00292 *opaque = NULL;
00293 }
00294 } else {
00295
00296
00297
00298 from = **((int **) opaque);
00299
00300
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
00367
00368
00369
00370
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
00383
00384 t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
00385 if (!t)
00386 return NULL;
00387
00388
00389
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
00450
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
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
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
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)
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
00580
00581
00582
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;
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