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