/src/net-snmp/agent/mibgroup/smux/smux.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Smux module authored by Rohit Dube. |
3 | | * Rewritten by Nick Amato <naamato@merit.net>. |
4 | | */ |
5 | | |
6 | | #include <net-snmp/net-snmp-config.h> |
7 | | #include <net-snmp/net-snmp-features.h> |
8 | | #include <sys/types.h> |
9 | | #include <ctype.h> |
10 | | |
11 | | #ifdef HAVE_IO_H |
12 | | #include <io.h> |
13 | | #endif |
14 | | #include <stdio.h> |
15 | | #ifdef HAVE_STDLIB_H |
16 | | #include <stdlib.h> |
17 | | #endif |
18 | | #ifdef HAVE_STRING_H |
19 | | #include <string.h> |
20 | | #else |
21 | | #include <strings.h> |
22 | | #endif |
23 | | #ifdef HAVE_UNISTD_H |
24 | | #include <unistd.h> |
25 | | #endif |
26 | | #ifdef HAVE_ERR_H |
27 | | #include <err.h> |
28 | | #endif |
29 | | #ifdef TIME_WITH_SYS_TIME |
30 | | # include <sys/time.h> |
31 | | # include <time.h> |
32 | | #else |
33 | | # ifdef HAVE_SYS_TIME_H |
34 | | # include <sys/time.h> |
35 | | # else |
36 | | # include <time.h> |
37 | | # endif |
38 | | #endif |
39 | | #include <errno.h> |
40 | | #ifdef HAVE_NETDB_H |
41 | | #include <netdb.h> |
42 | | #endif |
43 | | |
44 | | #include <sys/stat.h> |
45 | | #ifdef HAVE_SYS_SOCKET_H |
46 | | #include <sys/socket.h> |
47 | | #endif |
48 | | #ifdef HAVE_SYS_FILIO_H |
49 | | #include <sys/filio.h> |
50 | | #endif |
51 | | |
52 | | #ifdef HAVE_NETINET_IN_H |
53 | | #include <netinet/in.h> |
54 | | #endif |
55 | | |
56 | | #ifdef HAVE_ARPA_INET_H |
57 | | #include <arpa/inet.h> |
58 | | #endif |
59 | | |
60 | | #ifdef HAVE_SYS_IOCTL_H |
61 | | #include <sys/ioctl.h> |
62 | | #endif |
63 | | |
64 | | #include <net-snmp/net-snmp-includes.h> |
65 | | #include <net-snmp/agent/net-snmp-agent-includes.h> |
66 | | #include <net-snmp/library/tools.h> |
67 | | |
68 | | #include "smux.h" |
69 | | #include "snmpd.h" |
70 | | |
71 | | netsnmp_feature_require(snprint_objid); |
72 | | |
73 | | long smux_long; |
74 | | u_long smux_ulong; |
75 | | struct sockaddr_in smux_sa; |
76 | | struct counter64 smux_counter64; |
77 | | oid smux_objid[MAX_OID_LEN]; |
78 | | u_char smux_str[SMUXMAXSTRLEN]; |
79 | | int smux_listen_sd = -1; |
80 | | |
81 | | static struct timeval smux_rcv_timeout; |
82 | | static long smux_reqid; |
83 | | |
84 | | static u_char *smux_open_process(int, u_char *, size_t *, int *); |
85 | | static u_char *smux_rreq_process(int, u_char *, size_t *); |
86 | | static u_char *smux_close_process(int, u_char *, size_t *); |
87 | | static u_char *smux_trap_process(u_char *, size_t *); |
88 | | static u_char *smux_parse(u_char *, oid *, size_t *, size_t *, u_char *); |
89 | | static u_char *smux_parse_var(u_char *, size_t *, oid *, size_t *, |
90 | | size_t *, u_char *); |
91 | | static void smux_send_close(int, int); |
92 | | static void smux_list_detach(smux_reg **, smux_reg *); |
93 | | static void smux_replace_active(smux_reg *, smux_reg *); |
94 | | static void smux_peer_cleanup(int); |
95 | | static int smux_auth_peer(oid *, size_t, char *, int); |
96 | | static int smux_build(u_char, long, oid *, |
97 | | size_t *, u_char, u_char *, size_t, u_char *, |
98 | | size_t *); |
99 | | static int smux_list_add(smux_reg **, smux_reg *); |
100 | | static int smux_pdu_process(int, u_char *, size_t); |
101 | | static int smux_send_rrsp(int, int); |
102 | | static smux_reg *smux_find_match(smux_reg *, int, oid *, size_t, long); |
103 | | static smux_reg *smux_find_replacement(oid *, size_t); |
104 | | u_char *var_smux_get(oid *, size_t, oid *, size_t *, int, size_t *, |
105 | | u_char *); |
106 | | int var_smux_write(int, u_char *, u_char, size_t, oid *, size_t); |
107 | | |
108 | | static smux_reg *ActiveRegs; /* Active registrations */ |
109 | | static smux_reg *PassiveRegs; /* Currently unused registrations */ |
110 | | |
111 | | static smux_peer_auth *Auths[SMUX_MAX_PEERS]; /* Configured peers */ |
112 | | static int nauths, npeers = 0; |
113 | | |
114 | | |
115 | | |
116 | | void |
117 | | smux_parse_smux_socket(const char *token, char *cptr) |
118 | 0 | { |
119 | 0 | DEBUGMSGTL(("smux", "port spec: %s\n", cptr)); |
120 | 0 | netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_SMUX_SOCKET, cptr); |
121 | 0 | } |
122 | | |
123 | | void |
124 | | smux_parse_peer_auth(const char *token, char *cptr) |
125 | 0 | { |
126 | 0 | smux_peer_auth *aptr; |
127 | 0 | char *password_cptr; |
128 | 0 | int rv; |
129 | |
|
130 | 0 | if ((aptr = calloc(1, sizeof(smux_peer_auth))) == NULL) { |
131 | 0 | snmp_log_perror("smux_parse_peer_auth: malloc"); |
132 | 0 | return; |
133 | 0 | } |
134 | 0 | if (nauths == SMUX_MAX_PEERS) { |
135 | 0 | config_perror("Too many smuxpeers"); |
136 | 0 | free(aptr); |
137 | 0 | return; |
138 | 0 | } |
139 | | |
140 | 0 | password_cptr = strchr(cptr, ' '); |
141 | 0 | if (password_cptr) |
142 | 0 | *(password_cptr++) = '\0'; |
143 | | |
144 | | /* |
145 | | * oid |
146 | | */ |
147 | 0 | aptr->sa_active_fd = -1; |
148 | 0 | aptr->sa_oid_len = MAX_OID_LEN; |
149 | 0 | rv = read_objid( cptr, aptr->sa_oid, &aptr->sa_oid_len ); |
150 | 0 | DEBUGMSGTL(("smux_conf", "parsing registration for: %s\n", cptr)); |
151 | 0 | if (!rv) |
152 | 0 | config_perror("Error parsing smux oid"); |
153 | |
|
154 | 0 | if (password_cptr != NULL) { /* Do we have a password or not? */ |
155 | 0 | DEBUGMSGTL(("smux_conf", "password is: %s\n", |
156 | 0 | SNMP_STRORNULL(password_cptr))); |
157 | | |
158 | | /* |
159 | | * password |
160 | | */ |
161 | 0 | if (*password_cptr) |
162 | 0 | strlcpy(aptr->sa_passwd, password_cptr, sizeof(aptr->sa_passwd)); |
163 | 0 | } else { |
164 | | /* |
165 | | * null passwords OK |
166 | | */ |
167 | 0 | DEBUGMSGTL(("smux_conf", "null password\n")); |
168 | 0 | } |
169 | |
|
170 | 0 | Auths[nauths++] = aptr; |
171 | 0 | return; |
172 | 0 | } |
173 | | |
174 | | void |
175 | | smux_free_peer_auth(void) |
176 | 2 | { |
177 | 2 | int i; |
178 | | |
179 | 2 | for (i = 0; i < nauths; i++) { |
180 | 0 | free(Auths[i]); |
181 | 0 | Auths[i] = NULL; |
182 | 0 | } |
183 | 2 | nauths = 0; |
184 | 2 | } |
185 | | |
186 | | void |
187 | | init_smux(void) |
188 | 1 | { |
189 | 1 | snmpd_register_config_handler("smuxpeer", smux_parse_peer_auth, |
190 | 1 | smux_free_peer_auth, |
191 | 1 | "OID-IDENTITY PASSWORD"); |
192 | 1 | snmpd_register_config_handler("smuxsocket", |
193 | 1 | smux_parse_smux_socket, NULL, |
194 | 1 | "SMUX bind address"); |
195 | 1 | } |
196 | | |
197 | | void |
198 | | real_init_smux(void) |
199 | 0 | { |
200 | 0 | struct sockaddr_in lo_socket; |
201 | 0 | char *smux_socket; |
202 | 0 | int one = 1; |
203 | |
|
204 | 0 | if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) { |
205 | 0 | smux_listen_sd = -1; |
206 | 0 | return; |
207 | 0 | } |
208 | | |
209 | | /* |
210 | | * Reqid |
211 | | */ |
212 | 0 | smux_reqid = 0; |
213 | 0 | smux_listen_sd = -1; |
214 | | |
215 | | /* |
216 | | * Receive timeout |
217 | | */ |
218 | 0 | smux_rcv_timeout.tv_sec = 0; |
219 | 0 | smux_rcv_timeout.tv_usec = 500000; |
220 | | |
221 | | /* |
222 | | * Get ready to listen on the SMUX port |
223 | | */ |
224 | 0 | memset(&lo_socket, (0), sizeof(lo_socket)); |
225 | 0 | lo_socket.sin_family = AF_INET; |
226 | |
|
227 | 0 | smux_socket = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, |
228 | 0 | NETSNMP_DS_SMUX_SOCKET); |
229 | | #ifdef NETSNMP_ENABLE_LOCAL_SMUX |
230 | | if (!smux_socket) |
231 | | smux_socket = "127.0.0.1"; /* By default, listen on localhost only */ |
232 | | #endif |
233 | 0 | netsnmp_sockaddr_in( &lo_socket, smux_socket, SMUXPORT ); |
234 | |
|
235 | 0 | if ((smux_listen_sd = (int) socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
236 | 0 | snmp_log_perror("[init_smux] socket failed"); |
237 | 0 | return; |
238 | 0 | } |
239 | 0 | #ifdef SO_REUSEADDR |
240 | | /* |
241 | | * At least on Linux, when the master agent terminates, any |
242 | | * TCP connections for SMUX peers are put in the TIME_WAIT |
243 | | * state for about 60 seconds. If the master agent is started |
244 | | * during this time, the bind for the listening socket will |
245 | | * fail because the SMUX port is in use. |
246 | | */ |
247 | 0 | if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, |
248 | 0 | sizeof(one)) < 0) { |
249 | 0 | snmp_log_perror("[init_smux] setsockopt(SO_REUSEADDR) failed"); |
250 | 0 | } |
251 | 0 | #endif /* SO_REUSEADDR */ |
252 | |
|
253 | 0 | if (bind(smux_listen_sd, (struct sockaddr *) &lo_socket, |
254 | 0 | sizeof(lo_socket)) < 0) { |
255 | 0 | snmp_log_perror("[init_smux] bind failed"); |
256 | 0 | close(smux_listen_sd); |
257 | 0 | smux_listen_sd = -1; |
258 | 0 | return; |
259 | 0 | } |
260 | 0 | #ifdef SO_KEEPALIVE |
261 | 0 | if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, |
262 | 0 | sizeof(one)) < 0) { |
263 | 0 | snmp_log_perror("[init_smux] setsockopt(SO_KEEPALIVE) failed"); |
264 | 0 | close(smux_listen_sd); |
265 | 0 | smux_listen_sd = -1; |
266 | 0 | return; |
267 | 0 | } |
268 | 0 | #endif /* SO_KEEPALIVE */ |
269 | | |
270 | 0 | if (listen(smux_listen_sd, SOMAXCONN) == -1) { |
271 | 0 | snmp_log_perror("[init_smux] listen failed"); |
272 | 0 | close(smux_listen_sd); |
273 | 0 | smux_listen_sd = -1; |
274 | 0 | return; |
275 | 0 | } |
276 | | |
277 | 0 | DEBUGMSGTL(("smux_init", |
278 | 0 | "[smux_init] done; smux listen sd is %d, smux port is %d\n", |
279 | 0 | smux_listen_sd, ntohs(lo_socket.sin_port))); |
280 | 0 | } |
281 | | |
282 | | static int |
283 | | smux_handler(netsnmp_mib_handler *handler, |
284 | | netsnmp_handler_registration *reginfo, |
285 | | netsnmp_agent_request_info *reqinfo, |
286 | | netsnmp_request_info *requests) |
287 | 0 | { |
288 | 0 | u_char *access = NULL; |
289 | 0 | size_t var_len; |
290 | 0 | int exact = 1; |
291 | 0 | int status = 0; |
292 | 0 | u_char var_type; |
293 | 0 | static long old_reqid = -1; |
294 | 0 | static long old_sessid = -1; |
295 | 0 | long new_reqid, new_sessid; |
296 | | |
297 | | /* Increment the reqid of outgoing SMUX messages only when processing |
298 | | * new incoming SNMP message, i.e. when reqid or session id chamges */ |
299 | 0 | new_reqid = reqinfo->asp->pdu->reqid; |
300 | 0 | new_sessid = reqinfo->asp->session->sessid; |
301 | 0 | DEBUGMSGTL(("smux", "smux_handler: incoming reqid=%ld, sessid=%ld\n", |
302 | 0 | new_reqid, new_sessid)); |
303 | 0 | if (old_reqid != new_reqid || old_sessid != new_sessid) { |
304 | 0 | smux_reqid++; |
305 | 0 | old_reqid = new_reqid; |
306 | 0 | old_sessid = new_sessid; |
307 | 0 | } |
308 | |
|
309 | 0 | switch (reqinfo->mode) { |
310 | 0 | case MODE_GETNEXT: |
311 | 0 | case MODE_GETBULK: |
312 | 0 | exact = 0; |
313 | 0 | } |
314 | |
|
315 | 0 | for (; requests; requests = requests->next) { |
316 | 0 | switch(reqinfo->mode) { |
317 | 0 | case MODE_GET: |
318 | 0 | case MODE_GETNEXT: |
319 | 0 | case MODE_SET_RESERVE1: |
320 | 0 | access = var_smux_get(reginfo->rootoid, |
321 | 0 | reginfo->rootoid_len, |
322 | 0 | requests->requestvb->name, |
323 | 0 | &requests->requestvb->name_length, |
324 | 0 | exact, |
325 | 0 | &var_len, |
326 | 0 | &var_type); |
327 | 0 | if (access) |
328 | 0 | if (reqinfo->mode != MODE_SET_RESERVE1) |
329 | 0 | snmp_set_var_typed_value(requests->requestvb, |
330 | 0 | var_type, access, var_len); |
331 | 0 | if (reqinfo->mode != MODE_SET_RESERVE1) |
332 | 0 | break; |
333 | | /* fall through if MODE_SET_RESERVE1 */ |
334 | 0 | NETSNMP_FALLTHROUGH; |
335 | |
|
336 | 0 | default: |
337 | | /* SET processing */ |
338 | 0 | status = var_smux_write(reqinfo->mode, |
339 | 0 | requests->requestvb->val.string, |
340 | 0 | requests->requestvb->type, |
341 | 0 | requests->requestvb->val_len, |
342 | 0 | requests->requestvb->name, |
343 | 0 | requests->requestvb->name_length); |
344 | 0 | if (status != SNMP_ERR_NOERROR) { |
345 | 0 | netsnmp_set_request_error(reqinfo, requests, status); |
346 | 0 | } |
347 | 0 | } |
348 | 0 | } |
349 | 0 | return SNMP_ERR_NOERROR; |
350 | 0 | } |
351 | | |
352 | | u_char * |
353 | | var_smux_get(oid *root, size_t root_len, |
354 | | oid * name, size_t * length, |
355 | | int exact, size_t * var_len, u_char *var_type) |
356 | 0 | { |
357 | 0 | u_char *valptr; |
358 | 0 | smux_reg *rptr; |
359 | | |
360 | | /* |
361 | | * search the active registration list |
362 | | */ |
363 | 0 | for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) { |
364 | 0 | if (0 >= snmp_oidtree_compare(root, root_len, rptr->sr_name, |
365 | 0 | rptr->sr_name_len)) |
366 | 0 | break; |
367 | 0 | } |
368 | 0 | if (rptr == NULL) |
369 | 0 | return NULL; |
370 | 0 | else if (exact && (*length < rptr->sr_name_len)) |
371 | 0 | return NULL; |
372 | | |
373 | 0 | valptr = smux_snmp_process(exact, name, length, |
374 | 0 | var_len, var_type, rptr->sr_fd); |
375 | |
|
376 | 0 | if (valptr == NULL) |
377 | 0 | return NULL; |
378 | | |
379 | 0 | if ((snmp_oidtree_compare(name, *length, rptr->sr_name, |
380 | 0 | rptr->sr_name_len)) != 0) { |
381 | | /* |
382 | | * the peer has returned a value outside |
383 | | * * of the registered tree |
384 | | */ |
385 | 0 | return NULL; |
386 | 0 | } else { |
387 | 0 | return valptr; |
388 | 0 | } |
389 | 0 | } |
390 | | |
391 | | int |
392 | | var_smux_write(int action, |
393 | | u_char * var_val, |
394 | | u_char var_val_type, |
395 | | size_t var_val_len, |
396 | | oid * name, size_t name_len) |
397 | 0 | { |
398 | 0 | smux_reg *rptr; |
399 | 0 | u_char buf[SMUXMAXPKTSIZE], *ptr, sout[3], type; |
400 | 0 | int reterr; |
401 | 0 | size_t var_len, datalen, name_length, packet_len; |
402 | 0 | size_t len; |
403 | 0 | ssize_t tmp_len; |
404 | 0 | long reqid, errsts, erridx; |
405 | 0 | u_char *dataptr; |
406 | |
|
407 | 0 | DEBUGMSGTL(("smux", "[var_smux_write] entering var_smux_write\n")); |
408 | |
|
409 | 0 | len = SMUXMAXPKTSIZE; |
410 | 0 | reterr = SNMP_ERR_NOERROR; |
411 | 0 | var_len = var_val_len; |
412 | 0 | name_length = name_len; |
413 | | |
414 | | /* |
415 | | * XXX find the descriptor again |
416 | | */ |
417 | 0 | for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) { |
418 | 0 | if (!snmp_oidtree_compare(name, name_len, rptr->sr_name, |
419 | 0 | rptr->sr_name_len)) |
420 | 0 | break; |
421 | 0 | } |
422 | |
|
423 | 0 | if (!rptr) { |
424 | 0 | DEBUGMSGTL(("smux", "[var_smux_write] unknown registration\n")); |
425 | 0 | return SNMP_ERR_GENERR; |
426 | 0 | } |
427 | | |
428 | 0 | switch (action) { |
429 | 0 | case RESERVE1: |
430 | 0 | DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE1\n")); |
431 | | |
432 | | /* |
433 | | * length might be long |
434 | | */ |
435 | 0 | var_len += (*(var_val + 1) & ASN_LONG_LEN) ? |
436 | 0 | var_len + ((*(var_val + 1) & 0x7F) + 2) : 2; |
437 | |
|
438 | 0 | switch (var_val_type) { |
439 | 0 | case ASN_INTEGER: |
440 | 0 | case ASN_OCTET_STR: |
441 | 0 | case ASN_COUNTER: |
442 | 0 | case ASN_GAUGE: |
443 | 0 | case ASN_TIMETICKS: |
444 | 0 | case ASN_UINTEGER: |
445 | 0 | case ASN_COUNTER64: |
446 | 0 | case ASN_IPADDRESS: |
447 | 0 | case ASN_OPAQUE: |
448 | 0 | case ASN_NSAP: |
449 | 0 | case ASN_OBJECT_ID: |
450 | 0 | case ASN_BIT_STR: |
451 | 0 | datalen = var_val_len; |
452 | 0 | dataptr = var_val; |
453 | 0 | break; |
454 | 0 | case SNMP_NOSUCHOBJECT: |
455 | 0 | case SNMP_NOSUCHINSTANCE: |
456 | 0 | case SNMP_ENDOFMIBVIEW: |
457 | 0 | case ASN_NULL: |
458 | 0 | default: |
459 | 0 | DEBUGMSGTL(("smux", |
460 | 0 | "[var_smux_write] variable not supported\n")); |
461 | 0 | return SNMP_ERR_GENERR; |
462 | 0 | break; |
463 | 0 | } |
464 | | |
465 | 0 | if ((smux_build((u_char) SMUX_SET, smux_reqid, |
466 | 0 | name, &name_length, var_val_type, dataptr, |
467 | 0 | datalen, buf, &len)) < 0) { |
468 | 0 | DEBUGMSGTL(("smux", "[var_smux_write] smux build failed\n")); |
469 | 0 | return SNMP_ERR_GENERR; |
470 | 0 | } |
471 | | |
472 | 0 | if (sendto(rptr->sr_fd, (void *) buf, len, 0, NULL, 0) < 0) { |
473 | 0 | DEBUGMSGTL(("smux", "[var_smux_write] send failed\n")); |
474 | 0 | return SNMP_ERR_GENERR; |
475 | 0 | } |
476 | | |
477 | 0 | while (1) { |
478 | | /* |
479 | | * peek at what's received |
480 | | */ |
481 | 0 | if ((len = recvfrom(rptr->sr_fd, (void *) buf, |
482 | 0 | SMUXMAXPKTSIZE, MSG_PEEK, NULL, NULL)) <= 0) { |
483 | 0 | if ((len == -1) && ((errno == EINTR) || (errno == EAGAIN))) |
484 | 0 | { |
485 | 0 | continue; |
486 | 0 | } |
487 | 0 | DEBUGMSGTL(("smux", |
488 | 0 | "[var_smux_write] peek failed or timed out\n")); |
489 | | /* |
490 | | * do we need to do a peer cleanup in this case?? |
491 | | */ |
492 | 0 | smux_peer_cleanup(rptr->sr_fd); |
493 | 0 | smux_snmp_select_list_del(rptr->sr_fd); |
494 | 0 | return SNMP_ERR_GENERR; |
495 | 0 | } |
496 | | |
497 | 0 | DEBUGMSGTL(("smux", "[var_smux_write] Peeked at %" NETSNMP_PRIz |
498 | 0 | "d bytes\n", len)); |
499 | 0 | DEBUGDUMPSETUP("var_smux_write", buf, len); |
500 | | |
501 | | /* |
502 | | * determine if we received more than one packet |
503 | | */ |
504 | 0 | packet_len = len; |
505 | 0 | ptr = asn_parse_header(buf, &packet_len, &type); |
506 | 0 | if (ptr == NULL) |
507 | 0 | return SNMP_ERR_GENERR; |
508 | 0 | packet_len += (ptr - buf); |
509 | 0 | if (len > (ssize_t)packet_len) { |
510 | | /* |
511 | | * set length to receive only the first packet |
512 | | */ |
513 | 0 | len = packet_len; |
514 | 0 | } |
515 | | |
516 | | /* |
517 | | * receive the first packet |
518 | | */ |
519 | 0 | tmp_len = len; |
520 | 0 | do |
521 | 0 | { |
522 | 0 | len = tmp_len; |
523 | 0 | len = recvfrom(rptr->sr_fd, (void *) buf, len, 0, NULL, NULL); |
524 | 0 | } |
525 | 0 | while((len == -1) && ((errno == EINTR) || (errno == EAGAIN))); |
526 | |
|
527 | 0 | if (len <= 0) { |
528 | 0 | DEBUGMSGTL(("smux", |
529 | 0 | "[var_smux_write] recv failed or timed out\n")); |
530 | 0 | smux_peer_cleanup(rptr->sr_fd); |
531 | 0 | smux_snmp_select_list_del(rptr->sr_fd); |
532 | 0 | return SNMP_ERR_GENERR; |
533 | 0 | } |
534 | | |
535 | 0 | DEBUGMSGTL(("smux", "[var_smux_write] Received %" NETSNMP_PRIz |
536 | 0 | "d bytes\n", len)); |
537 | |
|
538 | 0 | if (buf[0] == SMUX_TRAP) { |
539 | 0 | DEBUGMSGTL(("smux", "[var_smux_write] Received trap\n")); |
540 | 0 | DEBUGMSGTL(("smux", "Got trap from peer on fd %d\n", |
541 | 0 | rptr->sr_fd)); |
542 | 0 | ptr = asn_parse_header(buf, &len, &type); |
543 | 0 | if (ptr == NULL) |
544 | 0 | return SNMP_ERR_GENERR; |
545 | 0 | smux_trap_process(ptr, &len); |
546 | | |
547 | | |
548 | | /* |
549 | | * go and peek at received data again |
550 | | */ |
551 | | /* |
552 | | * we could receive the reply or another trap |
553 | | */ |
554 | 0 | } else { |
555 | 0 | ptr = buf; |
556 | 0 | ptr = asn_parse_header(ptr, &len, &type); |
557 | 0 | if ((ptr == NULL) || type != SNMP_MSG_RESPONSE) |
558 | 0 | return SNMP_ERR_GENERR; |
559 | | |
560 | 0 | ptr = |
561 | 0 | asn_parse_int(ptr, &len, &type, &reqid, sizeof(reqid)); |
562 | 0 | if ((ptr == NULL) || type != ASN_INTEGER) |
563 | 0 | return SNMP_ERR_GENERR; |
564 | | |
565 | 0 | ptr = |
566 | 0 | asn_parse_int(ptr, &len, &type, &errsts, |
567 | 0 | sizeof(errsts)); |
568 | 0 | if ((ptr == NULL) || type != ASN_INTEGER) |
569 | 0 | return SNMP_ERR_GENERR; |
570 | | |
571 | 0 | if (errsts) { |
572 | 0 | DEBUGMSGTL(("smux", |
573 | 0 | "[var_smux_write] errsts returned\n")); |
574 | 0 | return (errsts); |
575 | 0 | } |
576 | | |
577 | 0 | ptr = |
578 | 0 | asn_parse_int(ptr, &len, &type, &erridx, |
579 | 0 | sizeof(erridx)); |
580 | 0 | if ((ptr == NULL) || type != ASN_INTEGER) |
581 | 0 | return SNMP_ERR_GENERR; |
582 | | |
583 | 0 | reterr = SNMP_ERR_NOERROR; |
584 | 0 | break; |
585 | 0 | } |
586 | 0 | } /* while (1) */ |
587 | 0 | break; /* case Action == RESERVE1 */ |
588 | | |
589 | 0 | case RESERVE2: |
590 | 0 | DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE2\n")); |
591 | 0 | reterr = SNMP_ERR_NOERROR; |
592 | 0 | break; /* case Action == RESERVE2 */ |
593 | | |
594 | 0 | case FREE: |
595 | 0 | case COMMIT: |
596 | 0 | ptr = sout; |
597 | 0 | *(ptr++) = (u_char) SMUX_SOUT; |
598 | 0 | *(ptr++) = (u_char) 1; |
599 | 0 | if (action == FREE) { |
600 | 0 | *ptr = (u_char) 1; /* rollback */ |
601 | 0 | DEBUGMSGTL(("smux", |
602 | 0 | "[var_smux_write] entering FREE - sending RollBack \n")); |
603 | 0 | } else { |
604 | 0 | *ptr = (u_char) 0; /* commit */ |
605 | 0 | DEBUGMSGTL(("smux", |
606 | 0 | "[var_smux_write] entering FREE - sending Commit \n")); |
607 | 0 | } |
608 | |
|
609 | 0 | if ((sendto(rptr->sr_fd, (void *) sout, 3, 0, NULL, 0)) < 0) { |
610 | 0 | DEBUGMSGTL(("smux", |
611 | 0 | "[var_smux_write] send rollback/commit failed\n")); |
612 | 0 | return SNMP_ERR_GENERR; |
613 | 0 | } |
614 | | |
615 | 0 | reterr = SNMP_ERR_NOERROR; |
616 | 0 | break; /* case Action == COMMIT */ |
617 | | |
618 | 0 | default: |
619 | 0 | break; |
620 | 0 | } |
621 | 0 | return reterr; |
622 | 0 | } |
623 | | |
624 | | |
625 | | int |
626 | | smux_accept(int sd) |
627 | 0 | { |
628 | 0 | u_char data[SMUXMAXPKTSIZE], *ptr, type; |
629 | 0 | struct sockaddr_in in_socket; |
630 | 0 | struct timeval tv; |
631 | 0 | int fail, fd; |
632 | 0 | socklen_t alen; |
633 | 0 | int length; |
634 | 0 | size_t len; |
635 | |
|
636 | 0 | alen = sizeof(struct sockaddr_in); |
637 | | /* |
638 | | * this may be too high |
639 | | */ |
640 | 0 | tv.tv_sec = 5; |
641 | 0 | tv.tv_usec = 0; |
642 | | |
643 | | /* |
644 | | * connection request |
645 | | */ |
646 | 0 | DEBUGMSGTL(("smux", "[smux_accept] Calling accept()\n")); |
647 | 0 | errno = 0; |
648 | 0 | if ((fd = (int) accept(sd, (struct sockaddr *) &in_socket, &alen)) < 0) { |
649 | 0 | snmp_log_perror("[smux_accept] accept failed"); |
650 | 0 | return -1; |
651 | 0 | } else { |
652 | 0 | DEBUGMSGTL(("smux", "[smux_accept] accepted fd %d from %s:%d\n", |
653 | 0 | fd, inet_ntoa(in_socket.sin_addr), |
654 | 0 | ntohs(in_socket.sin_port))); |
655 | 0 | if (npeers + 1 == SMUXMAXPEERS) { |
656 | 0 | snmp_log(LOG_ERR, |
657 | 0 | "[smux_accept] denied peer on fd %d, limit %d reached", |
658 | 0 | fd, SMUXMAXPEERS); |
659 | 0 | close(fd); |
660 | 0 | return -1; |
661 | 0 | } |
662 | | |
663 | | /* |
664 | | * now block for an OpenPDU |
665 | | */ |
666 | 0 | do |
667 | 0 | { |
668 | 0 | length = recvfrom(fd, (char *) data, SMUXMAXPKTSIZE, 0, NULL, NULL); |
669 | 0 | } |
670 | 0 | while((length == -1) && ((errno == EINTR) || (errno == EAGAIN))); |
671 | |
|
672 | 0 | if (length <= 0) { |
673 | 0 | DEBUGMSGTL(("smux", |
674 | 0 | "[smux_accept] peer on fd %d died or timed out\n", |
675 | 0 | fd)); |
676 | 0 | close(fd); |
677 | 0 | return -1; |
678 | 0 | } |
679 | | /* |
680 | | * try to authorize him |
681 | | */ |
682 | 0 | ptr = data; |
683 | 0 | len = length; |
684 | 0 | if ((ptr = asn_parse_header(ptr, &len, &type)) == NULL) { |
685 | 0 | smux_send_close(fd, SMUXC_PACKETFORMAT); |
686 | 0 | close(fd); |
687 | 0 | DEBUGMSGTL(("smux", "[smux_accept] peer on %d sent bad open", fd)); |
688 | 0 | return -1; |
689 | 0 | } else if (type != (u_char) SMUX_OPEN) { |
690 | 0 | smux_send_close(fd, SMUXC_PROTOCOLERROR); |
691 | 0 | close(fd); |
692 | 0 | DEBUGMSGTL(("smux", |
693 | 0 | "[smux_accept] peer on %d did not send open: (%d)\n", |
694 | 0 | fd, type)); |
695 | 0 | return -1; |
696 | 0 | } |
697 | 0 | ptr = smux_open_process(fd, ptr, &len, &fail); |
698 | 0 | if (fail) { |
699 | 0 | smux_send_close(fd, SMUXC_AUTHENTICATIONFAILURE); |
700 | 0 | close(fd); |
701 | 0 | DEBUGMSGTL(("smux", |
702 | 0 | "[smux_accept] peer on %d failed authentication\n", |
703 | 0 | fd)); |
704 | 0 | return -1; |
705 | 0 | } |
706 | | |
707 | | /* |
708 | | * he's OK |
709 | | */ |
710 | 0 | #ifdef SO_RCVTIMEO |
711 | 0 | if (setsockopt |
712 | 0 | (fd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv, sizeof(tv)) < 0) { |
713 | 0 | DEBUGMSGTL(("smux", |
714 | 0 | "[smux_accept] setsockopt(SO_RCVTIMEO) failed fd %d\n", |
715 | 0 | fd)); |
716 | 0 | snmp_log_perror("smux_accept: setsockopt SO_RCVTIMEO"); |
717 | 0 | } |
718 | 0 | #endif |
719 | 0 | npeers++; |
720 | 0 | DEBUGMSGTL(("smux", "[smux_accept] fd %d\n", fd)); |
721 | | |
722 | | /* |
723 | | * Process other PDUs already read, e.g. a registerRequest. |
724 | | */ |
725 | 0 | len = length - (ptr - data); |
726 | 0 | if (smux_pdu_process(fd, ptr, len) < 0) { |
727 | | /* |
728 | | * Easy come, easy go. Clean-up is already done. |
729 | | */ |
730 | 0 | return -1; |
731 | 0 | } |
732 | 0 | } |
733 | 0 | return fd; |
734 | 0 | } |
735 | | |
736 | | int |
737 | | smux_process(int fd) |
738 | 0 | { |
739 | 0 | int length, tmp_length; |
740 | 0 | u_char data[SMUXMAXPKTSIZE]; |
741 | 0 | u_char type, *ptr; |
742 | 0 | size_t packet_len; |
743 | |
|
744 | 0 | do |
745 | 0 | { |
746 | 0 | length = recvfrom(fd, (char *) data, SMUXMAXPKTSIZE, MSG_PEEK, NULL, |
747 | 0 | NULL); |
748 | 0 | } |
749 | 0 | while((length == -1) && ((errno == EINTR) || (errno == EAGAIN))); |
750 | |
|
751 | 0 | if (length <= 0) |
752 | 0 | { |
753 | 0 | if (length < 0) |
754 | 0 | snmp_log_perror("[smux_process] peek failed"); |
755 | 0 | smux_peer_cleanup(fd); |
756 | 0 | return -1; |
757 | 0 | } |
758 | | |
759 | | /* |
760 | | * determine if we received more than one packet |
761 | | */ |
762 | 0 | packet_len = length; |
763 | 0 | ptr = asn_parse_header(data, &packet_len, &type); |
764 | 0 | if (ptr == NULL) |
765 | 0 | return -1; |
766 | 0 | packet_len += (ptr - data); |
767 | 0 | if (length > packet_len) { |
768 | | /* |
769 | | * set length to receive only the first packet |
770 | | */ |
771 | 0 | length = packet_len; |
772 | 0 | } |
773 | |
|
774 | 0 | tmp_length = length; |
775 | 0 | do |
776 | 0 | { |
777 | 0 | length = tmp_length; |
778 | 0 | length = recvfrom(fd, (char *) data, length, 0, NULL, NULL); |
779 | 0 | } |
780 | 0 | while((length == -1) && ((errno == EINTR) || (errno == EAGAIN))); |
781 | |
|
782 | 0 | if (length <= 0) { |
783 | | /* |
784 | | * the peer went away, close this descriptor |
785 | | * * and delete it from the list |
786 | | */ |
787 | 0 | DEBUGMSGTL(("smux", |
788 | 0 | "[smux_process] peer on fd %d died or timed out\n", |
789 | 0 | fd)); |
790 | 0 | smux_peer_cleanup(fd); |
791 | 0 | return -1; |
792 | 0 | } |
793 | | |
794 | 0 | return smux_pdu_process(fd, data, length); |
795 | 0 | } |
796 | | |
797 | | static int |
798 | | smux_pdu_process(int fd, u_char * data, size_t length) |
799 | 0 | { |
800 | 0 | int error; |
801 | 0 | size_t len; |
802 | 0 | u_char *ptr, type; |
803 | |
|
804 | 0 | DEBUGMSGTL(("smux", "[smux_pdu_process] Processing %" NETSNMP_PRIz |
805 | 0 | "d bytes\n", length)); |
806 | |
|
807 | 0 | error = 0; |
808 | 0 | ptr = data; |
809 | 0 | while (error == 0 && ptr != NULL && ptr < data + length) { |
810 | 0 | len = length - (ptr - data); |
811 | 0 | ptr = asn_parse_header(ptr, &len, &type); |
812 | 0 | if (ptr == NULL) { |
813 | 0 | DEBUGMSGTL(("smux", "[smux_pdu_process] cannot parse header\n")); |
814 | 0 | break; |
815 | 0 | } |
816 | 0 | DEBUGMSGTL(("smux", "[smux_pdu_process] type is %d\n", |
817 | 0 | (int) type)); |
818 | 0 | switch (type) { |
819 | 0 | case SMUX_OPEN: |
820 | 0 | smux_send_close(fd, SMUXC_PROTOCOLERROR); |
821 | 0 | DEBUGMSGTL(("smux", |
822 | 0 | "[smux_pdu_process] peer on fd %d sent duplicate open?\n", |
823 | 0 | fd)); |
824 | 0 | smux_peer_cleanup(fd); |
825 | 0 | error = -1; |
826 | 0 | break; |
827 | 0 | case SMUX_CLOSE: |
828 | 0 | ptr = smux_close_process(fd, ptr, &len); |
829 | 0 | smux_peer_cleanup(fd); |
830 | 0 | error = -1; |
831 | 0 | break; |
832 | 0 | case SMUX_RREQ: |
833 | 0 | ptr = smux_rreq_process(fd, ptr, &len); |
834 | 0 | break; |
835 | 0 | case SMUX_RRSP: |
836 | 0 | error = -1; |
837 | 0 | smux_send_close(fd, SMUXC_PROTOCOLERROR); |
838 | 0 | smux_peer_cleanup(fd); |
839 | 0 | DEBUGMSGTL(("smux", |
840 | 0 | "[smux_pdu_process] peer on fd %d sent RRSP!\n", |
841 | 0 | fd)); |
842 | 0 | break; |
843 | 0 | case SMUX_SOUT: |
844 | 0 | error = -1; |
845 | 0 | smux_send_close(fd, SMUXC_PROTOCOLERROR); |
846 | 0 | smux_peer_cleanup(fd); |
847 | 0 | DEBUGMSGTL(("smux", "This shouldn't have happened!\n")); |
848 | 0 | break; |
849 | 0 | case SMUX_TRAP: |
850 | 0 | DEBUGMSGTL(("smux", "Got trap from peer on fd %d\n", fd)); |
851 | 0 | if (ptr) |
852 | 0 | { |
853 | 0 | DEBUGMSGTL(("smux", "[smux_pdu_process] call smux_trap_process.\n")); |
854 | 0 | ptr = smux_trap_process(ptr, &len); |
855 | 0 | } |
856 | 0 | else |
857 | 0 | { |
858 | 0 | DEBUGMSGTL(("smux", "[smux_pdu_process] smux_trap_process not called: ptr=NULL.\n")); |
859 | 0 | DEBUGMSGTL(("smux", "[smux_pdu_process] Error: \n%s\n", snmp_api_errstring(0))); |
860 | 0 | } |
861 | | /* |
862 | | * watch out for close on top of this...should return correct end |
863 | | */ |
864 | 0 | break; |
865 | 0 | default: |
866 | 0 | smux_send_close(fd, SMUXC_PACKETFORMAT); |
867 | 0 | smux_peer_cleanup(fd); |
868 | 0 | DEBUGMSGTL(("smux", "[smux_pdu_process] Wrong type %d\n", |
869 | 0 | (int) type)); |
870 | 0 | error = -1; |
871 | 0 | break; |
872 | 0 | } |
873 | 0 | } |
874 | 0 | return error; |
875 | 0 | } |
876 | | |
877 | | static u_char * |
878 | | smux_open_process(int fd, u_char * ptr, size_t * len, int *fail) |
879 | 0 | { |
880 | 0 | u_char type; |
881 | 0 | long version; |
882 | 0 | oid oid_name[MAX_OID_LEN]; |
883 | 0 | char passwd[SMUXMAXSTRLEN]; |
884 | 0 | char descr[SMUXMAXSTRLEN]; |
885 | 0 | char oid_print[SMUXMAXSTRLEN]; |
886 | 0 | int i; |
887 | 0 | size_t oid_name_len, string_len; |
888 | |
|
889 | 0 | if (!(ptr = asn_parse_int(ptr, len, &type, &version, sizeof(version)))) { |
890 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] version parse failed\n")); |
891 | 0 | *fail = TRUE; |
892 | 0 | return ((ptr += *len)); |
893 | 0 | } |
894 | 0 | DEBUGMSGTL(("smux", |
895 | 0 | "[smux_open_process] version %ld, len %" NETSNMP_PRIz |
896 | 0 | "u, type %d\n", version, *len, (int) type)); |
897 | |
|
898 | 0 | oid_name_len = MAX_OID_LEN; |
899 | 0 | if ((ptr = asn_parse_objid(ptr, len, &type, oid_name, |
900 | 0 | &oid_name_len)) == NULL) { |
901 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] oid parse failed\n")); |
902 | 0 | *fail = TRUE; |
903 | 0 | return ((ptr += *len)); |
904 | 0 | } |
905 | 0 | snprint_objid(oid_print, sizeof(oid_print), oid_name, oid_name_len); |
906 | |
|
907 | 0 | if (snmp_get_do_debugging()) { |
908 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] smux peer: %s\n", |
909 | 0 | oid_print)); |
910 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] len %" NETSNMP_PRIz |
911 | 0 | "u, type %d\n", *len, (int) type)); |
912 | 0 | } |
913 | |
|
914 | 0 | string_len = SMUXMAXSTRLEN; |
915 | 0 | if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) descr, |
916 | 0 | &string_len)) == NULL) { |
917 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] descr parse failed\n")); |
918 | 0 | *fail = TRUE; |
919 | 0 | return ((ptr += *len)); |
920 | 0 | } |
921 | | |
922 | 0 | if (snmp_get_do_debugging()) { |
923 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] smux peer descr: ")); |
924 | 0 | for (i = 0; i < (int) string_len; i++) |
925 | 0 | DEBUGMSG(("smux", "%c", descr[i])); |
926 | 0 | DEBUGMSG(("smux", "\n")); |
927 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] len %" NETSNMP_PRIz |
928 | 0 | "u, type %d\n", *len, (int) type)); |
929 | 0 | } |
930 | 0 | descr[string_len] = 0; |
931 | |
|
932 | 0 | string_len = SMUXMAXSTRLEN; |
933 | 0 | if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) passwd, |
934 | 0 | &string_len)) == NULL) { |
935 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] passwd parse failed\n")); |
936 | 0 | *fail = TRUE; |
937 | 0 | return ((ptr += *len)); |
938 | 0 | } |
939 | | |
940 | 0 | if (snmp_get_do_debugging()) { |
941 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] smux peer passwd: ")); |
942 | 0 | for (i = 0; i < (int) string_len; i++) |
943 | 0 | DEBUGMSG(("smux", "%c", passwd[i])); |
944 | 0 | DEBUGMSG(("smux", "\n")); |
945 | 0 | DEBUGMSGTL(("smux", "[smux_open_process] len %" NETSNMP_PRIz |
946 | 0 | "u, type %d\n", *len, (int) type)); |
947 | 0 | } |
948 | 0 | passwd[string_len] = '\0'; |
949 | 0 | if (!smux_auth_peer(oid_name, oid_name_len, passwd, fd)) { |
950 | 0 | snmp_log(LOG_WARNING, |
951 | 0 | "refused smux peer: oid %s, descr %s\n", |
952 | 0 | oid_print, descr); |
953 | 0 | *fail = TRUE; |
954 | 0 | return ptr; |
955 | 0 | } |
956 | 0 | DEBUGMSGTL(("smux", |
957 | 0 | "accepted smux peer: oid %s, descr %s\n", |
958 | 0 | oid_print, descr)); |
959 | 0 | *fail = FALSE; |
960 | 0 | return ptr; |
961 | 0 | } |
962 | | |
963 | | static void |
964 | | smux_send_close(int fd, int reason) |
965 | 0 | { |
966 | 0 | u_char outpacket[3], *ptr; |
967 | |
|
968 | 0 | ptr = outpacket; |
969 | |
|
970 | 0 | *(ptr++) = (u_char) SMUX_CLOSE; |
971 | 0 | *(ptr++) = (u_char) 1; |
972 | 0 | *ptr = (u_char) (reason & 0xFF); |
973 | |
|
974 | 0 | if (snmp_get_do_debugging()) |
975 | 0 | DEBUGMSGTL(("smux", |
976 | 0 | "[smux_close] sending close to fd %d, reason %d\n", fd, |
977 | 0 | reason)); |
978 | | |
979 | | /* |
980 | | * send a response back |
981 | | */ |
982 | 0 | if (sendto(fd, (char *) outpacket, 3, 0, NULL, 0) < 0) { |
983 | 0 | snmp_log_perror("[smux_snmp_close] send failed"); |
984 | 0 | } |
985 | 0 | } |
986 | | |
987 | | |
988 | | static int |
989 | | smux_auth_peer(oid * name, size_t namelen, char *passwd, int fd) |
990 | 0 | { |
991 | 0 | int i; |
992 | 0 | char oid_print[SMUXMAXSTRLEN]; |
993 | |
|
994 | 0 | if (snmp_get_do_debugging()) { |
995 | 0 | snprint_objid(oid_print, sizeof(oid_print), name, namelen); |
996 | 0 | DEBUGMSGTL(("smux:auth", "[smux_auth_peer] Authorizing: %s, %s\n", |
997 | 0 | oid_print, passwd)); |
998 | 0 | } |
999 | |
|
1000 | 0 | for (i = 0; i < nauths; i++) { |
1001 | 0 | if (snmp_get_do_debugging()) { |
1002 | 0 | snprint_objid(oid_print, sizeof(oid_print), |
1003 | 0 | Auths[i]->sa_oid, Auths[i]->sa_oid_len); |
1004 | 0 | DEBUGMSGTL(("smux:auth", "[smux_auth_peer] Checking OID: %s (%d)\n", |
1005 | 0 | oid_print, i)); |
1006 | 0 | } |
1007 | 0 | if (snmp_oid_compare(Auths[i]->sa_oid, Auths[i]->sa_oid_len, |
1008 | 0 | name, namelen) == 0) { |
1009 | 0 | if (snmp_get_do_debugging()) { |
1010 | 0 | DEBUGMSGTL(("smux:auth", "[smux_auth_peer] Checking P/W: %s (%d)\n", |
1011 | 0 | Auths[i]->sa_passwd, Auths[i]->sa_active_fd)); |
1012 | 0 | } |
1013 | 0 | if (!(strcmp(Auths[i]->sa_passwd, passwd)) && |
1014 | 0 | (Auths[i]->sa_active_fd == -1)) { |
1015 | | /* |
1016 | | * matched, mark the auth |
1017 | | */ |
1018 | 0 | Auths[i]->sa_active_fd = fd; |
1019 | 0 | return 1; |
1020 | 0 | } |
1021 | 0 | } |
1022 | 0 | } |
1023 | | /* |
1024 | | * did not match oid and passwd |
1025 | | */ |
1026 | 0 | return 0; |
1027 | 0 | } |
1028 | | |
1029 | | |
1030 | | /* |
1031 | | * XXX - Bells and Whistles: |
1032 | | * Need to catch signal when snmpd goes down and send close pdu to gated |
1033 | | */ |
1034 | | static u_char * |
1035 | | smux_close_process(int fd, u_char * ptr, size_t * len) |
1036 | 0 | { |
1037 | 0 | long down = 0; |
1038 | 0 | int length = *len; |
1039 | | |
1040 | | /* |
1041 | | * This is the integer part of the close pdu |
1042 | | */ |
1043 | 0 | while (length--) { |
1044 | 0 | down = (down << 8) | (long) *ptr; |
1045 | 0 | ptr++; |
1046 | 0 | } |
1047 | |
|
1048 | 0 | DEBUGMSGTL(("smux", |
1049 | 0 | "[smux_close_process] close from peer on fd %d reason %ld\n", |
1050 | 0 | fd, down)); |
1051 | 0 | smux_peer_cleanup(fd); |
1052 | |
|
1053 | 0 | return NULL; |
1054 | 0 | } |
1055 | | |
1056 | | static u_char * |
1057 | | smux_rreq_process(int sd, u_char * ptr, size_t * len) |
1058 | 0 | { |
1059 | 0 | long priority, rpriority; |
1060 | 0 | long operation; |
1061 | 0 | oid oid_name[MAX_OID_LEN]; |
1062 | 0 | size_t oid_name_len; |
1063 | 0 | int i, result; |
1064 | 0 | u_char type; |
1065 | 0 | smux_reg *rptr, *nrptr; |
1066 | 0 | netsnmp_handler_registration *reg; |
1067 | |
|
1068 | 0 | oid_name_len = MAX_OID_LEN; |
1069 | 0 | ptr = asn_parse_objid(ptr, len, &type, oid_name, &oid_name_len); |
1070 | |
|
1071 | 0 | DEBUGMSGTL(("smux", "[smux_rreq_process] smux subtree: ")); |
1072 | 0 | DEBUGMSGOID(("smux", oid_name, oid_name_len)); |
1073 | 0 | DEBUGMSG(("smux", "\n")); |
1074 | |
|
1075 | 0 | if ((ptr = asn_parse_int(ptr, len, &type, &priority, |
1076 | 0 | sizeof(priority))) == NULL) { |
1077 | 0 | DEBUGMSGTL(("smux", |
1078 | 0 | "[smux_rreq_process] priority parse failed\n")); |
1079 | 0 | smux_send_rrsp(sd, -1); |
1080 | 0 | return NULL; |
1081 | 0 | } |
1082 | 0 | DEBUGMSGTL(("smux", "[smux_rreq_process] priority %ld\n", priority)); |
1083 | |
|
1084 | 0 | if ((ptr = asn_parse_int(ptr, len, &type, &operation, |
1085 | 0 | sizeof(operation))) == NULL) { |
1086 | 0 | DEBUGMSGTL(("smux", |
1087 | 0 | "[smux_rreq_process] operation parse failed\n")); |
1088 | 0 | smux_send_rrsp(sd, -1); |
1089 | 0 | return NULL; |
1090 | 0 | } |
1091 | 0 | DEBUGMSGTL(("smux", "[smux_rreq_process] operation %ld\n", operation)); |
1092 | |
|
1093 | 0 | if (operation == SMUX_REGOP_DELETE) { |
1094 | | /* |
1095 | | * search the active list for this registration |
1096 | | */ |
1097 | 0 | rptr = |
1098 | 0 | smux_find_match(ActiveRegs, sd, oid_name, oid_name_len, |
1099 | 0 | priority); |
1100 | 0 | if (rptr) { |
1101 | 0 | rpriority = rptr->sr_priority; |
1102 | | /* |
1103 | | * unregister the mib |
1104 | | */ |
1105 | 0 | unregister_mib(rptr->sr_name, rptr->sr_name_len); |
1106 | | /* |
1107 | | * find a replacement |
1108 | | */ |
1109 | 0 | nrptr = |
1110 | 0 | smux_find_replacement(rptr->sr_name, rptr->sr_name_len); |
1111 | 0 | if (nrptr) { |
1112 | | /* |
1113 | | * found one |
1114 | | */ |
1115 | 0 | smux_replace_active(rptr, nrptr); |
1116 | 0 | } else { |
1117 | | /* |
1118 | | * no replacement found |
1119 | | */ |
1120 | 0 | smux_list_detach(&ActiveRegs, rptr); |
1121 | 0 | free(rptr); |
1122 | 0 | } |
1123 | 0 | smux_send_rrsp(sd, rpriority); |
1124 | 0 | return ptr; |
1125 | 0 | } |
1126 | | /* |
1127 | | * search the passive list for this registration |
1128 | | */ |
1129 | 0 | rptr = |
1130 | 0 | smux_find_match(PassiveRegs, sd, oid_name, oid_name_len, |
1131 | 0 | priority); |
1132 | 0 | if (rptr) { |
1133 | 0 | rpriority = rptr->sr_priority; |
1134 | 0 | smux_list_detach(&PassiveRegs, rptr); |
1135 | 0 | free(rptr); |
1136 | 0 | smux_send_rrsp(sd, rpriority); |
1137 | 0 | return ptr; |
1138 | 0 | } |
1139 | | /* |
1140 | | * This peer cannot unregister the tree, it does not |
1141 | | * * belong to him. Send him an error. |
1142 | | */ |
1143 | 0 | smux_send_rrsp(sd, -1); |
1144 | 0 | return ptr; |
1145 | |
|
1146 | 0 | } else if ((operation == SMUX_REGOP_REGISTER_RO) || |
1147 | 0 | (operation == SMUX_REGOP_REGISTER_RW)) { |
1148 | 0 | if (priority < -1) { |
1149 | 0 | DEBUGMSGTL(("smux", |
1150 | 0 | "[smux_rreq_process] peer fd %d invalid priority %ld", |
1151 | 0 | sd, priority)); |
1152 | 0 | smux_send_rrsp(sd, -1); |
1153 | 0 | return NULL; |
1154 | 0 | } |
1155 | 0 | if ((nrptr = malloc(sizeof(smux_reg))) == NULL) { |
1156 | 0 | snmp_log_perror("[smux_rreq_process] malloc"); |
1157 | 0 | smux_send_rrsp(sd, -1); |
1158 | 0 | return NULL; |
1159 | 0 | } |
1160 | 0 | nrptr->sr_priority = priority; |
1161 | 0 | nrptr->sr_name_len = oid_name_len; |
1162 | 0 | nrptr->sr_fd = sd; |
1163 | 0 | for (i = 0; i < (int) oid_name_len; i++) |
1164 | 0 | nrptr->sr_name[i] = oid_name[i]; |
1165 | | |
1166 | | /* |
1167 | | * See if this tree matches or scopes any of the |
1168 | | * * active trees. |
1169 | | */ |
1170 | 0 | for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) { |
1171 | 0 | result = |
1172 | 0 | snmp_oid_compare(oid_name, oid_name_len, rptr->sr_name, |
1173 | 0 | rptr->sr_name_len); |
1174 | 0 | if (result == 0) { |
1175 | 0 | if (oid_name_len == rptr->sr_name_len) { |
1176 | 0 | if (nrptr->sr_priority == -1) { |
1177 | 0 | nrptr->sr_priority = rptr->sr_priority; |
1178 | 0 | do { |
1179 | 0 | nrptr->sr_priority++; |
1180 | 0 | } while (smux_list_add(&PassiveRegs, nrptr)); |
1181 | 0 | goto done; |
1182 | 0 | } else if (nrptr->sr_priority < rptr->sr_priority) { |
1183 | | /* |
1184 | | * Better priority. There are no better |
1185 | | * * priorities for this tree in the passive list, |
1186 | | * * so replace the current active tree. |
1187 | | */ |
1188 | 0 | smux_replace_active(rptr, nrptr); |
1189 | 0 | goto done; |
1190 | 0 | } else { |
1191 | | /* |
1192 | | * Equal or worse priority |
1193 | | */ |
1194 | 0 | do { |
1195 | 0 | nrptr->sr_priority++; |
1196 | 0 | } while (smux_list_add(&PassiveRegs, nrptr) == -1); |
1197 | 0 | goto done; |
1198 | 0 | } |
1199 | 0 | } else if (oid_name_len < rptr->sr_name_len) { |
1200 | | /* |
1201 | | * This tree scopes a current active |
1202 | | * * tree. Replace the current active tree. |
1203 | | */ |
1204 | 0 | smux_replace_active(rptr, nrptr); |
1205 | 0 | goto done; |
1206 | 0 | } else { /* oid_name_len > rptr->sr_name_len */ |
1207 | | /* |
1208 | | * This tree is scoped by a current |
1209 | | * * active tree. |
1210 | | */ |
1211 | 0 | do { |
1212 | 0 | nrptr->sr_priority++; |
1213 | 0 | } while (smux_list_add(&PassiveRegs, nrptr) == -1); |
1214 | 0 | goto done; |
1215 | 0 | } |
1216 | 0 | } |
1217 | 0 | } |
1218 | | /* |
1219 | | * We didn't find it in the active list. Add it at |
1220 | | * * the requested priority. |
1221 | | */ |
1222 | 0 | if (nrptr->sr_priority == -1) |
1223 | 0 | nrptr->sr_priority = 0; |
1224 | |
|
1225 | 0 | reg = netsnmp_create_handler_registration("smux", |
1226 | 0 | smux_handler, |
1227 | 0 | nrptr->sr_name, |
1228 | 0 | nrptr->sr_name_len, |
1229 | 0 | HANDLER_CAN_RWRITE); |
1230 | 0 | if (reg == NULL) { |
1231 | 0 | snmp_log(LOG_ERR, "SMUX: cannot create new smux peer " |
1232 | 0 | "registration\n"); |
1233 | 0 | smux_send_rrsp(sd, -1); |
1234 | 0 | free(nrptr); |
1235 | 0 | return NULL; |
1236 | 0 | } |
1237 | 0 | if (netsnmp_register_handler(reg) != MIB_REGISTERED_OK) { |
1238 | 0 | snmp_log(LOG_ERR, "SMUX: cannot register new smux peer\n"); |
1239 | 0 | smux_send_rrsp(sd, -1); |
1240 | 0 | free(nrptr); |
1241 | 0 | return NULL; |
1242 | 0 | } |
1243 | 0 | nrptr->reginfo = reg; |
1244 | 0 | smux_list_add(&ActiveRegs, nrptr); |
1245 | |
|
1246 | 0 | done: |
1247 | 0 | smux_send_rrsp(sd, nrptr->sr_priority); |
1248 | 0 | return ptr; |
1249 | 0 | } else { |
1250 | 0 | DEBUGMSGTL(("smux", "[smux_rreq_process] unknown operation\n")); |
1251 | 0 | smux_send_rrsp(sd, -1); |
1252 | 0 | return NULL; |
1253 | 0 | } |
1254 | 0 | } |
1255 | | |
1256 | | /* |
1257 | | * Find the registration with a matching descriptor, OID and priority. If |
1258 | | * the priority is -1 then find a registration with a matching descriptor, |
1259 | | * a matching OID, and the highest priority. |
1260 | | */ |
1261 | | static smux_reg * |
1262 | | smux_find_match(smux_reg * regs, int sd, oid * oid_name, |
1263 | | size_t oid_name_len, long priority) |
1264 | 0 | { |
1265 | 0 | smux_reg *rptr, *bestrptr; |
1266 | |
|
1267 | 0 | bestrptr = NULL; |
1268 | 0 | for (rptr = regs; rptr; rptr = rptr->sr_next) { |
1269 | 0 | if (rptr->sr_fd != sd) |
1270 | 0 | continue; |
1271 | 0 | if (snmp_oid_compare |
1272 | 0 | (rptr->sr_name, rptr->sr_name_len, oid_name, oid_name_len)) |
1273 | 0 | continue; |
1274 | 0 | if (rptr->sr_priority == priority) |
1275 | 0 | return rptr; |
1276 | 0 | if (priority != -1) |
1277 | 0 | continue; |
1278 | 0 | if (bestrptr) { |
1279 | 0 | if (bestrptr->sr_priority > rptr->sr_priority) |
1280 | 0 | bestrptr = rptr; |
1281 | 0 | } else { |
1282 | 0 | bestrptr = rptr; |
1283 | 0 | } |
1284 | 0 | } |
1285 | 0 | return bestrptr; |
1286 | 0 | } |
1287 | | |
1288 | | static void |
1289 | | smux_replace_active(smux_reg * actptr, smux_reg * pasptr) |
1290 | 0 | { |
1291 | 0 | netsnmp_handler_registration *reg; |
1292 | |
|
1293 | 0 | smux_list_detach(&ActiveRegs, actptr); |
1294 | 0 | if (actptr->reginfo) { |
1295 | 0 | netsnmp_unregister_handler(actptr->reginfo); |
1296 | 0 | actptr->reginfo = NULL; |
1297 | 0 | } |
1298 | |
|
1299 | 0 | smux_list_detach(&PassiveRegs, pasptr); |
1300 | |
|
1301 | 0 | (void) smux_list_add(&ActiveRegs, pasptr); |
1302 | 0 | free(actptr); |
1303 | |
|
1304 | 0 | reg = netsnmp_create_handler_registration("smux", |
1305 | 0 | smux_handler, |
1306 | 0 | pasptr->sr_name, |
1307 | 0 | pasptr->sr_name_len, |
1308 | 0 | HANDLER_CAN_RWRITE); |
1309 | 0 | if (reg == NULL) { |
1310 | 0 | snmp_log(LOG_ERR, "SMUX: cannot create new smux peer registration\n"); |
1311 | 0 | pasptr->reginfo = NULL; |
1312 | 0 | return; |
1313 | 0 | } |
1314 | 0 | if (netsnmp_register_handler(reg) != MIB_REGISTERED_OK) { |
1315 | 0 | snmp_log(LOG_ERR, "SMUX: cannot register new smux peer\n"); |
1316 | 0 | pasptr->reginfo = NULL; |
1317 | 0 | return; |
1318 | 0 | } |
1319 | 0 | pasptr->reginfo = reg; |
1320 | 0 | } |
1321 | | |
1322 | | static void |
1323 | | smux_list_detach(smux_reg ** head, smux_reg * m_remove) |
1324 | 0 | { |
1325 | 0 | smux_reg *rptr, *rptr2; |
1326 | |
|
1327 | 0 | if (*head == NULL) { |
1328 | 0 | DEBUGMSGTL(("smux", "[smux_list_detach] Ouch!")); |
1329 | 0 | return; |
1330 | 0 | } |
1331 | 0 | if (*head == m_remove) { |
1332 | 0 | *head = (*head)->sr_next; |
1333 | 0 | return; |
1334 | 0 | } |
1335 | 0 | for (rptr = *head, rptr2 = rptr->sr_next; rptr2; |
1336 | 0 | rptr2 = rptr2->sr_next, rptr = rptr->sr_next) { |
1337 | 0 | if (rptr2 == m_remove) { |
1338 | 0 | rptr->sr_next = rptr2->sr_next; |
1339 | 0 | return; |
1340 | 0 | } |
1341 | 0 | } |
1342 | 0 | } |
1343 | | |
1344 | | /* |
1345 | | * Attempt to add a registration (in order) to a list. If the |
1346 | | * add fails (because of an existing registration with equal |
1347 | | * priority) return -1. |
1348 | | */ |
1349 | | static int |
1350 | | smux_list_add(smux_reg ** head, smux_reg * add) |
1351 | 0 | { |
1352 | 0 | smux_reg *rptr, *prev; |
1353 | 0 | int result; |
1354 | |
|
1355 | 0 | if (*head == NULL) { |
1356 | 0 | *head = add; |
1357 | 0 | (*head)->sr_next = NULL; |
1358 | 0 | return 0; |
1359 | 0 | } |
1360 | 0 | prev = NULL; |
1361 | 0 | for (rptr = *head; rptr; rptr = rptr->sr_next) { |
1362 | 0 | result = snmp_oid_compare(add->sr_name, add->sr_name_len, |
1363 | 0 | rptr->sr_name, rptr->sr_name_len); |
1364 | 0 | if (result == 0) { |
1365 | | /* |
1366 | | * Same tree... |
1367 | | */ |
1368 | 0 | if (add->sr_priority == rptr->sr_priority) { |
1369 | | /* |
1370 | | * ... same pri : nope |
1371 | | */ |
1372 | 0 | return -1; |
1373 | 0 | } else if (add->sr_priority < rptr->sr_priority) { |
1374 | | /* |
1375 | | * ... lower pri : insert and return |
1376 | | */ |
1377 | 0 | add->sr_next = rptr; |
1378 | 0 | if ( prev ) { prev->sr_next = add; } |
1379 | 0 | else { *head = add; } |
1380 | 0 | return 0; |
1381 | | #ifdef XXX |
1382 | | } else { |
1383 | | /* |
1384 | | * ... higher pri : put after |
1385 | | */ |
1386 | | add->sr_next = rptr->sr_next; |
1387 | | rptr->sr_next = add; |
1388 | | #endif |
1389 | 0 | } |
1390 | 0 | } else if (result < 0) { |
1391 | | /* |
1392 | | * Earlier tree : insert and return |
1393 | | */ |
1394 | 0 | add->sr_next = rptr; |
1395 | 0 | if ( prev ) { prev->sr_next = add; } |
1396 | 0 | else { *head = add; } |
1397 | 0 | return 0; |
1398 | | #ifdef XXX |
1399 | | } else { |
1400 | | /* |
1401 | | * Later tree : put after |
1402 | | */ |
1403 | | add->sr_next = rptr->sr_next; |
1404 | | rptr->sr_next = add; |
1405 | | return 0; |
1406 | | #endif |
1407 | 0 | } |
1408 | 0 | prev = rptr; |
1409 | 0 | } |
1410 | | /* |
1411 | | * Otherwise, this entry must come last |
1412 | | */ |
1413 | 0 | if ( prev ) { prev->sr_next = add; } |
1414 | 0 | else { *head = add; } |
1415 | 0 | add->sr_next = NULL; |
1416 | 0 | return 0; |
1417 | 0 | } |
1418 | | |
1419 | | /* |
1420 | | * Find a replacement for this registration. In order |
1421 | | * of preference: |
1422 | | * |
1423 | | * - Least difference in subtree length |
1424 | | * - Best (lowest) priority |
1425 | | * |
1426 | | * For example, if we need to replace .1.3.6.1.69, |
1427 | | * we would pick .1.3.6.1.69.1 instead of .1.3.6.69.1.1 |
1428 | | * |
1429 | | */ |
1430 | | static smux_reg * |
1431 | | smux_find_replacement(oid * name, size_t name_len) |
1432 | 0 | { |
1433 | 0 | smux_reg *rptr, *bestptr; |
1434 | 0 | int bestlen, difflen; |
1435 | |
|
1436 | 0 | bestlen = SMUX_MAX_PRIORITY; |
1437 | 0 | bestptr = NULL; |
1438 | |
|
1439 | 0 | for (rptr = PassiveRegs; rptr; rptr = rptr->sr_next) { |
1440 | 0 | if (!snmp_oidtree_compare(rptr->sr_name, rptr->sr_name_len, |
1441 | 0 | name, name_len)) { |
1442 | 0 | if ((difflen = rptr->sr_name_len - name_len) |
1443 | 0 | < bestlen || !bestptr) { |
1444 | 0 | bestlen = difflen; |
1445 | 0 | bestptr = rptr; |
1446 | 0 | } else if ((difflen == bestlen) && |
1447 | 0 | (rptr->sr_priority < bestptr->sr_priority)) |
1448 | 0 | bestptr = rptr; |
1449 | 0 | } |
1450 | 0 | } |
1451 | 0 | return bestptr; |
1452 | 0 | } |
1453 | | |
1454 | | u_char * |
1455 | | smux_snmp_process(int exact, |
1456 | | oid * objid, |
1457 | | size_t * len, |
1458 | | size_t * return_len, u_char * return_type, int sd) |
1459 | 0 | { |
1460 | 0 | u_char packet[SMUXMAXPKTSIZE], *ptr, result[SMUXMAXPKTSIZE]; |
1461 | 0 | ssize_t length = SMUXMAXPKTSIZE; |
1462 | 0 | int tmp_length; |
1463 | 0 | u_char type; |
1464 | 0 | size_t packet_len; |
1465 | | |
1466 | | /* |
1467 | | * Send the query to the peer |
1468 | | */ |
1469 | 0 | if (exact) |
1470 | 0 | type = SMUX_GET; |
1471 | 0 | else |
1472 | 0 | type = SMUX_GETNEXT; |
1473 | |
|
1474 | 0 | if (smux_build(type, smux_reqid, objid, len, 0, NULL, |
1475 | 0 | *len, packet, (size_t *) &length) < 0) { |
1476 | 0 | snmp_log(LOG_ERR, "[smux_snmp_process]: smux_build failed\n"); |
1477 | 0 | return NULL; |
1478 | 0 | } |
1479 | 0 | DEBUGMSGTL(("smux", "[smux_snmp_process] oid from build: ")); |
1480 | 0 | DEBUGMSGOID(("smux", objid, *len)); |
1481 | 0 | DEBUGMSG(("smux", "\n")); |
1482 | |
|
1483 | 0 | if (sendto(sd, (char *) packet, length, 0, NULL, 0) < 0) { |
1484 | 0 | snmp_log_perror("[smux_snmp_process] send failed"); |
1485 | 0 | } |
1486 | |
|
1487 | 0 | DEBUGMSGTL(("smux", |
1488 | 0 | "[smux_snmp_process] Sent %d request to peer; %" NETSNMP_PRIz "d bytes\n", |
1489 | 0 | (int) type, length)); |
1490 | |
|
1491 | 0 | while (1) { |
1492 | | /* |
1493 | | * peek at what's received |
1494 | | */ |
1495 | 0 | length = recvfrom(sd, (char *) result, SMUXMAXPKTSIZE, MSG_PEEK, NULL, |
1496 | 0 | NULL); |
1497 | 0 | if (length <= 0) { |
1498 | 0 | if ((length == -1) && ((errno == EINTR) || (errno == EAGAIN))) |
1499 | 0 | { |
1500 | 0 | continue; |
1501 | 0 | } |
1502 | 0 | else |
1503 | 0 | { |
1504 | 0 | snmp_log_perror("[smux_snmp_process] peek failed"); |
1505 | 0 | smux_peer_cleanup(sd); |
1506 | 0 | smux_snmp_select_list_del(sd); |
1507 | 0 | return NULL; |
1508 | 0 | } |
1509 | 0 | } |
1510 | | |
1511 | 0 | DEBUGMSGTL(("smux", "[smux_snmp_process] Peeked at %" NETSNMP_PRIz "d bytes\n", |
1512 | 0 | length)); |
1513 | 0 | DEBUGDUMPSETUP("smux_snmp_process", result, length); |
1514 | | |
1515 | | /* |
1516 | | * determine if we received more than one packet |
1517 | | */ |
1518 | 0 | packet_len = length; |
1519 | 0 | ptr = asn_parse_header(result, &packet_len, &type); |
1520 | 0 | if (ptr == NULL) |
1521 | 0 | return NULL; |
1522 | 0 | packet_len += (ptr - result); |
1523 | 0 | if (length > packet_len) { |
1524 | | /* |
1525 | | * set length to receive only the first packet |
1526 | | */ |
1527 | 0 | length = packet_len; |
1528 | 0 | } |
1529 | | |
1530 | | /* |
1531 | | * receive the first packet |
1532 | | */ |
1533 | 0 | tmp_length = length; |
1534 | 0 | do |
1535 | 0 | { |
1536 | 0 | length = tmp_length; |
1537 | 0 | length = recvfrom(sd, (char *) result, length, 0, NULL, NULL); |
1538 | 0 | } |
1539 | 0 | while((length == -1) && ((errno == EINTR) || (errno == EAGAIN))); |
1540 | |
|
1541 | 0 | if (length <= 0) { |
1542 | 0 | snmp_log_perror("[smux_snmp_process] recv failed"); |
1543 | 0 | smux_peer_cleanup(sd); |
1544 | 0 | smux_snmp_select_list_del(sd); |
1545 | 0 | return NULL; |
1546 | 0 | } |
1547 | | |
1548 | 0 | DEBUGMSGTL(("smux", "[smux_snmp_process] Received %" NETSNMP_PRIz "d bytes\n", |
1549 | 0 | length)); |
1550 | |
|
1551 | 0 | if (result[0] == SMUX_TRAP) { |
1552 | 0 | DEBUGMSGTL(("smux", "[smux_snmp_process] Received trap\n")); |
1553 | 0 | DEBUGMSGTL(("smux", "Got trap from peer on fd %d\n", sd)); |
1554 | 0 | ptr = asn_parse_header(result, (size_t *) &length, &type); |
1555 | 0 | if (ptr == NULL) |
1556 | 0 | return NULL; |
1557 | 0 | smux_trap_process(ptr, (size_t *) &length); |
1558 | | |
1559 | | /* |
1560 | | * go and peek at received data again |
1561 | | */ |
1562 | | /* |
1563 | | * we could receive the reply or another trap |
1564 | | */ |
1565 | 0 | } else { |
1566 | | /* |
1567 | | * Interpret reply |
1568 | | */ |
1569 | 0 | ptr = smux_parse(result, objid, len, return_len, return_type); |
1570 | | /* |
1571 | | * ptr will point to query result or NULL if error |
1572 | | */ |
1573 | 0 | break; |
1574 | 0 | } |
1575 | 0 | } /* while (1) */ |
1576 | | |
1577 | 0 | return ptr; |
1578 | 0 | } |
1579 | | |
1580 | | static u_char * |
1581 | | smux_parse(u_char * rsp, |
1582 | | oid * objid, |
1583 | | size_t * oidlen, size_t * return_len, u_char * return_type) |
1584 | 0 | { |
1585 | 0 | size_t length = SMUXMAXPKTSIZE; |
1586 | 0 | u_char *ptr, type; |
1587 | 0 | long reqid, errstat, errindex; |
1588 | |
|
1589 | 0 | ptr = rsp; |
1590 | | |
1591 | | /* |
1592 | | * Return pointer to the snmp/smux return value. |
1593 | | * return_len should contain the number of bytes in the value |
1594 | | * returned above. |
1595 | | * objid is the next object, with len for GETNEXT. |
1596 | | * objid and len are not changed for GET |
1597 | | */ |
1598 | 0 | ptr = asn_parse_header(ptr, &length, &type); |
1599 | 0 | if (ptr == NULL || type != SNMP_MSG_RESPONSE) |
1600 | 0 | return NULL; |
1601 | | |
1602 | 0 | if ((ptr = asn_parse_int(ptr, &length, &type, &reqid, |
1603 | 0 | sizeof(reqid))) == NULL) { |
1604 | 0 | DEBUGMSGTL(("smux", "[smux_parse] parse of reqid failed\n")); |
1605 | 0 | return NULL; |
1606 | 0 | } |
1607 | 0 | if ((ptr = asn_parse_int(ptr, &length, &type, &errstat, |
1608 | 0 | sizeof(errstat))) == NULL) { |
1609 | 0 | DEBUGMSGTL(("smux", |
1610 | 0 | "[smux_parse] parse of error status failed\n")); |
1611 | 0 | return NULL; |
1612 | 0 | } |
1613 | 0 | if ((ptr = asn_parse_int(ptr, &length, &type, &errindex, |
1614 | 0 | sizeof(errindex))) == NULL) { |
1615 | 0 | DEBUGMSGTL(("smux", "[smux_parse] parse of error index failed\n")); |
1616 | 0 | return NULL; |
1617 | 0 | } |
1618 | | |
1619 | | /* |
1620 | | * XXX How to send something intelligent back in case of an error |
1621 | | */ |
1622 | 0 | DEBUGMSGTL(("smux", |
1623 | 0 | "[smux_parse] Message type %d, reqid %ld, errstat %ld, \n\terrindex %ld\n", |
1624 | 0 | (int) type, reqid, errstat, errindex)); |
1625 | 0 | if (ptr == NULL || errstat != SNMP_ERR_NOERROR) |
1626 | 0 | return NULL; |
1627 | | |
1628 | | /* |
1629 | | * stuff to return |
1630 | | */ |
1631 | 0 | return (smux_parse_var |
1632 | 0 | (ptr, &length, objid, oidlen, return_len, return_type)); |
1633 | 0 | } |
1634 | | |
1635 | | |
1636 | | static u_char * |
1637 | | smux_parse_var(u_char * varbind, |
1638 | | size_t * varbindlength, |
1639 | | oid * objid, |
1640 | | size_t * oidlen, size_t * varlength, u_char * vartype) |
1641 | 0 | { |
1642 | 0 | oid var_name[MAX_OID_LEN]; |
1643 | 0 | size_t var_name_len; |
1644 | 0 | size_t var_val_len; |
1645 | 0 | u_char *var_val; |
1646 | 0 | size_t str_len, objid_len; |
1647 | 0 | size_t len; |
1648 | 0 | u_char *ptr; |
1649 | 0 | u_char type; |
1650 | |
|
1651 | 0 | ptr = varbind; |
1652 | 0 | len = *varbindlength; |
1653 | |
|
1654 | 0 | DEBUGMSGTL(("smux", "[smux_parse_var] before any processing: ")); |
1655 | 0 | DEBUGMSGOID(("smux", objid, *oidlen)); |
1656 | 0 | DEBUGMSG(("smux", "\n")); |
1657 | |
|
1658 | 0 | ptr = asn_parse_header(ptr, &len, &type); |
1659 | 0 | if (ptr == NULL || type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) { |
1660 | 0 | snmp_log(LOG_NOTICE, "[smux_parse_var] Panic: type %d\n", |
1661 | 0 | (int) type); |
1662 | 0 | return NULL; |
1663 | 0 | } |
1664 | | |
1665 | | /* |
1666 | | * get hold of the objid and the asn1 coded value |
1667 | | */ |
1668 | 0 | var_name_len = MAX_OID_LEN; |
1669 | 0 | ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, vartype, |
1670 | 0 | &var_val_len, &var_val, &len); |
1671 | |
|
1672 | 0 | *oidlen = var_name_len; |
1673 | 0 | memcpy(objid, var_name, var_name_len * sizeof(oid)); |
1674 | |
|
1675 | 0 | DEBUGMSGTL(("smux", "[smux_parse_var] returning oid : ")); |
1676 | 0 | DEBUGMSGOID(("smux", objid, *oidlen)); |
1677 | 0 | DEBUGMSG(("smux", "\n")); |
1678 | | /* |
1679 | | * XXX |
1680 | | */ |
1681 | 0 | len = SMUXMAXPKTSIZE; |
1682 | 0 | DEBUGMSGTL(("smux", |
1683 | 0 | "[smux_parse_var] Asn coded len of var %" NETSNMP_PRIz |
1684 | 0 | "u, type %d\n", var_val_len, (int) *vartype)); |
1685 | |
|
1686 | 0 | switch ((short) *vartype) { |
1687 | 0 | case ASN_INTEGER: |
1688 | 0 | *varlength = sizeof(long); |
1689 | 0 | asn_parse_int(var_val, &len, vartype, |
1690 | 0 | (long *) &smux_long, *varlength); |
1691 | 0 | return (u_char *) & smux_long; |
1692 | 0 | break; |
1693 | 0 | case ASN_COUNTER: |
1694 | 0 | case ASN_GAUGE: |
1695 | 0 | case ASN_TIMETICKS: |
1696 | 0 | case ASN_UINTEGER: |
1697 | 0 | *varlength = sizeof(u_long); |
1698 | 0 | asn_parse_unsigned_int(var_val, &len, vartype, |
1699 | 0 | (u_long *) & smux_ulong, *varlength); |
1700 | 0 | return (u_char *) & smux_ulong; |
1701 | 0 | break; |
1702 | 0 | case ASN_COUNTER64: |
1703 | 0 | *varlength = sizeof(smux_counter64); |
1704 | 0 | asn_parse_unsigned_int64(var_val, &len, vartype, |
1705 | 0 | (struct counter64 *) &smux_counter64, |
1706 | 0 | *varlength); |
1707 | 0 | return (u_char *) & smux_counter64; |
1708 | 0 | break; |
1709 | 0 | case ASN_IPADDRESS: |
1710 | 0 | *varlength = 4; |
1711 | | /* |
1712 | | * consume the tag and length, but just copy here |
1713 | | * because we know it is an ip address |
1714 | | */ |
1715 | 0 | if ((var_val = asn_parse_header(var_val, &len, &type)) == NULL) |
1716 | 0 | return NULL; |
1717 | 0 | memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val, |
1718 | 0 | *varlength); |
1719 | 0 | return (u_char *) & (smux_sa.sin_addr.s_addr); |
1720 | 0 | break; |
1721 | 0 | case ASN_OCTET_STR: |
1722 | | /* |
1723 | | * XXX |
1724 | | */ |
1725 | 0 | if (len == 0) |
1726 | 0 | return NULL; |
1727 | 0 | str_len = SMUXMAXSTRLEN; |
1728 | 0 | asn_parse_string(var_val, &len, vartype, smux_str, &str_len); |
1729 | 0 | *varlength = str_len; |
1730 | 0 | return smux_str; |
1731 | 0 | break; |
1732 | 0 | case ASN_OPAQUE: |
1733 | 0 | case ASN_NSAP: |
1734 | 0 | case ASN_OBJECT_ID: |
1735 | 0 | objid_len = MAX_OID_LEN; |
1736 | 0 | asn_parse_objid(var_val, &len, vartype, smux_objid, &objid_len); |
1737 | 0 | *varlength = objid_len * sizeof(oid); |
1738 | 0 | return (u_char *) smux_objid; |
1739 | 0 | break; |
1740 | 0 | case SNMP_NOSUCHOBJECT: |
1741 | 0 | case SNMP_NOSUCHINSTANCE: |
1742 | 0 | case SNMP_ENDOFMIBVIEW: |
1743 | 0 | case ASN_NULL: |
1744 | 0 | return NULL; |
1745 | 0 | break; |
1746 | 0 | case ASN_BIT_STR: |
1747 | | /* |
1748 | | * XXX |
1749 | | */ |
1750 | 0 | if (len == 0) |
1751 | 0 | return NULL; |
1752 | 0 | str_len = SMUXMAXSTRLEN; |
1753 | 0 | asn_parse_bitstring(var_val, &len, vartype, smux_str, &str_len); |
1754 | 0 | *varlength = str_len; |
1755 | 0 | return (u_char *) smux_str; |
1756 | 0 | break; |
1757 | 0 | default: |
1758 | 0 | snmp_log(LOG_ERR, "bad type returned (%x)\n", *vartype); |
1759 | 0 | return NULL; |
1760 | 0 | break; |
1761 | 0 | } |
1762 | 0 | } |
1763 | | |
1764 | | /* |
1765 | | * XXX This is a bad hack - do not want to muck with ucd code |
1766 | | */ |
1767 | | static int |
1768 | | smux_build(u_char type, |
1769 | | long reqid, |
1770 | | oid * objid, |
1771 | | size_t * oidlen, |
1772 | | u_char val_type, |
1773 | | u_char * val, size_t val_len, u_char * packet, size_t * length) |
1774 | 0 | { |
1775 | 0 | u_char *ptr, *save1, *save2; |
1776 | 0 | size_t len; |
1777 | 0 | long errstat = 0; |
1778 | 0 | long errindex = 0; |
1779 | | |
1780 | | /* |
1781 | | * leave space for Seq and length |
1782 | | */ |
1783 | 0 | save1 = packet; |
1784 | 0 | ptr = packet + 4; |
1785 | 0 | len = *length - 4; |
1786 | | |
1787 | | /* |
1788 | | * build reqid |
1789 | | */ |
1790 | 0 | ptr = asn_build_int(ptr, &len, |
1791 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
1792 | 0 | ASN_INTEGER), &reqid, |
1793 | 0 | sizeof(reqid)); |
1794 | 0 | if (ptr == NULL) { |
1795 | 0 | return -1; |
1796 | 0 | } |
1797 | | |
1798 | | /* |
1799 | | * build err stat |
1800 | | */ |
1801 | 0 | ptr = asn_build_int(ptr, &len, |
1802 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
1803 | 0 | ASN_INTEGER), &errstat, sizeof(errstat)); |
1804 | 0 | if (ptr == NULL) { |
1805 | 0 | return -1; |
1806 | 0 | } |
1807 | | |
1808 | | /* |
1809 | | * build err index |
1810 | | */ |
1811 | 0 | ptr = asn_build_int(ptr, &len, |
1812 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
1813 | 0 | ASN_INTEGER), &errindex, |
1814 | 0 | sizeof(errindex)); |
1815 | 0 | if (ptr == NULL) { |
1816 | 0 | return -1; |
1817 | 0 | } |
1818 | | |
1819 | 0 | save2 = ptr; |
1820 | 0 | ptr += 4; |
1821 | 0 | len -= 4; |
1822 | |
|
1823 | 0 | if (type != SMUX_SET) { |
1824 | 0 | val_type = ASN_NULL; |
1825 | 0 | val_len = 0; |
1826 | 0 | } |
1827 | | |
1828 | | /* |
1829 | | * build var list : snmp_build_var_op not liked by gated XXX |
1830 | | */ |
1831 | 0 | ptr = snmp_build_var_op(ptr, objid, oidlen, val_type, val_len, |
1832 | 0 | val, &len); |
1833 | 0 | if (ptr == NULL) { |
1834 | 0 | return -1; |
1835 | 0 | } |
1836 | | |
1837 | 0 | len = ptr - save1; |
1838 | 0 | asn_build_sequence(save1, &len, type, (ptr - save1 - 4)); |
1839 | |
|
1840 | 0 | len = ptr - save2; |
1841 | 0 | asn_build_sequence(save2, &len, |
1842 | 0 | (ASN_SEQUENCE | ASN_CONSTRUCTOR), |
1843 | 0 | (ptr - save2 - 4)); |
1844 | |
|
1845 | 0 | *length = ptr - packet; |
1846 | |
|
1847 | 0 | return 0; |
1848 | 0 | } |
1849 | | |
1850 | | static void |
1851 | | smux_peer_cleanup(int sd) |
1852 | 0 | { |
1853 | 0 | smux_reg *nrptr, *rptr, *rptr2; |
1854 | 0 | int i; |
1855 | 0 | netsnmp_handler_registration *reg; |
1856 | | |
1857 | | /* |
1858 | | * close the descriptor |
1859 | | */ |
1860 | 0 | close(sd); |
1861 | | |
1862 | | /* |
1863 | | * delete all of the passive registrations that this peer owns |
1864 | | */ |
1865 | 0 | for (rptr = PassiveRegs; rptr; rptr = nrptr) { |
1866 | 0 | nrptr = rptr->sr_next; |
1867 | 0 | if (rptr->sr_fd == sd) { |
1868 | 0 | smux_list_detach(&PassiveRegs, rptr); |
1869 | 0 | free(rptr); |
1870 | 0 | } |
1871 | 0 | rptr = nrptr; |
1872 | 0 | } |
1873 | | /* |
1874 | | * find replacements for all of the active registrations found |
1875 | | */ |
1876 | 0 | for (rptr = ActiveRegs; rptr; rptr = rptr2) { |
1877 | 0 | rptr2 = rptr->sr_next; |
1878 | 0 | if (rptr->sr_fd == sd) { |
1879 | 0 | smux_list_detach(&ActiveRegs, rptr); |
1880 | 0 | if (rptr->reginfo) { |
1881 | 0 | netsnmp_unregister_handler(rptr->reginfo); |
1882 | 0 | rptr->reginfo = NULL; |
1883 | 0 | } |
1884 | 0 | if ((nrptr = smux_find_replacement(rptr->sr_name, |
1885 | 0 | rptr->sr_name_len)) != |
1886 | 0 | NULL) { |
1887 | 0 | smux_list_detach(&PassiveRegs, nrptr); |
1888 | 0 | reg = netsnmp_create_handler_registration("smux", |
1889 | 0 | smux_handler, |
1890 | 0 | nrptr->sr_name, |
1891 | 0 | nrptr->sr_name_len, |
1892 | 0 | HANDLER_CAN_RWRITE); |
1893 | 0 | if (reg == NULL) { |
1894 | 0 | snmp_log(LOG_ERR, "SMUX: cannot create new smux peer " |
1895 | 0 | "registration\n"); |
1896 | 0 | continue; |
1897 | 0 | } |
1898 | 0 | if (netsnmp_register_handler(reg) != MIB_REGISTERED_OK) { |
1899 | 0 | snmp_log(LOG_ERR, "SMUX: cannot register new smux peer\n"); |
1900 | 0 | continue; |
1901 | 0 | } |
1902 | 0 | nrptr->reginfo = reg; |
1903 | 0 | smux_list_add(&ActiveRegs, nrptr); |
1904 | 0 | } |
1905 | 0 | free(rptr); |
1906 | 0 | } |
1907 | 0 | } |
1908 | | |
1909 | | /* |
1910 | | * decrement the peer count |
1911 | | */ |
1912 | 0 | npeers--; |
1913 | | |
1914 | | /* |
1915 | | * make his auth available again |
1916 | | */ |
1917 | 0 | for (i = 0; i < nauths; i++) { |
1918 | 0 | if (Auths[i]->sa_active_fd == sd) { |
1919 | 0 | char oid_name[128]; |
1920 | 0 | Auths[i]->sa_active_fd = -1; |
1921 | 0 | snprint_objid(oid_name, sizeof(oid_name), Auths[i]->sa_oid, |
1922 | 0 | Auths[i]->sa_oid_len); |
1923 | 0 | DEBUGMSGTL(("smux", "peer disconnected: %s\n", oid_name)); |
1924 | 0 | } |
1925 | 0 | } |
1926 | 0 | } |
1927 | | |
1928 | | int |
1929 | | smux_send_rrsp(int sd, int pri) |
1930 | 0 | { |
1931 | 0 | u_char outdata[2 + sizeof(int)]; |
1932 | 0 | u_char *ptr = outdata; |
1933 | 0 | int intsize = sizeof(int); |
1934 | 0 | u_int mask = ((u_int) 0xFF) << (8 * (sizeof(int) - 1)); |
1935 | | /* |
1936 | | * e.g. mask is 0xFF000000 on a 32-bit machine |
1937 | | */ |
1938 | 0 | int sent; |
1939 | | |
1940 | | /* |
1941 | | * This is kind of like calling asn_build_int(), but the |
1942 | | * encoding will always be the size of an integer on this |
1943 | | * machine, never shorter. |
1944 | | */ |
1945 | 0 | *ptr++ = (u_char) SMUX_RRSP; |
1946 | 0 | *ptr++ = (u_char) intsize; |
1947 | | |
1948 | | /* |
1949 | | * Copy each byte, most significant first. |
1950 | | */ |
1951 | 0 | while (intsize--) { |
1952 | 0 | *ptr++ = (u_char) ((pri & mask) >> (8 * (sizeof(int) - 1))); |
1953 | 0 | pri <<= 8; |
1954 | 0 | } |
1955 | |
|
1956 | 0 | sent = sendto(sd, (char *) outdata, sizeof outdata, 0, NULL, 0); |
1957 | 0 | if (sent < 0) { |
1958 | 0 | DEBUGMSGTL(("smux", "[smux_send_rrsp] send failed\n")); |
1959 | 0 | } |
1960 | 0 | return (sent); |
1961 | 0 | } |
1962 | | |
1963 | | static u_char * |
1964 | | smux_trap_process(u_char * rsp, size_t * len) |
1965 | 0 | { |
1966 | 0 | oid sa_enterpriseoid[MAX_OID_LEN], var_name[MAX_OID_LEN]; |
1967 | 0 | size_t datalen, var_name_len, var_val_len, maxlen; |
1968 | 0 | size_t sa_enterpriseoid_len; |
1969 | 0 | u_char vartype, *ptr, *var_val; |
1970 | |
|
1971 | 0 | long trap, specific; |
1972 | 0 | u_long timestamp; |
1973 | |
|
1974 | 0 | netsnmp_variable_list *snmptrap_head, *snmptrap_ptr, *snmptrap_tmp; |
1975 | 0 | snmptrap_head = NULL; |
1976 | 0 | snmptrap_ptr = NULL; |
1977 | |
|
1978 | 0 | ptr = rsp; |
1979 | | |
1980 | | /* |
1981 | | * parse the sub-agent enterprise oid |
1982 | | */ |
1983 | 0 | sa_enterpriseoid_len = MAX_OID_LEN; |
1984 | 0 | if ((ptr = asn_parse_objid(ptr, len, |
1985 | 0 | &vartype, (oid *) & sa_enterpriseoid, |
1986 | 0 | &sa_enterpriseoid_len)) == NULL) { |
1987 | 0 | DEBUGMSGTL(("smux", |
1988 | 0 | "[smux_trap_process] asn_parse_objid failed\n")); |
1989 | 0 | return NULL; |
1990 | 0 | } |
1991 | | |
1992 | | /* |
1993 | | * parse the agent-addr ipAddress |
1994 | | */ |
1995 | 0 | datalen = SMUXMAXSTRLEN; |
1996 | 0 | if (((ptr = asn_parse_string(ptr, len, |
1997 | 0 | &vartype, smux_str, |
1998 | 0 | &datalen)) == NULL) || |
1999 | 0 | (vartype != (u_char) ASN_IPADDRESS)) { |
2000 | 0 | DEBUGMSGTL(("smux", |
2001 | 0 | "[smux_trap_process] asn_parse_string failed\n")); |
2002 | 0 | return NULL; |
2003 | 0 | } |
2004 | | |
2005 | | /* |
2006 | | * parse the generic trap int |
2007 | | */ |
2008 | 0 | datalen = sizeof(long); |
2009 | 0 | if ((ptr = asn_parse_int(ptr, len, &vartype, &trap, datalen)) == NULL) { |
2010 | 0 | DEBUGMSGTL(("smux", |
2011 | 0 | "[smux_trap_process] asn_parse_int generic failed\n")); |
2012 | 0 | return NULL; |
2013 | 0 | } |
2014 | | |
2015 | | /* |
2016 | | * parse the specific trap int |
2017 | | */ |
2018 | 0 | datalen = sizeof(long); |
2019 | 0 | if ((ptr = asn_parse_int(ptr, len, |
2020 | 0 | &vartype, &specific, datalen)) == NULL) { |
2021 | 0 | DEBUGMSGTL(("smux", |
2022 | 0 | "[smux_trap_process] asn_parse_int specific failed\n")); |
2023 | 0 | return NULL; |
2024 | 0 | } |
2025 | | |
2026 | | /* |
2027 | | * parse the timeticks timestamp |
2028 | | */ |
2029 | 0 | datalen = sizeof(u_long); |
2030 | 0 | if (((ptr = asn_parse_unsigned_int(ptr, len, |
2031 | 0 | &vartype, (u_long *) & timestamp, |
2032 | 0 | datalen)) == NULL) || |
2033 | 0 | (vartype != (u_char) ASN_TIMETICKS)) { |
2034 | 0 | DEBUGMSGTL(("smux", |
2035 | 0 | "[smux_trap_process] asn_parse_unsigned_int (timestamp) failed\n")); |
2036 | 0 | return NULL; |
2037 | 0 | } |
2038 | | |
2039 | | /* |
2040 | | * parse out the overall sequence |
2041 | | */ |
2042 | 0 | ptr = asn_parse_header(ptr, len, &vartype); |
2043 | 0 | if (ptr == NULL || vartype != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) { |
2044 | 0 | return NULL; |
2045 | 0 | } |
2046 | | |
2047 | | /* |
2048 | | * parse the variable bindings |
2049 | | */ |
2050 | 0 | while (ptr && *len) { |
2051 | | |
2052 | | /* |
2053 | | * get the objid and the asn1 coded value |
2054 | | */ |
2055 | 0 | var_name_len = MAX_OID_LEN; |
2056 | 0 | ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, &vartype, |
2057 | 0 | &var_val_len, (u_char **) & var_val, len); |
2058 | |
|
2059 | 0 | if (ptr == NULL) |
2060 | 0 | goto err; |
2061 | | |
2062 | 0 | maxlen = SMUXMAXPKTSIZE; |
2063 | 0 | switch ((short) vartype) { |
2064 | 0 | case ASN_INTEGER: |
2065 | 0 | var_val_len = sizeof(long); |
2066 | 0 | asn_parse_int(var_val, &maxlen, &vartype, |
2067 | 0 | (long *) &smux_long, var_val_len); |
2068 | 0 | var_val = (u_char *) & smux_long; |
2069 | 0 | break; |
2070 | 0 | case ASN_COUNTER: |
2071 | 0 | case ASN_GAUGE: |
2072 | 0 | case ASN_TIMETICKS: |
2073 | 0 | case ASN_UINTEGER: |
2074 | 0 | var_val_len = sizeof(u_long); |
2075 | 0 | asn_parse_unsigned_int(var_val, &maxlen, &vartype, |
2076 | 0 | (u_long *) & smux_ulong, var_val_len); |
2077 | 0 | var_val = (u_char *) & smux_ulong; |
2078 | 0 | break; |
2079 | 0 | case ASN_COUNTER64: |
2080 | 0 | var_val_len = sizeof(smux_counter64); |
2081 | 0 | asn_parse_unsigned_int64(var_val, &maxlen, &vartype, |
2082 | 0 | (struct counter64 *) &smux_counter64, |
2083 | 0 | var_val_len); |
2084 | 0 | var_val = (u_char *) & smux_counter64; |
2085 | 0 | break; |
2086 | 0 | case ASN_IPADDRESS: |
2087 | 0 | var_val_len = 4; |
2088 | | /* |
2089 | | * consume the tag and length, but just copy here |
2090 | | * because we know it is an ip address |
2091 | | */ |
2092 | 0 | if ((var_val = |
2093 | 0 | asn_parse_header(var_val, &maxlen, &vartype)) == NULL) |
2094 | 0 | goto err; |
2095 | 0 | memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val, |
2096 | 0 | var_val_len); |
2097 | 0 | var_val = (u_char *) & (smux_sa.sin_addr.s_addr); |
2098 | 0 | break; |
2099 | 0 | case ASN_OPAQUE: |
2100 | 0 | case ASN_OCTET_STR: |
2101 | | /* |
2102 | | * XXX |
2103 | | */ |
2104 | 0 | var_val_len = SMUXMAXSTRLEN; |
2105 | 0 | asn_parse_string(var_val, &maxlen, &vartype, |
2106 | 0 | smux_str, &var_val_len); |
2107 | 0 | var_val = smux_str; |
2108 | 0 | break; |
2109 | 0 | case ASN_OBJECT_ID: |
2110 | 0 | var_val_len = MAX_OID_LEN; |
2111 | 0 | asn_parse_objid(var_val, &maxlen, &vartype, |
2112 | 0 | smux_objid, &var_val_len); |
2113 | 0 | var_val_len *= sizeof(oid); |
2114 | 0 | var_val = (u_char *) smux_objid; |
2115 | 0 | break; |
2116 | 0 | case SNMP_NOSUCHOBJECT: |
2117 | 0 | case SNMP_NOSUCHINSTANCE: |
2118 | 0 | case SNMP_ENDOFMIBVIEW: |
2119 | 0 | case ASN_NULL: |
2120 | 0 | var_val = NULL; |
2121 | 0 | break; |
2122 | 0 | case ASN_BIT_STR: |
2123 | | /* |
2124 | | * XXX |
2125 | | */ |
2126 | 0 | var_val_len = SMUXMAXSTRLEN; |
2127 | 0 | asn_parse_bitstring(var_val, &maxlen, &vartype, |
2128 | 0 | smux_str, &var_val_len); |
2129 | 0 | var_val = (u_char *) smux_str; |
2130 | 0 | break; |
2131 | 0 | case ASN_NSAP: |
2132 | 0 | default: |
2133 | 0 | snmp_log(LOG_ERR, "bad type returned (%x)\n", vartype); |
2134 | 0 | var_val = NULL; |
2135 | 0 | break; |
2136 | 0 | } |
2137 | | |
2138 | 0 | snmptrap_tmp = calloc(1, sizeof(netsnmp_variable_list)); |
2139 | 0 | if (snmptrap_tmp == NULL) |
2140 | 0 | goto err; |
2141 | 0 | if (snmptrap_head == NULL) { |
2142 | 0 | snmptrap_head = snmptrap_tmp; |
2143 | 0 | snmptrap_ptr = snmptrap_head; |
2144 | 0 | } else { |
2145 | 0 | snmptrap_ptr->next_variable = snmptrap_tmp; |
2146 | 0 | snmptrap_ptr = snmptrap_ptr->next_variable; |
2147 | 0 | } |
2148 | |
|
2149 | 0 | snmptrap_ptr->type = vartype; |
2150 | 0 | snmptrap_ptr->next_variable = NULL; |
2151 | 0 | snmp_set_var_objid(snmptrap_ptr, var_name, var_name_len); |
2152 | 0 | snmp_set_var_value(snmptrap_ptr, (char *) var_val, var_val_len); |
2153 | |
|
2154 | 0 | } |
2155 | | |
2156 | | /* |
2157 | | * send the traps |
2158 | | */ |
2159 | 0 | send_enterprise_trap_vars(trap, specific, (oid *) & sa_enterpriseoid, |
2160 | 0 | sa_enterpriseoid_len, snmptrap_head); |
2161 | | |
2162 | | /* |
2163 | | * free trap variables |
2164 | | */ |
2165 | 0 | snmp_free_varbind(snmptrap_head); |
2166 | |
|
2167 | 0 | return ptr; |
2168 | | |
2169 | 0 | err: |
2170 | 0 | snmp_free_varbind(snmptrap_head); |
2171 | 0 | return NULL; |
2172 | 0 | } |
2173 | | |
2174 | 0 | #define NUM_SOCKETS 32 |
2175 | | static int sdlist[NUM_SOCKETS], sdlen = 0; |
2176 | | |
2177 | | int smux_snmp_select_list_add(int sd) |
2178 | 0 | { |
2179 | 0 | if (sdlen < NUM_SOCKETS) |
2180 | 0 | { |
2181 | 0 | sdlist[sdlen++] = sd; |
2182 | 0 | return(1); |
2183 | 0 | } |
2184 | 0 | return(0); |
2185 | 0 | } |
2186 | | |
2187 | | int smux_snmp_select_list_del(int sd) |
2188 | 0 | { |
2189 | 0 | int i, found=0; |
2190 | |
|
2191 | 0 | for (i = 0; i < (sdlen); i++) { |
2192 | 0 | if (sdlist[i] == sd) |
2193 | 0 | { |
2194 | 0 | sdlist[i] = 0; |
2195 | 0 | found = 1; |
2196 | 0 | } |
2197 | 0 | if ((found) &&(i < (sdlen - 1))) |
2198 | 0 | sdlist[i] = sdlist[i + 1]; |
2199 | 0 | } |
2200 | 0 | if (found) |
2201 | 0 | { |
2202 | 0 | sdlen--; |
2203 | 0 | return(1); |
2204 | 0 | } |
2205 | 0 | return(0); |
2206 | 0 | } |
2207 | | |
2208 | | int smux_snmp_select_list_get_length(void) |
2209 | 0 | { |
2210 | 0 | return(sdlen); |
2211 | 0 | } |
2212 | | |
2213 | | int smux_snmp_select_list_get_SD_from_List(int pos) |
2214 | 0 | { |
2215 | 0 | if (pos < NUM_SOCKETS) |
2216 | 0 | { |
2217 | 0 | return(sdlist[pos]); |
2218 | 0 | } |
2219 | 0 | return(0); |
2220 | 0 | } |