added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / ucd-snmp / proxy.c
1 #include <net-snmp/net-snmp-config.h>
2
3 #include <sys/types.h>
4 #if HAVE_WINSOCK_H
5 #include <winsock.h>
6 #endif
7 #if HAVE_STRING_H
8 #include <string.h>
9 #endif
10 #ifdef HAVE_NETINET_IN_H
11 #include <netinet/in.h>
12 #endif
13
14 #include <net-snmp/net-snmp-includes.h>
15 #include <net-snmp/agent/net-snmp-agent-includes.h>
16
17 #include "proxy.h"
18
19 static struct simple_proxy *proxies = NULL;
20
21 oid             testoid[] = { 1, 3, 6, 1, 4, 1, 2021, 8888, 1 };
22
23 /*
24  * this must be standardized somewhere, right? 
25  */
26 #define MAX_ARGS 128
27
28 char           *context_string;
29
30 static void
31 proxyOptProc(int argc, char *const *argv, int opt)
32 {
33     switch (opt) {
34     case 'C':
35         while (*optarg) {
36             switch (*optarg++) {
37             case 'n':
38                 optind++;
39                 if (optind < argc) {
40                     context_string = argv[optind - 1];
41                 } else {
42                     config_perror("No context name passed to -Cn");
43                 }
44                 break;
45             default:
46                 config_perror("unknown argument passed to -C");
47                 break;
48             }
49         }
50         break;
51     default:
52         break;
53         /*
54          * shouldn't get here 
55          */
56     }
57 }
58
59 void
60 proxy_parse_config(const char *token, char *line)
61 {
62     /*
63      * proxy args [base-oid] [remap-to-remote-oid] 
64      */
65
66     netsnmp_session session, *ss;
67     struct simple_proxy *newp, **listpp;
68     char            args[MAX_ARGS][SPRINT_MAX_LEN], *argv[MAX_ARGS];
69     int             argn, arg;
70     char           *cp;
71     netsnmp_handler_registration *reg;
72
73     context_string = NULL;
74
75     DEBUGMSGTL(("proxy_config", "entering\n"));
76
77     /*
78      * create the argv[] like array 
79      */
80     strcpy(argv[0] = args[0], "snmpd-proxy");   /* bogus entry for getopt() */
81     for (argn = 1, cp = line; cp && argn < MAX_ARGS;
82          cp = copy_nword(cp, argv[argn] = args[argn++], SPRINT_MAX_LEN)) {
83     }
84
85     for (arg = 0; arg < argn; arg++) {
86         DEBUGMSGTL(("proxy_args", "final args: %d = %s\n", arg,
87                     argv[arg]));
88     }
89
90     DEBUGMSGTL(("proxy_config", "parsing args: %d\n", argn));
91     arg = snmp_parse_args(argn, argv, &session, "C:", proxyOptProc);
92     DEBUGMSGTL(("proxy_config", "done parsing args\n"));
93
94     if (arg >= argn) {
95         config_perror("missing base oid");
96         return;
97     }
98
99     SOCK_STARTUP;
100     /*
101      * usm_set_reportErrorOnUnknownID(0); 
102      *
103      * hack, stupid v3 ASIs. 
104      */
105     /*
106      * XXX: on a side note, we don't really need to be a reference
107      * platform any more so the proper thing to do would be to fix
108      * snmplib/snmpusm.c to pass in the pdu type to usm_process_incoming
109      * so this isn't needed. 
110      */
111     ss = snmp_open(&session);
112     /*
113      * usm_set_reportErrorOnUnknownID(1); 
114      */
115     if (ss == NULL) {
116         /*
117          * diagnose snmp_open errors with the input netsnmp_session pointer 
118          */
119         snmp_sess_perror("snmpget", &session);
120         SOCK_CLEANUP;
121         return;
122     }
123
124     newp = (struct simple_proxy *) calloc(1, sizeof(struct simple_proxy));
125
126     newp->sess = ss;
127     DEBUGMSGTL(("proxy_init", "name = %s\n", args[arg]));
128     newp->name_len = MAX_OID_LEN;
129     if (!snmp_parse_oid(args[arg++], newp->name, &newp->name_len)) {
130         snmp_perror("proxy");
131         config_perror("illegal proxy oid specified\n");
132         return;
133     }
134
135     if (arg < argn) {
136         DEBUGMSGTL(("proxy_init", "base = %s\n", args[arg]));
137         newp->base_len = MAX_OID_LEN;
138         if (!snmp_parse_oid(args[arg++], newp->base, &newp->base_len)) {
139             snmp_perror("proxy");
140             config_perror("illegal variable name specified (base oid)\n");
141             return;
142         }
143     }
144
145     DEBUGMSGTL(("proxy_init", "registering at: "));
146     DEBUGMSGOID(("proxy_init", newp->name, newp->name_len));
147     DEBUGMSG(("proxy_init", "\n"));
148
149     /*
150      * add to our chain 
151      */
152     /*
153      * must be sorted! 
154      */
155     listpp = &proxies;
156     while (*listpp &&
157            snmp_oid_compare(newp->name, newp->name_len,
158                             (*listpp)->name, (*listpp)->name_len) > 0) {
159         listpp = &((*listpp)->next);
160     }
161
162     /*
163      * listpp should be next in line from us. 
164      */
165     if (*listpp) {
166         /*
167          * make our next in the link point to the current link 
168          */
169         newp->next = *listpp;
170     }
171     /*
172      * replace current link with us 
173      */
174     *listpp = newp;
175
176     reg = netsnmp_create_handler_registration("proxy",
177                                               proxy_handler,
178                                               newp->name,
179                                               newp->name_len,
180                                               HANDLER_CAN_RWRITE);
181     reg->handler->myvoid = newp;
182     if (context_string)
183         reg->contextName = strdup(context_string);
184
185     netsnmp_register_handler(reg);
186 }
187
188 void
189 proxy_free_config(void)
190 {
191     struct simple_proxy *rm;
192
193     /*
194      * XXX: finish me (needs unregister_mib()) 
195      */
196     return;
197
198     while (proxies) {
199         rm = proxies;
200         proxies = rm->next;
201         SNMP_FREE(rm->variables);
202         snmp_close(rm->sess);
203         SNMP_FREE(rm);
204     }
205 }
206
207 void
208 init_proxy(void)
209 {
210     snmpd_register_config_handler("proxy", proxy_parse_config,
211                                   proxy_free_config,
212                                   "[snmpcmd args] host oid [remoteoid]");
213 }
214
215 int
216 proxy_handler(netsnmp_mib_handler *handler,
217               netsnmp_handler_registration *reginfo,
218               netsnmp_agent_request_info *reqinfo,
219               netsnmp_request_info *requests)
220 {
221
222     netsnmp_pdu    *pdu;
223     struct simple_proxy *sp;
224     oid            *ourname;
225     size_t          ourlength;
226     netsnmp_request_info *request = requests;
227
228     DEBUGMSGTL(("proxy", "proxy handler starting, mode = %d\n",
229                 reqinfo->mode));
230
231     switch (reqinfo->mode) {
232     case MODE_GET:
233     case MODE_GETNEXT:
234     case MODE_GETBULK:         /* WWWXXX */
235         pdu = snmp_pdu_create(reqinfo->mode);
236         break;
237
238     case MODE_SET_COMMIT:
239         pdu = snmp_pdu_create(SNMP_MSG_SET);
240         break;
241
242     default:
243         snmp_log(LOG_WARNING, "unsupported mode for proxy called\n");
244         return SNMP_ERR_NOERROR;
245     }
246
247     sp = (struct simple_proxy *) handler->myvoid;
248
249     if (!pdu || !sp) {
250         netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_GENERR);
251         return SNMP_ERR_NOERROR;
252     }
253
254     while (request) {
255         ourname = request->requestvb->name;
256         ourlength = request->requestvb->name_length;
257
258         if (sp->base_len > 0) {
259             if ((ourlength - sp->name_len + sp->base_len) > MAX_OID_LEN) {
260                 /*
261                  * too large 
262                  */
263                 snmp_log(LOG_ERR,
264                          "proxy oid request length is too long\n");
265                 return SNMP_ERR_NOERROR;
266             }
267             /*
268              * suffix appended? 
269              */
270             DEBUGMSGTL(("proxy", "length=%d, base_len=%d, name_len=%d\n",
271                         ourlength, sp->base_len, sp->name_len));
272             if (ourlength > (int) sp->name_len)
273                 memcpy(&(sp->base[sp->base_len]), &(ourname[sp->name_len]),
274                        sizeof(oid) * (ourlength - sp->name_len));
275             ourlength = ourlength - sp->name_len + sp->base_len;
276             ourname = sp->base;
277         }
278
279         snmp_pdu_add_variable(pdu, ourname, ourlength,
280                               request->requestvb->type,
281                               request->requestvb->val.string,
282                               request->requestvb->val_len);
283         request->delegated = 1;
284         request = request->next;
285     }
286
287     /*
288      * send the request out 
289      */
290     DEBUGMSGTL(("proxy", "sending pdu\n"));
291     snmp_async_send(sp->sess, pdu, proxy_got_response,
292                     netsnmp_create_delegated_cache(handler, reginfo,
293                                                    reqinfo, requests,
294                                                    (void *) sp));
295     return SNMP_ERR_NOERROR;
296 }
297
298 int
299 proxy_got_response(int operation, netsnmp_session * sess, int reqid,
300                    netsnmp_pdu *pdu, void *cb_data)
301 {
302     netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) cb_data;
303     netsnmp_request_info *requests, *request;
304     netsnmp_variable_list *vars, *var;
305
306     struct simple_proxy *sp;
307     oid             myname[MAX_OID_LEN];
308     size_t          myname_len = MAX_OID_LEN;
309
310     cache = netsnmp_handler_check_cache(cache);
311     requests = cache->requests;
312
313
314     sp = (struct simple_proxy *) cache->localinfo;
315
316     if (!cache || !sp) {
317         DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n"));
318         return SNMP_ERR_NOERROR;
319     }
320
321
322     if (operation == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
323         /*
324          * WWWXXX: don't leave requests delayed if operation is
325          * something like TIMEOUT 
326          */
327         vars = pdu->variables;
328
329         /*
330          * update the original request varbinds with the results 
331          */
332         for (var = vars, request = requests;
333              request && var;
334              request = request->next, var = var->next_variable) {
335             snmp_set_var_typed_value(request->requestvb, var->type,
336                                      var->val.string, var->val_len);
337
338             DEBUGMSGTL(("proxy", "got response... "));
339             DEBUGMSGOID(("proxy", var->name, var->name_length));
340             DEBUGMSG(("proxy", "\n"));
341             request->delegated = 0;
342
343             /*
344              * copy the oid it belongs to 
345              */
346             if (sp->base_len &&
347                 (var->name_length < sp->base_len ||
348                  snmp_oid_compare(var->name, sp->base_len, sp->base,
349                                   sp->base_len) != 0)) {
350                 DEBUGMSGTL(("proxy", "out of registered range... "));
351                 DEBUGMSGOID(("proxy", var->name, sp->base_len));
352                 DEBUGMSG(("proxy", " (%d) != ", sp->base_len));
353                 DEBUGMSGOID(("proxy", sp->base, sp->base_len));
354                 DEBUGMSG(("proxy", "\n"));
355
356                 continue;
357             } else if (!sp->base_len &&
358                        (var->name_length < sp->name_len ||
359                         snmp_oid_compare(var->name, sp->name_len, sp->name,
360                                          sp->name_len) != 0)) {
361                 DEBUGMSGTL(("proxy", "out of registered base range...\n"));
362                 /*
363                  * or not if its out of our search range 
364                  */
365                 continue;
366             } else {
367                 if (sp->base_len) {
368                     /*
369                      * XXX: oid size maxed? 
370                      */
371                     memcpy(myname, sp->name, sizeof(oid) * sp->name_len);
372                     myname_len =
373                         sp->name_len + var->name_length - sp->base_len;
374                     if (myname_len > MAX_OID_LEN) {
375                         snmp_log(LOG_WARNING,
376                                  "proxy OID return length too long.\n");
377                         netsnmp_set_request_error(cache->reqinfo, requests,
378                                                   SNMP_ERR_GENERR);
379                         if (pdu)
380                             snmp_free_pdu(pdu);
381                         netsnmp_free_delegated_cache(cache);
382                         return 1;
383                     }
384
385                     if (var->name_length > sp->base_len)
386                         memcpy(&myname[sp->name_len],
387                                &var->name[sp->base_len],
388                                sizeof(oid) * (var->name_length -
389                                               sp->base_len));
390                     snmp_set_var_objid(request->requestvb, myname,
391                                        myname_len);
392                 } else {
393                     snmp_set_var_objid(request->requestvb, var->name,
394                                        var->name_length);
395                 }
396             }
397         }
398
399         if (request || var) {
400             /*
401              * ack, this is bad.  The # of varbinds don't match and
402              * there is no way to fix the problem 
403              */
404             if (pdu)
405                 snmp_free_pdu(pdu);
406             snmp_log(LOG_ERR,
407                      "response to proxy request illegal.  We're screwed.\n");
408             netsnmp_set_request_error(cache->reqinfo, requests,
409                                       SNMP_ERR_GENERR);
410         }
411
412         /*
413          * free the response 
414          */
415         if (pdu && 0)
416             snmp_free_pdu(pdu);
417     } else {
418         DEBUGMSGTL(("proxy", "no response received: op = %d\n",
419                     operation));
420     }
421
422     netsnmp_free_delegated_cache(cache);
423     return 1;
424 }