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 SNMP_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 = %d, errindex = %d\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 newitem->callback_num = num;
00106 newitem->item = item;
00107 if (thequeue) {
00108 for (ptr = thequeue; ptr && ptr->next; ptr = ptr->next) {
00109 }
00110 ptr->next = newitem;
00111 newitem->prev = ptr;
00112 } else {
00113 thequeue = newitem;
00114 }
00115 DEBUGIF("dump_send_callback_transport") {
00116 callback_debug_pdu("dump_send_callback_transport", item->pdu);
00117 }
00118 }
00119
00120 netsnmp_callback_pass *
00121 callback_pop_queue(int num)
00122 {
00123 netsnmp_callback_pass *cp;
00124 callback_queue *ptr;
00125
00126 for (ptr = thequeue; ptr; ptr = ptr->next) {
00127 if (ptr->callback_num == num) {
00128 if (ptr->prev) {
00129 ptr->prev->next = ptr->next;
00130 } else {
00131 thequeue = ptr->next;
00132 }
00133 if (ptr->next) {
00134 ptr->next->prev = ptr->prev;
00135 }
00136 cp = ptr->item;
00137 SNMP_FREE(ptr);
00138 DEBUGIF("dump_recv_callback_transport") {
00139 callback_debug_pdu("dump_recv_callback_transport",
00140 cp->pdu);
00141 }
00142 return cp;
00143 }
00144 }
00145 return NULL;
00146 }
00147
00148
00149
00150
00151
00152
00153 char *
00154 netsnmp_callback_fmtaddr(netsnmp_transport *t, void *data, int len)
00155 {
00156 char buf[SPRINT_MAX_LEN];
00157 netsnmp_callback_info *mystuff;
00158
00159 if (!t)
00160 return strdup("callback: unknown");
00161
00162 mystuff = (netsnmp_callback_info *) t->data;
00163
00164 if (!mystuff)
00165 return strdup("callback: unknown");
00166
00167 snprintf(buf, SPRINT_MAX_LEN, "callback: %d on fd %d",
00168 mystuff->callback_num, mystuff->pipefds[0]);
00169 return strdup(buf);
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 int
00181 netsnmp_callback_recv(netsnmp_transport *t, void *buf, int size,
00182 void **opaque, int *olength)
00183 {
00184 int rc = -1;
00185 char newbuf[1];
00186 netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
00187
00188 DEBUGMSGTL(("transport_callback", "hook_recv enter\n"));
00189
00190 while (rc < 0) {
00191 #ifdef WIN32
00192 rc = recv(mystuff->pipefds[0], newbuf, 1, 0);
00193 #else
00194 rc = read(mystuff->pipefds[0], newbuf, 1);
00195 #endif
00196 if (rc < 0 && errno != EINTR) {
00197 break;
00198 }
00199 }
00200
00201 if (mystuff->linkedto) {
00202
00203
00204
00205 } else {
00206
00207
00208
00209
00210 int *returnnum = (int *) calloc(1, sizeof(int));
00211 *opaque = returnnum;
00212 *olength = sizeof(int);
00213 }
00214 DEBUGMSGTL(("transport_callback", "hook_recv exit\n"));
00215 return rc;
00216 }
00217
00218
00219
00220 int
00221 netsnmp_callback_send(netsnmp_transport *t, void *buf, int size,
00222 void **opaque, int *olength)
00223 {
00224 int from, rc = -1;
00225 netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
00226 netsnmp_callback_pass *cp;
00227
00228
00229
00230
00231 netsnmp_transport *other_side;
00232 callback_hack *ch = (callback_hack *) * opaque;
00233 netsnmp_pdu *pdu = ch->pdu;
00234 *opaque = ch->orig_transport_data;
00235 SNMP_FREE(ch);
00236
00237 DEBUGMSGTL(("transport_callback", "hook_send enter\n"));
00238
00239 cp = SNMP_MALLOC_TYPEDEF(netsnmp_callback_pass);
00240 if (!cp)
00241 return -1;
00242
00243 cp->pdu = snmp_clone_pdu(pdu);
00244 if (cp->pdu->transport_data) {
00245
00246
00247
00248 SNMP_FREE(cp->pdu->transport_data);
00249 }
00250
00251 if (cp->pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE)
00252 cp->pdu->flags ^= UCD_MSG_FLAG_EXPECT_RESPONSE;
00253
00254
00255
00256
00257
00258
00259
00260 if (mystuff->linkedto) {
00261
00262
00263
00264 cp->return_transport_num = mystuff->callback_num;
00265
00266 other_side = find_transport_from_callback_num(mystuff->linkedto);
00267 if (!other_side) {
00268 snmp_free_pdu(cp->pdu);
00269 SNMP_FREE(cp);
00270 return -1;
00271 }
00272
00273 while (rc < 0) {
00274 #ifdef WIN32
00275 rc = send(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0);
00276 #else
00277 rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
00278 " ", 1);
00279 #endif
00280 if (rc < 0 && errno != EINTR) {
00281 break;
00282 }
00283 }
00284 callback_push_queue(mystuff->linkedto, cp);
00285
00286
00287
00288 if (*opaque) {
00289 SNMP_FREE(*opaque);
00290 *opaque = NULL;
00291 }
00292 } else {
00293
00294
00295
00296 from = **((int **) opaque);
00297
00298
00299
00300 if (*opaque) {
00301 SNMP_FREE(*opaque);
00302 *opaque = NULL;
00303 }
00304 other_side = find_transport_from_callback_num(from);
00305 if (!other_side) {
00306 snmp_free_pdu(cp->pdu);
00307 SNMP_FREE(cp);
00308 return -1;
00309 }
00310 while (rc < 0) {
00311 #ifdef WIN32
00312 rc = send(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0);
00313 #else
00314 rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
00315 " ", 1);
00316 #endif
00317 if (rc < 0 && errno != EINTR) {
00318 break;
00319 }
00320 }
00321 callback_push_queue(from, cp);
00322 }
00323
00324 DEBUGMSGTL(("transport_callback", "hook_send exit\n"));
00325 return 0;
00326 }
00327
00328
00329
00330 int
00331 netsnmp_callback_close(netsnmp_transport *t)
00332 {
00333 int rc;
00334 netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
00335 DEBUGMSGTL(("transport_callback", "hook_close enter\n"));
00336
00337 #ifdef WIN32
00338 rc = closesocket(mystuff->pipefds[0]);
00339 rc |= closesocket(mystuff->pipefds[1]);
00340 #else
00341 rc = close(mystuff->pipefds[0]);
00342 rc |= close(mystuff->pipefds[1]);
00343 #endif
00344
00345 rc |= netsnmp_transport_remove_from_list(&trlist, t);
00346
00347 DEBUGMSGTL(("transport_callback", "hook_close exit\n"));
00348 return rc;
00349 }
00350
00351
00352
00353 int
00354 netsnmp_callback_accept(netsnmp_transport *t)
00355 {
00356 DEBUGMSGTL(("transport_callback", "hook_accept enter\n"));
00357 DEBUGMSGTL(("transport_callback", "hook_accept exit\n"));
00358 return 0;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 netsnmp_transport *
00372 netsnmp_callback_transport(int to)
00373 {
00374
00375 netsnmp_transport *t = NULL;
00376 netsnmp_callback_info *mydata;
00377 int rc;
00378
00379
00380
00381
00382 t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
00383 if (!t)
00384 return NULL;
00385
00386
00387
00388
00389 mydata = SNMP_MALLOC_TYPEDEF(netsnmp_callback_info);
00390 mydata->linkedto = to;
00391 mydata->callback_num = ++callback_count;
00392 mydata->data = NULL;
00393 t->data = mydata;
00394
00395 #ifdef WIN32
00396 rc = create_winpipe_transport(mydata->pipefds);
00397 #else
00398 rc = pipe(mydata->pipefds);
00399 #endif
00400 t->sock = mydata->pipefds[0];
00401
00402 if (rc) {
00403 SNMP_FREE(mydata);
00404 SNMP_FREE(t);
00405 return NULL;
00406 }
00407
00408 t->f_recv = netsnmp_callback_recv;
00409 t->f_send = netsnmp_callback_send;
00410 t->f_close = netsnmp_callback_close;
00411 t->f_accept = netsnmp_callback_accept;
00412 t->f_fmtaddr = netsnmp_callback_fmtaddr;
00413
00414 netsnmp_transport_add_to_list(&trlist, t);
00415
00416 if (to)
00417 DEBUGMSGTL(("transport_callback", "initialized %d linked to %d\n",
00418 mydata->callback_num, to));
00419 else
00420 DEBUGMSGTL(("transport_callback",
00421 "initialized master listening on %d\n",
00422 mydata->callback_num));
00423 return t;
00424 }
00425
00426 int
00427 netsnmp_callback_hook_parse(netsnmp_session * sp,
00428 netsnmp_pdu *pdu,
00429 u_char * packetptr, size_t len)
00430 {
00431 if (SNMP_MSG_RESPONSE == pdu->command ||
00432 SNMP_MSG_REPORT == pdu->command)
00433 pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
00434 else
00435 pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
00436
00437 return SNMP_ERR_NOERROR;
00438 }
00439
00440 int
00441 netsnmp_callback_hook_build(netsnmp_session * sp,
00442 netsnmp_pdu *pdu, u_char * ptk, size_t * len)
00443 {
00444
00445
00446
00447
00448 callback_hack *ch = SNMP_MALLOC_TYPEDEF(callback_hack);
00449 DEBUGMSGTL(("transport_callback", "hook_build enter\n"));
00450 ch->pdu = pdu;
00451 ch->orig_transport_data = pdu->transport_data;
00452 pdu->transport_data = ch;
00453 switch (pdu->command) {
00454 case SNMP_MSG_GETBULK:
00455 if (pdu->max_repetitions < 0) {
00456 sp->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
00457 return -1;
00458 }
00459 if (pdu->non_repeaters < 0) {
00460 sp->s_snmp_errno = SNMPERR_BAD_REPEATERS;
00461 return -1;
00462 }
00463 break;
00464 case SNMP_MSG_RESPONSE:
00465 case SNMP_MSG_TRAP:
00466 case SNMP_MSG_TRAP2:
00467 pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
00468
00469
00470
00471 default:
00472 if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
00473 pdu->errstat = 0;
00474 if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
00475 pdu->errindex = 0;
00476 break;
00477 }
00478
00479
00480
00481
00482 switch (pdu->version) {
00483 #ifndef DISABLE_SNMPV1
00484 case SNMP_VERSION_1:
00485 #endif
00486 #ifndef DISABLE_SNMPV2C
00487 case SNMP_VERSION_2c:
00488 #endif
00489 #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
00490 if (pdu->community_len == 0) {
00491 if (sp->community_len == 0) {
00492 sp->s_snmp_errno = SNMPERR_BAD_COMMUNITY;
00493 return -1;
00494 }
00495 pdu->community = (u_char *) malloc(sp->community_len);
00496 if (pdu->community == NULL) {
00497 sp->s_snmp_errno = SNMPERR_MALLOC;
00498 return -1;
00499 }
00500 memmove(pdu->community,
00501 sp->community, sp->community_len);
00502 pdu->community_len = sp->community_len;
00503 }
00504 break;
00505 #endif
00506 case SNMP_VERSION_3:
00507 if (pdu->securityNameLen == 0) {
00508 pdu->securityName = malloc(sp->securityNameLen);
00509 if (pdu->securityName == NULL) {
00510 sp->s_snmp_errno = SNMPERR_MALLOC;
00511 return -1;
00512 }
00513 memmove(pdu->securityName,
00514 sp->securityName, sp->securityNameLen);
00515 pdu->securityNameLen = sp->securityNameLen;
00516 }
00517 if (pdu->securityModel == -1)
00518 pdu->securityModel = sp->securityModel;
00519 if (pdu->securityLevel == 0)
00520 pdu->securityLevel = sp->securityLevel;
00521
00522 }
00523 *len = 1;
00524 DEBUGMSGTL(("transport_callback", "hook_build exit\n"));
00525 return 1;
00526 }
00527
00528 int
00529 netsnmp_callback_check_packet(u_char * pkt, size_t len)
00530 {
00531 return 1;
00532 }
00533
00534 netsnmp_pdu *
00535 netsnmp_callback_create_pdu(netsnmp_transport *transport,
00536 void *opaque, size_t olength)
00537 {
00538 netsnmp_pdu *pdu;
00539 netsnmp_callback_pass *cp =
00540 callback_pop_queue(((netsnmp_callback_info *) transport->data)->
00541 callback_num);
00542 if (!cp)
00543 return NULL;
00544 pdu = cp->pdu;
00545 pdu->transport_data = opaque;
00546 pdu->transport_data_length = olength;
00547 if (opaque)
00548 *((int *) opaque) = cp->return_transport_num;
00549 SNMP_FREE(cp);
00550 return pdu;
00551 }
00552
00553 netsnmp_session *
00554 netsnmp_callback_open(int attach_to,
00555 int (*return_func) (int op,
00556 netsnmp_session * session,
00557 int reqid, netsnmp_pdu *pdu,
00558 void *magic),
00559 int (*fpre_parse) (netsnmp_session *,
00560 struct netsnmp_transport_s *,
00561 void *, int),
00562 int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
00563 int))
00564 {
00565 netsnmp_session callback_sess, *callback_ss;
00566 netsnmp_transport *callback_tr;
00567
00568 callback_tr = netsnmp_callback_transport(attach_to);
00569 snmp_sess_init(&callback_sess);
00570 callback_sess.callback = return_func;
00571 if (attach_to) {
00572
00573
00574
00575
00576
00577
00578 } else {
00579 callback_sess.isAuthoritative = SNMP_SESS_AUTHORITATIVE;
00580 }
00581 callback_sess.remote_port = 0;
00582 callback_sess.retries = 0;
00583 callback_sess.timeout = 30000000;
00584 callback_sess.version = SNMP_DEFAULT_VERSION;
00585 callback_ss = snmp_add_full(&callback_sess, callback_tr,
00586 fpre_parse,
00587 netsnmp_callback_hook_parse, fpost_parse,
00588 netsnmp_callback_hook_build,
00589 NULL,
00590 netsnmp_callback_check_packet,
00591 netsnmp_callback_create_pdu);
00592 if (callback_ss)
00593 callback_ss->local_port =
00594 ((netsnmp_callback_info *) callback_tr->data)->callback_num;
00595 return callback_ss;
00596 }
00597
00598
00599
00600 void
00601 netsnmp_clear_callback_list(void)
00602 {
00603
00604 netsnmp_transport_list *list = trlist, *next = NULL;
00605 netsnmp_transport *tr = NULL;
00606
00607 DEBUGMSGTL(("callback_clear", "called netsnmp_callback_clear_list()\n"));
00608 while (list != NULL) {
00609 next = list->next;
00610 tr = list->transport;
00611
00612 if (tr != NULL) {
00613 tr->f_close(tr);
00614 netsnmp_transport_remove_from_list(&trlist, list->transport);
00615 netsnmp_transport_free(list->transport);
00616 }
00617 list = next;
00618 }
00619 trlist = NULL;
00620
00621 }
00622
00623 #endif