OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / ferret / snmp.c
1 /* Copyright (c) 2007 by Errata Security */\r
2 #include "protos.h"\r
3 #include "netframe.h"\r
4 #include "ferret.h"\r
5 #include "formats.h"\r
6 \r
7 #include <string.h>\r
8 \r
9 struct SNMP\r
10 {\r
11         unsigned version;\r
12         unsigned pdu_tag;\r
13         const unsigned char *community;\r
14         unsigned community_length;\r
15         unsigned request_id;\r
16         unsigned error_index;\r
17         unsigned error_status;\r
18 };\r
19 \r
20 const unsigned snmp_length(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)\r
21 {\r
22         unsigned result;\r
23 \r
24         if ( (*r_offset >= length) \r
25                 || (px[*r_offset] & 0x80) \r
26                 && ((*r_offset) + (px[*r_offset]&0x7F) >= length)) {\r
27                 FRAMERR(frame, "snmp: truncated\n");\r
28                 *r_offset = length;\r
29                 return 0xFFFFffff;\r
30         }\r
31         result = px[(*r_offset)++];\r
32         if (result & 0x80) {\r
33                 unsigned length_of_length = result & 0x7F;\r
34                 if (length_of_length == 0) {\r
35                         FRAMERR(frame, "snmp: unexpected value\n");\r
36                         *r_offset = length;\r
37                         return 0xFFFFffff;\r
38                 }\r
39                 result = 0;\r
40                 while (length_of_length) {\r
41                         result = result * 256 + px[(*r_offset)++];\r
42                         if (result > 0x10000) {\r
43                                 FRAMERR(frame, "snmp: unexpected value\n");\r
44                                 *r_offset = length;\r
45                                 return 0xFFFFffff;\r
46                         }\r
47                 }\r
48         }\r
49         return result;\r
50 }\r
51 const unsigned snmp_integer(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)\r
52 {\r
53         unsigned int_length;\r
54         unsigned result;\r
55 \r
56         if (px[(*r_offset)++] != 0x02) {\r
57                 FRAMERR(frame, "snmp: unexpected tag\n");\r
58                 *r_offset = length;\r
59                 return 0xFFFFffff;\r
60         }\r
61 \r
62         int_length = snmp_length(frame, px, length, r_offset);\r
63         if (int_length == 0xFFFFffff) {\r
64                 *r_offset = length;\r
65                 return 0xFFFFffff;\r
66         }\r
67         if (*r_offset + int_length > length) {\r
68                 FRAMERR(frame, "snmp: truncated\n");\r
69                 *r_offset = length;\r
70                 return 0xFFFFffff;\r
71         }\r
72 \r
73         result = 0;\r
74         while (int_length--)\r
75                 result = result * 256 + px[(*r_offset)++];\r
76 \r
77         return result;\r
78 }\r
79 \r
80 static unsigned snmp_tag(const unsigned char *px, unsigned length, unsigned *r_offset)\r
81 {\r
82         if (*r_offset >= length)\r
83                 return 0;\r
84         return px[(*r_offset)++];\r
85 }\r
86 \r
87 void process_snmp(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length)\r
88 {\r
89         unsigned offset=0;\r
90         unsigned outer_length;\r
91         struct SNMP snmp[1];\r
92 \r
93         memset(&snmp, 0, sizeof(*snmp));\r
94 \r
95         /* tag */\r
96         if (snmp_tag(px, length, &offset) != 0x30)\r
97                 return;\r
98 \r
99         /* length */\r
100         outer_length = snmp_length(frame, px, length, &offset);\r
101         if (length > outer_length + offset)\r
102                 length = outer_length + offset;\r
103 \r
104         /* Version */\r
105         snmp->version = snmp_integer(frame, px, length, &offset);\r
106         if (snmp->version != 0)\r
107                 return;\r
108 \r
109         /* Community */\r
110         if (snmp_tag(px, length, &offset) != 0x04)\r
111                 return;\r
112         snmp->community_length = snmp_length(frame, px, length, &offset);\r
113         snmp->community = px+offset;\r
114         offset += snmp->community_length;\r
115 \r
116         /* PDU */\r
117         snmp->pdu_tag = snmp_tag(px, length, &offset);\r
118         if (snmp->pdu_tag < 0xA0 || 0xA5 < snmp->pdu_tag)\r
119                 return;\r
120         outer_length = snmp_length(frame, px, length, &offset);\r
121         if (length > outer_length + offset)\r
122                 length = outer_length + offset;\r
123 \r
124         /* Request ID */\r
125         snmp->request_id = snmp_integer(frame, px, length, &offset);\r
126         snmp->error_status = snmp_integer(frame, px, length, &offset);\r
127         snmp->error_index = snmp_integer(frame, px, length, &offset);\r
128 \r
129         /* Varbind List */\r
130         if (snmp_tag(px, length, &offset) != 0x30)\r
131                 return;\r
132         outer_length = snmp_length(frame, px, length, &offset);\r
133         if (length > outer_length + offset)\r
134                 length = outer_length + offset;\r
135 \r
136         /* Var-bind list */\r
137         while (offset < length) {\r
138                 unsigned varbind_length;\r
139                 unsigned varbind_end;\r
140                 if (px[offset++] != 0x30) {\r
141                         FRAMERR(frame, "snmp: unexpected value\n");\r
142                         break;\r
143                 }\r
144                 varbind_length = snmp_length(frame, px, length, &offset);\r
145                 if (varbind_length == 0xFFFFffff)\r
146                         break;\r
147                 varbind_end = offset + varbind_length;\r
148                 if (varbind_end > length) {\r
149                         FRAMERR(frame, "snmp: unexpected value\n");\r
150                         return;\r
151                 }\r
152                 \r
153                 /* OID */\r
154                 if (snmp_tag(px,length,&offset) != 6)\r
155                         return;\r
156                 else {\r
157                         unsigned oid_length = snmp_length(frame, px, length, &offset);\r
158                         const unsigned char *oid = px+offset;\r
159                         unsigned value_tag;\r
160                         unsigned value_length;\r
161 \r
162                         offset += oid_length;\r
163                         if (offset > length)\r
164                                 return;\r
165 \r
166                         value_tag = snmp_tag(px,length,&offset);\r
167                         value_length = snmp_length(frame, px, length, &offset);\r
168                 \r
169                         switch (snmp->pdu_tag) {\r
170                         case 0xA0:\r
171                                 process_record(seap, \r
172                                         "proto",REC_SZ,"SNMP",-1,\r
173                                         "GET", REC_FRAMESRC,    frame, -1,\r
174                                         "community",REC_PRINTABLE, snmp->community, snmp->community_length,\r
175                                         0);\r
176                                 process_record(seap, \r
177                                         "proto",REC_SZ,"SNMP",-1,\r
178                                         "GET", REC_FRAMESRC,    frame, -1,\r
179                                         "oid",REC_OID, oid, oid_length,\r
180                                         0);\r
181                                 break;\r
182                         default:\r
183                                 FRAMERR(frame, "snmp: unknown msg type\n");\r
184                         }\r
185 \r
186                 }\r
187 \r
188         }\r
189 \r
190 }\r
191 \r