OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / ferret / smb_dgm.c
1 /* Copyright (c) 2007 by Errata Security */\r
2 #include "protos.h"\r
3 #include "netframe.h"\r
4 #include "formats.h"\r
5 #include "ferret.h"\r
6 \r
7 #include <ctype.h>\r
8 #include <string.h>\r
9 #include <stdio.h>\r
10 \r
11 #ifndef MIN\r
12 #define MIN(a,b) ((a)<(b)?(a):(b))\r
13 #endif\r
14 \r
15 struct SMBdgm_transact\r
16 {\r
17         unsigned word_count;\r
18         unsigned total_parm_count;\r
19         unsigned total_data_count;\r
20         unsigned max_parm_count;\r
21         unsigned max_data_count;\r
22         unsigned max_setup_count;\r
23         unsigned flags;\r
24         unsigned timeout;\r
25         unsigned parm_count;\r
26         unsigned parm_offset;\r
27         unsigned data_count;\r
28         unsigned data_offset;\r
29         unsigned setup_count;\r
30         unsigned byte_count;\r
31         unsigned setup_offset;\r
32         unsigned extra_offset;\r
33         unsigned extra_length;\r
34 };\r
35 struct SMBdgm\r
36 {\r
37         unsigned command;\r
38         unsigned err;\r
39         unsigned errcode;\r
40         unsigned flags;\r
41         unsigned flags2;\r
42         unsigned process_id_high;\r
43         unsigned process_id;\r
44         unsigned char signature[8];\r
45         unsigned tree_id;\r
46         unsigned user_id;\r
47         unsigned multiplex_id;\r
48 \r
49         union {\r
50                 struct SMBdgm_transact trans;\r
51         } dgm;\r
52 \r
53         struct MailSlot {\r
54                 unsigned opcode;\r
55                 unsigned priority;\r
56                 unsigned clss;\r
57                 const unsigned char *name;\r
58                 unsigned name_length;\r
59         } mailslot;\r
60 \r
61 };\r
62 \r
63 static unsigned get_byte(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)\r
64 {\r
65         unsigned result;\r
66         unsigned offset = *r_offset;\r
67         \r
68         if (offset > length)\r
69                 return 0;\r
70         if (offset == length) {\r
71                 FRAMERR(frame, "smb: truncated\n");\r
72                 return 0;\r
73         }\r
74         result = px[offset];\r
75         \r
76         (*r_offset)++;\r
77         return result;\r
78 }\r
79 static unsigned get_word(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)\r
80 {\r
81         unsigned result;\r
82         unsigned offset = *r_offset;\r
83         \r
84         if (offset > length)\r
85                 return 0;\r
86         if (offset == length) {\r
87                 FRAMERR(frame, "smb: truncated\n");\r
88                 return 0;\r
89         }\r
90         if (offset+1 == length) {\r
91                 FRAMERR(frame, "smb: truncated\n");\r
92                 return 0;\r
93         }\r
94         result = ex16le(px+offset);\r
95         \r
96         (*r_offset) += 2;\r
97         return result;\r
98 }\r
99 static unsigned get_dword(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)\r
100 {\r
101         unsigned result;\r
102         unsigned offset = *r_offset;\r
103         \r
104         if (offset > length)\r
105                 return 0;\r
106         if (offset == length) {\r
107                 FRAMERR(frame, "smb: truncated\n");\r
108                 return 0;\r
109         }\r
110         if (offset+1 == length) {\r
111                 FRAMERR(frame, "smb: truncated\n");\r
112                 return 0;\r
113         }\r
114         if (offset+2 == length) {\r
115                 FRAMERR(frame, "smb: truncated\n");\r
116                 return 0;\r
117         }\r
118         if (offset+3 == length) {\r
119                 FRAMERR(frame, "smb: truncated\n");\r
120                 return 0;\r
121         }\r
122         result = ex32le(px+offset);\r
123         \r
124         (*r_offset) += 4;\r
125         return result;\r
126 }\r
127 \r
128 static int path_equals(const unsigned char *name, unsigned name_length, const char *value)\r
129 {\r
130         unsigned i;\r
131 \r
132         for (i=0; i<name_length && value[i]; i++)\r
133                 if (tolower(name[i]) != tolower(value[i]))\r
134                         return 0;\r
135         if (i==name_length && value[i] == '\0')\r
136                 return 1;\r
137         else \r
138                 return 0;\r
139 }\r
140 \r
141 static unsigned cleanse_netbios_name(const char *name)\r
142 {\r
143         unsigned length = strlen(name);\r
144 \r
145         if (length>4 && name[length-1] == '>') {\r
146                 if (isdigit(name[length-2]) && isdigit(name[length-3]) && name[length-4] == '<')\r
147                         length-=4;\r
148         }\r
149         while (length && isspace(name[length-1]))\r
150                 length--;\r
151         return length;\r
152 }\r
153 void process_BROWSE(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned offset, struct SMBdgm *smb)\r
154 {\r
155         unsigned cmd;\r
156 \r
157         smb;length;\r
158         cmd = px[offset]; //get_byte(frame, px, length, &offset);\r
159 \r
160         switch (cmd) {\r
161         case 15: /*Local Master Announcement*/\r
162         case 9: /* Get Backup List Request*/\r
163         case 8: /* Browser election Request */\r
164         case 2: /* Request Announcement */\r
165                 break;\r
166         case 12: /*0x0c - Domain/Workgroup Announcement */\r
167                 {\r
168                         const unsigned char *workgroup = px+offset+6;\r
169                         unsigned workgroup_length;\r
170                         const char *hostname = frame->netbios_source;\r
171                         unsigned hostname_length = cleanse_netbios_name(hostname);\r
172 \r
173                         /* find nul terminator */\r
174                         for (workgroup_length=0; workgroup_length<16 && workgroup[workgroup_length]; workgroup_length++)\r
175                                 ;\r
176 \r
177                         process_record(seap,\r
178                                 "proto",        REC_SZ,                 "MS-BROWSE",                            -1,\r
179                                 "op",           REC_SZ,                 "domain",                                       -1,\r
180                                 "domain",       REC_PRINTABLE,  workgroup,                                      workgroup_length,\r
181                                 "hostname",     REC_PRINTABLE,  hostname,                                       hostname_length,\r
182                                 "ip.src",       REC_FRAMESRC,   frame, -1,\r
183                                 0);\r
184                 }\r
185                 break;\r
186         case 1: /*0x01 - Host Announcement */\r
187                 {\r
188                         const unsigned char *netbios;\r
189                         unsigned netbios_length;\r
190                         unsigned major, minor;\r
191                         const unsigned char *comment;\r
192                         unsigned comment_length;\r
193                         char winver[32];\r
194 \r
195                         if (offset + 22 > length) {\r
196                                 FRAMERR(frame, "MS-BROWSE: truncated\n");\r
197                                 break;\r
198                         }\r
199                         offset += 6;\r
200 \r
201                         netbios = px+offset;\r
202 \r
203                         /* find nul terminator */\r
204                         for (netbios_length=0; offset+netbios_length<length && netbios_length<16 && netbios[netbios_length]; netbios_length++)\r
205                                 ;\r
206 \r
207 \r
208                         process_record(seap,\r
209                                 "ID-IP",        REC_FRAMESRC,   frame, -1,\r
210                                 "netbios",      REC_PRINTABLE,  netbios,                                        netbios_length,\r
211                                 0);\r
212 \r
213                         offset += 16;\r
214 \r
215                         if (offset + 2 > length) {\r
216                                 FRAMERR(frame, "MS-BROWSE: truncated\n");\r
217                                 break;\r
218                         }\r
219 \r
220                         major = px[offset];\r
221                         minor = px[offset+1];\r
222                         _snprintf(winver, sizeof(winver), "%d.%d", major, minor);\r
223 \r
224                         process_record(seap,\r
225                                 "ID-IP",        REC_FRAMESRC,   frame, -1,\r
226                                 "win-ver",      REC_SZ,         winver,                                 -1,\r
227                                 0);\r
228 \r
229                         offset += 10;\r
230 \r
231 \r
232                         comment = px+offset;\r
233                         for (comment_length=0; offset+comment_length<length && comment[comment_length]; comment_length++)\r
234                                 ;\r
235                         if (comment_length)\r
236                         process_record(seap,\r
237                                 "ID-IP",        REC_FRAMESRC,   frame, -1,\r
238                                 "comment",      REC_PRINTABLE,  comment,                                        comment_length,\r
239                                 0);\r
240 \r
241                 }\r
242                 break;\r
243         default:\r
244                 FRAMERR(frame, "MSBROWSE: unknown command %d\n", cmd);\r
245         }\r
246 }\r
247 \r
248 void process_smb_mailslot(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned offset, struct SMBdgm *smb)\r
249 {\r
250         unsigned offset_max;\r
251         unsigned i;\r
252 \r
253         offset = smb->dgm.trans.setup_offset;\r
254 \r
255         if (smb->dgm.trans.setup_count != 3)\r
256                 FRAMERR(frame, "smb: corrupt\n");\r
257         smb->mailslot.opcode = get_word(frame, px, length, &offset);\r
258         smb->mailslot.priority = get_word(frame, px, length, &offset);\r
259         smb->mailslot.clss = get_word(frame, px, length, &offset);\r
260 \r
261         smb->mailslot.name = px+smb->dgm.trans.extra_offset;\r
262         for (i=0; i<length; i++)\r
263                 if (smb->mailslot.name[i] == '\0')\r
264                         break;\r
265         smb->mailslot.name_length = i;\r
266 \r
267         switch (smb->mailslot.opcode) {\r
268         case 1: /* write mail slot */\r
269                 offset = smb->dgm.trans.data_offset;\r
270                 offset_max = smb->dgm.trans.data_count;\r
271                 if (path_equals(smb->mailslot.name, smb->mailslot.name_length, "\\MAILSLOT\\BROWSE"))\r
272                         process_BROWSE(seap, frame, px, MIN(length, offset+offset_max), offset, smb);\r
273                 else\r
274                         FRAMERR(frame, "smb: unknown mailslot=%.*s\n", smb->mailslot.name_length, smb->mailslot.name);\r
275                 break;\r
276         default:\r
277                 FRAMERR(frame, "smb: corrupt\n");\r
278         }\r
279 \r
280 }\r
281 \r
282 void process_smb_dgm_transaction(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned offset, struct SMBdgm *smb)\r
283 {\r
284         unsigned reserved;\r
285 \r
286         smb->dgm.trans.word_count               = get_byte(frame, px, length, &offset);\r
287         smb->dgm.trans.total_parm_count = get_word(frame, px, length, &offset);\r
288         smb->dgm.trans.total_data_count = get_word(frame, px, length, &offset);\r
289         smb->dgm.trans.max_parm_count   = get_word(frame, px, length, &offset);\r
290         smb->dgm.trans.max_data_count   = get_word(frame, px, length, &offset);\r
291         smb->dgm.trans.max_setup_count  = get_byte(frame, px, length, &offset);\r
292         reserved                                                = get_byte(frame, px, length, &offset);\r
293         smb->dgm.trans.flags                    = get_word(frame, px, length, &offset);\r
294         smb->dgm.trans.timeout                  = get_dword(frame, px, length, &offset);\r
295         reserved                                                = get_word(frame, px, length, &offset);\r
296         smb->dgm.trans.parm_count               = get_word(frame, px, length, &offset);\r
297         smb->dgm.trans.parm_offset              = get_word(frame, px, length, &offset);\r
298         smb->dgm.trans.data_count               = get_word(frame, px, length, &offset);\r
299         smb->dgm.trans.data_offset              = get_word(frame, px, length, &offset);\r
300         smb->dgm.trans.setup_count              = get_byte(frame, px, length, &offset);\r
301         reserved                                                = get_byte(frame, px, length, &offset);\r
302         smb->dgm.trans.setup_offset             = offset;\r
303         offset += smb->dgm.trans.setup_count*2;\r
304         smb->dgm.trans.byte_count               = get_word(frame, px, length, &offset);\r
305         smb->dgm.trans.extra_offset                     = offset;\r
306         \r
307         if (offset+10 < length && memicmp(px+offset, "\\MAILSLOT\\", 10)==0)\r
308                 process_smb_mailslot(seap, frame, px, length, offset, smb);\r
309         else\r
310                 FRAMERR(frame, "smb: unknow transact command\n");\r
311 \r
312 }\r
313 \r
314 void process_smb_dgm(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length)\r
315 {\r
316         unsigned offset;\r
317         struct SMBdgm smb;\r
318         unsigned reserved;\r
319 \r
320         if (length < 28) {\r
321                 FRAMERR(frame, "smb: truncated\n");\r
322                 return;\r
323         }\r
324         offset = 4;\r
325 \r
326         smb.command                     = get_byte(frame, px, length, &offset);\r
327         smb.err                         = get_byte(frame, px, length, &offset);\r
328         reserved                        = get_byte(frame, px, length, &offset);\r
329         smb.errcode                     = get_word(frame, px, length, &offset);\r
330         smb.flags                       = get_byte(frame, px, length, &offset);\r
331         smb.flags2                      = get_word(frame, px, length, &offset);\r
332         smb.process_id_high = get_word(frame, px, length, &offset);\r
333         memcpy(smb.signature, px+offset, 8);\r
334         offset += 8;\r
335         reserved                        = get_word(frame, px, length, &offset);\r
336         smb.tree_id                     = get_word(frame, px, length, &offset);\r
337         smb.process_id          = get_word(frame, px, length, &offset);\r
338         smb.user_id                     = get_word(frame, px, length, &offset);\r
339         smb.multiplex_id        = get_word(frame, px, length, &offset);\r
340 \r
341         switch (smb.command) {\r
342         case 0x25: /* Transaction Request*/\r
343                 process_smb_dgm_transaction(seap, frame, px, length, offset, &smb);\r
344                 break;\r
345         default:\r
346                 FRAMERR(frame, "smb: unknow dgm command\n");\r
347         }\r
348 \r
349 }\r
350 \r