/src/net-snmp/snmplib/snmp.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Simple Network Management Protocol (RFC 1067). |
3 | | * |
4 | | */ |
5 | | /********************************************************************** |
6 | | Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University |
7 | | |
8 | | All Rights Reserved |
9 | | |
10 | | Permission to use, copy, modify, and distribute this software and its |
11 | | documentation for any purpose and without fee is hereby granted, |
12 | | provided that the above copyright notice appear in all copies and that |
13 | | both that copyright notice and this permission notice appear in |
14 | | supporting documentation, and that the name of CMU not be |
15 | | used in advertising or publicity pertaining to distribution of the |
16 | | software without specific, written prior permission. |
17 | | |
18 | | CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
19 | | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
20 | | CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
21 | | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
22 | | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
23 | | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
24 | | SOFTWARE. |
25 | | ******************************************************************/ |
26 | | |
27 | | #include <net-snmp/net-snmp-config.h> |
28 | | #include <ctype.h> |
29 | | |
30 | | #ifdef KINETICS |
31 | | #include "gw.h" |
32 | | #include "ab.h" |
33 | | #include "inet.h" |
34 | | #include "fp4/cmdmacro.h" |
35 | | #include "fp4/pbuf.h" |
36 | | #include "glob.h" |
37 | | #endif |
38 | | |
39 | | #include <stdio.h> |
40 | | #include <stdlib.h> |
41 | | |
42 | | #include <sys/types.h> |
43 | | #ifdef HAVE_STRING_H |
44 | | #include <string.h> |
45 | | #else |
46 | | #include <strings.h> |
47 | | #endif |
48 | | #ifdef HAVE_NETINET_IN_H |
49 | | #include <netinet/in.h> |
50 | | #endif |
51 | | #ifdef HAVE_SYS_SELECT_H |
52 | | #include <sys/select.h> |
53 | | #endif |
54 | | #ifndef NULL |
55 | | #define NULL 0 |
56 | | #endif |
57 | | |
58 | | #ifdef vms |
59 | | #include <in.h> |
60 | | #endif |
61 | | |
62 | | #include <net-snmp/types.h> |
63 | | #include <net-snmp/output_api.h> |
64 | | |
65 | | #include <net-snmp/library/asn1.h> |
66 | | #include <net-snmp/library/snmp.h> /* for "internal" definitions */ |
67 | | #include <net-snmp/library/snmp_api.h> |
68 | | #include <net-snmp/library/snmp_impl.h> |
69 | | #include <net-snmp/library/mib.h> |
70 | | |
71 | | /** @mainpage Net-SNMP Coding Documentation |
72 | | * @section Introduction |
73 | | |
74 | | This is the Net-SNMP coding and API reference documentation. It is |
75 | | incomplete, but when combined with the manual page set and |
76 | | tutorials forms a pretty comprehensive starting point. |
77 | | |
78 | | @section Starting_out Starting out |
79 | | |
80 | | The best places to start learning are the @e Net-SNMP @e tutorial |
81 | | (http://www.Net-SNMP.org/tutorial-5/) and the @e Modules and @e |
82 | | Examples sections of this document. |
83 | | |
84 | | */ |
85 | | |
86 | | void |
87 | | xdump(const void * data, size_t length, const char *prefix) |
88 | 0 | { |
89 | 0 | const u_char * const cp = (const u_char*)data; |
90 | 0 | int col, count; |
91 | 0 | char *buffer; |
92 | 0 | #ifndef NETSNMP_DISABLE_DYNAMIC_LOG_LEVEL |
93 | 0 | int debug_log_level = netsnmp_get_debug_log_level(); |
94 | | #else |
95 | | #define debug_log_level LOG_DEBUG |
96 | | #endif /* NETSNMP_DISABLE_DYNAMIC_LOG_LEVEL */ |
97 | |
|
98 | 0 | buffer = (char *) malloc(strlen(prefix) + 80); |
99 | 0 | if (!buffer) { |
100 | 0 | snmp_log(LOG_NOTICE, |
101 | 0 | "xdump: malloc failed. packet-dump skipped\n"); |
102 | 0 | return; |
103 | 0 | } |
104 | | |
105 | 0 | count = 0; |
106 | 0 | while (count < (int) length) { |
107 | 0 | strcpy(buffer, prefix); |
108 | 0 | sprintf(buffer + strlen(buffer), "%.4d: ", count); |
109 | |
|
110 | 0 | for (col = 0; ((count + col) < (int) length) && col < 16; col++) { |
111 | 0 | sprintf(buffer + strlen(buffer), "%02X ", cp[count + col]); |
112 | 0 | if (col % 4 == 3) |
113 | 0 | strcat(buffer, " "); |
114 | 0 | } |
115 | 0 | for (; col < 16; col++) { /* pad end of buffer with zeros */ |
116 | 0 | strcat(buffer, " "); |
117 | 0 | if (col % 4 == 3) |
118 | 0 | strcat(buffer, " "); |
119 | 0 | } |
120 | 0 | strcat(buffer, " "); |
121 | 0 | for (col = 0; ((count + col) < (int) length) && col < 16; col++) { |
122 | 0 | buffer[col + 60] = |
123 | 0 | isprint(cp[count + col]) ? cp[count + col] : '.'; |
124 | 0 | } |
125 | 0 | buffer[col + 60] = '\n'; |
126 | 0 | buffer[col + 60 + 1] = 0; |
127 | 0 | snmp_log(debug_log_level, "%s", buffer); |
128 | 0 | count += col; |
129 | 0 | } |
130 | 0 | snmp_log(debug_log_level, "\n"); |
131 | 0 | free(buffer); |
132 | |
|
133 | 0 | } /* end xdump() */ |
134 | | |
135 | | /* |
136 | | * u_char * snmp_parse_var_op( |
137 | | * u_char *data IN - pointer to the start of object |
138 | | * oid *var_name OUT - object id of variable |
139 | | * int *var_name_len IN/OUT - length of variable name |
140 | | * u_char *var_val_type OUT - type of variable (int or octet string) (one byte) |
141 | | * int *var_val_len OUT - length of variable |
142 | | * u_char **var_val OUT - pointer to ASN1 encoded value of variable |
143 | | * int *listlength IN/OUT - number of valid bytes left in var_op_list |
144 | | */ |
145 | | |
146 | | u_char * |
147 | | snmp_parse_var_op(u_char * data, |
148 | | oid * var_name, |
149 | | size_t * var_name_len, |
150 | | u_char * var_val_type, |
151 | | size_t * var_val_len, |
152 | | u_char ** var_val, size_t * listlength) |
153 | 0 | { |
154 | 0 | u_char var_op_type; |
155 | 0 | size_t var_op_len = *listlength; |
156 | 0 | u_char *var_op_start = data; |
157 | |
|
158 | 0 | data = asn_parse_sequence(data, &var_op_len, &var_op_type, |
159 | 0 | (ASN_SEQUENCE | ASN_CONSTRUCTOR), "var_op"); |
160 | 0 | if (data == NULL) { |
161 | | /* |
162 | | * msg detail is set |
163 | | */ |
164 | 0 | return NULL; |
165 | 0 | } |
166 | 0 | DEBUGDUMPHEADER("recv", "Name"); |
167 | 0 | data = |
168 | 0 | asn_parse_objid(data, &var_op_len, &var_op_type, var_name, |
169 | 0 | var_name_len); |
170 | 0 | DEBUGINDENTLESS(); |
171 | 0 | if (data == NULL) { |
172 | 0 | ERROR_MSG("No OID for variable"); |
173 | 0 | return NULL; |
174 | 0 | } |
175 | 0 | if (var_op_type != |
176 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID)) |
177 | 0 | return NULL; |
178 | 0 | *var_val = data; /* save pointer to this object */ |
179 | | /* |
180 | | * find out what type of object this is |
181 | | */ |
182 | 0 | data = asn_parse_header(data, &var_op_len, var_val_type); |
183 | 0 | if (data == NULL) { |
184 | 0 | ERROR_MSG("No header for value"); |
185 | 0 | return NULL; |
186 | 0 | } |
187 | | /* |
188 | | * XXX no check for type! |
189 | | */ |
190 | 0 | *var_val_len = var_op_len; |
191 | 0 | data += var_op_len; |
192 | 0 | *listlength -= (int) (data - var_op_start); |
193 | 0 | return data; |
194 | 0 | } |
195 | | |
196 | | /** |
197 | | * ASN encode a varbind |
198 | | * |
199 | | * @param data[in] pointer to the beginning of the output buffer |
200 | | * @param var_name[in] object id of variable |
201 | | * @param var_name_len[in] length of object id |
202 | | * @param var_val_type[in] type of variable |
203 | | * @param var_val_len[in] length of variable |
204 | | * @param var_val[in] value of variable |
205 | | * @param listlength[in|out] number of valid bytes left in output buffer |
206 | | */ |
207 | | |
208 | | u_char * |
209 | | snmp_build_var_op(u_char * data, |
210 | | const oid * var_name, |
211 | | size_t * var_name_len, |
212 | | u_char var_val_type, |
213 | | size_t var_val_len, |
214 | | const void * var_val, size_t * listlength) |
215 | 0 | { |
216 | 0 | const size_t headerLen = 4; |
217 | 0 | size_t sequenceLen; |
218 | 0 | u_char *const dataPtr = data; |
219 | |
|
220 | 0 | if (*listlength < headerLen) |
221 | 0 | return NULL; |
222 | 0 | data += headerLen; |
223 | 0 | *listlength -= headerLen; |
224 | |
|
225 | 0 | DEBUGDUMPHEADER("send", "Name"); |
226 | 0 | data = asn_build_objid(data, listlength, |
227 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
228 | 0 | ASN_OBJECT_ID), var_name, |
229 | 0 | *var_name_len); |
230 | 0 | DEBUGINDENTLESS(); |
231 | 0 | if (data == NULL) { |
232 | 0 | ERROR_MSG("Can't build OID for variable"); |
233 | 0 | return NULL; |
234 | 0 | } |
235 | 0 | DEBUGDUMPHEADER("send", "Value"); |
236 | 0 | switch (var_val_type) { |
237 | 0 | case ASN_INTEGER: |
238 | 0 | data = asn_build_int(data, listlength, var_val_type, |
239 | 0 | var_val, var_val_len); |
240 | 0 | break; |
241 | 0 | case ASN_GAUGE: |
242 | 0 | case ASN_COUNTER: |
243 | 0 | case ASN_TIMETICKS: |
244 | 0 | case ASN_UINTEGER: |
245 | 0 | data = asn_build_unsigned_int(data, listlength, var_val_type, |
246 | 0 | var_val, var_val_len); |
247 | 0 | break; |
248 | 0 | #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
249 | 0 | case ASN_OPAQUE_COUNTER64: |
250 | 0 | case ASN_OPAQUE_U64: |
251 | 0 | #endif |
252 | 0 | case ASN_COUNTER64: |
253 | 0 | data = asn_build_unsigned_int64(data, listlength, var_val_type, |
254 | 0 | var_val, var_val_len); |
255 | 0 | break; |
256 | 0 | case ASN_OCTET_STR: |
257 | 0 | case ASN_IPADDRESS: |
258 | 0 | case ASN_OPAQUE: |
259 | 0 | case ASN_NSAP: |
260 | 0 | data = asn_build_string(data, listlength, var_val_type, |
261 | 0 | var_val, var_val_len); |
262 | 0 | break; |
263 | 0 | case ASN_OBJECT_ID: |
264 | 0 | data = asn_build_objid(data, listlength, var_val_type, |
265 | 0 | var_val, var_val_len / sizeof(oid)); |
266 | 0 | break; |
267 | 0 | case ASN_NULL: |
268 | 0 | data = asn_build_null(data, listlength, var_val_type); |
269 | 0 | break; |
270 | 0 | case ASN_BIT_STR: |
271 | 0 | data = asn_build_bitstring(data, listlength, var_val_type, |
272 | 0 | var_val, var_val_len); |
273 | 0 | break; |
274 | 0 | case SNMP_NOSUCHOBJECT: |
275 | 0 | case SNMP_NOSUCHINSTANCE: |
276 | 0 | case SNMP_ENDOFMIBVIEW: |
277 | 0 | data = asn_build_null(data, listlength, var_val_type); |
278 | 0 | break; |
279 | 0 | #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
280 | 0 | case ASN_OPAQUE_FLOAT: |
281 | 0 | data = asn_build_float(data, listlength, var_val_type, |
282 | 0 | var_val, var_val_len); |
283 | 0 | break; |
284 | 0 | case ASN_OPAQUE_DOUBLE: |
285 | 0 | data = asn_build_double(data, listlength, var_val_type, |
286 | 0 | var_val, var_val_len); |
287 | 0 | break; |
288 | 0 | case ASN_OPAQUE_I64: |
289 | 0 | data = asn_build_signed_int64(data, listlength, var_val_type, |
290 | 0 | var_val, var_val_len); |
291 | 0 | break; |
292 | 0 | #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ |
293 | 0 | default: |
294 | 0 | { |
295 | 0 | char error_buf[64]; |
296 | 0 | snprintf(error_buf, sizeof(error_buf), |
297 | 0 | "wrong type in snmp_build_var_op: %d", var_val_type); |
298 | 0 | ERROR_MSG(error_buf); |
299 | 0 | data = NULL; |
300 | 0 | } |
301 | 0 | } |
302 | 0 | DEBUGINDENTLESS(); |
303 | 0 | if (data == NULL) { |
304 | 0 | return NULL; |
305 | 0 | } |
306 | | |
307 | 0 | sequenceLen = (data - dataPtr) - headerLen; |
308 | 0 | asn_build_sequence(dataPtr, &sequenceLen, ASN_SEQUENCE | ASN_CONSTRUCTOR, |
309 | 0 | headerLen); |
310 | 0 | return data; |
311 | 0 | } |
312 | | |
313 | | #ifdef NETSNMP_USE_REVERSE_ASNENCODING |
314 | | int |
315 | | snmp_realloc_rbuild_var_op(u_char ** pkt, size_t * pkt_len, |
316 | | size_t * offset, int allow_realloc, |
317 | | const oid * var_name, size_t * var_name_len, |
318 | | u_char var_val_type, |
319 | | u_char * var_val, size_t var_val_len) |
320 | 0 | { |
321 | 0 | size_t start_offset = *offset; |
322 | 0 | int rc = 0; |
323 | | |
324 | | /* |
325 | | * Encode the value. |
326 | | */ |
327 | 0 | DEBUGDUMPHEADER("send", "Value"); |
328 | |
|
329 | 0 | switch (var_val_type) { |
330 | 0 | case ASN_INTEGER: |
331 | 0 | rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, allow_realloc, |
332 | 0 | var_val_type, (long *) var_val, |
333 | 0 | var_val_len); |
334 | 0 | break; |
335 | | |
336 | 0 | case ASN_GAUGE: |
337 | 0 | case ASN_COUNTER: |
338 | 0 | case ASN_TIMETICKS: |
339 | 0 | case ASN_UINTEGER: |
340 | 0 | rc = asn_realloc_rbuild_unsigned_int(pkt, pkt_len, offset, |
341 | 0 | allow_realloc, var_val_type, |
342 | 0 | (u_long *) var_val, |
343 | 0 | var_val_len); |
344 | 0 | break; |
345 | | |
346 | 0 | #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
347 | 0 | case ASN_OPAQUE_COUNTER64: |
348 | 0 | case ASN_OPAQUE_U64: |
349 | 0 | #endif |
350 | 0 | case ASN_COUNTER64: |
351 | 0 | rc = asn_realloc_rbuild_unsigned_int64(pkt, pkt_len, offset, |
352 | 0 | allow_realloc, var_val_type, |
353 | 0 | (struct counter64 *) |
354 | 0 | var_val, var_val_len); |
355 | 0 | break; |
356 | | |
357 | 0 | case ASN_OCTET_STR: |
358 | 0 | case ASN_IPADDRESS: |
359 | 0 | case ASN_OPAQUE: |
360 | 0 | case ASN_NSAP: |
361 | 0 | rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, allow_realloc, |
362 | 0 | var_val_type, var_val, var_val_len); |
363 | 0 | break; |
364 | | |
365 | 0 | case ASN_OBJECT_ID: |
366 | 0 | rc = asn_realloc_rbuild_objid(pkt, pkt_len, offset, allow_realloc, |
367 | 0 | var_val_type, (oid *) var_val, |
368 | 0 | var_val_len / sizeof(oid)); |
369 | 0 | break; |
370 | | |
371 | 0 | case ASN_NULL: |
372 | 0 | rc = asn_realloc_rbuild_null(pkt, pkt_len, offset, allow_realloc, |
373 | 0 | var_val_type); |
374 | 0 | break; |
375 | | |
376 | 0 | case ASN_BIT_STR: |
377 | 0 | rc = asn_realloc_rbuild_bitstring(pkt, pkt_len, offset, |
378 | 0 | allow_realloc, var_val_type, |
379 | 0 | var_val, var_val_len); |
380 | 0 | break; |
381 | | |
382 | 0 | case SNMP_NOSUCHOBJECT: |
383 | 0 | case SNMP_NOSUCHINSTANCE: |
384 | 0 | case SNMP_ENDOFMIBVIEW: |
385 | 0 | rc = asn_realloc_rbuild_null(pkt, pkt_len, offset, allow_realloc, |
386 | 0 | var_val_type); |
387 | 0 | break; |
388 | | |
389 | 0 | #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES |
390 | 0 | case ASN_OPAQUE_FLOAT: |
391 | 0 | rc = asn_realloc_rbuild_float(pkt, pkt_len, offset, allow_realloc, |
392 | 0 | var_val_type, (float *) var_val, |
393 | 0 | var_val_len); |
394 | 0 | break; |
395 | | |
396 | 0 | case ASN_OPAQUE_DOUBLE: |
397 | 0 | rc = asn_realloc_rbuild_double(pkt, pkt_len, offset, allow_realloc, |
398 | 0 | var_val_type, (double *) var_val, |
399 | 0 | var_val_len); |
400 | 0 | break; |
401 | | |
402 | 0 | case ASN_OPAQUE_I64: |
403 | 0 | rc = asn_realloc_rbuild_signed_int64(pkt, pkt_len, offset, |
404 | 0 | allow_realloc, var_val_type, |
405 | 0 | (struct counter64 *) var_val, |
406 | 0 | var_val_len); |
407 | 0 | break; |
408 | 0 | #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ |
409 | 0 | default: |
410 | 0 | { |
411 | 0 | char error_buf[64]; |
412 | 0 | snprintf(error_buf, sizeof(error_buf), |
413 | 0 | "wrong type in snmp_realloc_rbuild_var_op: %d", var_val_type); |
414 | 0 | ERROR_MSG(error_buf); |
415 | 0 | rc = 0; |
416 | 0 | } |
417 | 0 | } |
418 | 0 | DEBUGINDENTLESS(); |
419 | |
|
420 | 0 | if (rc == 0) { |
421 | 0 | return 0; |
422 | 0 | } |
423 | | |
424 | | /* |
425 | | * Build the OID. |
426 | | */ |
427 | | |
428 | 0 | DEBUGDUMPHEADER("send", "Name"); |
429 | 0 | rc = asn_realloc_rbuild_objid(pkt, pkt_len, offset, allow_realloc, |
430 | 0 | (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | |
431 | 0 | ASN_OBJECT_ID), var_name, |
432 | 0 | *var_name_len); |
433 | 0 | DEBUGINDENTLESS(); |
434 | 0 | if (rc == 0) { |
435 | 0 | ERROR_MSG("Can't build OID for variable"); |
436 | 0 | return 0; |
437 | 0 | } |
438 | | |
439 | | /* |
440 | | * Build the sequence header. |
441 | | */ |
442 | | |
443 | 0 | rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, allow_realloc, |
444 | 0 | (u_char) (ASN_SEQUENCE | |
445 | 0 | ASN_CONSTRUCTOR), |
446 | 0 | *offset - start_offset); |
447 | 0 | return rc; |
448 | 0 | } |
449 | | |
450 | | #endif /* NETSNMP_USE_REVERSE_ASNENCODING */ |