]> git.sesse.net Git - nbtscanner/blob - nmb.c
Import nbtscanner 0.1.4.
[nbtscanner] / nmb.c
1 /*
2  * nbtscanner -- a tool for scanning large networks for SMB servers.
3  *
4  * nmb.c: Most functions directly related to the NMB protocol.
5  *
6  * Large amounts of code adapted from Samba (http://www.samba.org/)
7  * Copyright (C) Andrew Tridgell 1994-1998, and others.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <malloc.h>
28
29 #include "nmb.h"
30 #include "packet.h"
31 #include "byteorder.h"
32 #include "util.h"
33
34 void build_nbt_packet(struct nmb_packet *nmb, int name_trn_id)
35 {
36         /* this could in theory be optimized, but I don't think it's worth it */
37         nmb->header.name_trn_id = name_trn_id;
38         nmb->header.opcode = 0;
39         nmb->header.response = 0;
40         nmb->header.nm_flags.bcast = 0;
41         nmb->header.nm_flags.recursion_available = 0;
42         nmb->header.nm_flags.recursion_desired = 0;
43         nmb->header.nm_flags.trunc = 0;
44         nmb->header.nm_flags.authoritative = 0;
45         nmb->header.rcode = 0;
46         nmb->header.qdcount = 1;
47         nmb->header.ancount = 0;
48         nmb->header.nscount = 0;
49         nmb->header.arcount = 0;
50
51         make_nmb_name(&(nmb->question.question_name), "*", 0x0, "");
52
53         nmb->question.question_type = 0x21;
54         nmb->question.question_class = 0x1;
55 }
56
57 int build_nmb(char *buf, struct nmb_packet *nmb)
58 {
59         unsigned char *ubuf = (unsigned char *)buf;
60         int offset=0;
61
62         /* put in the header */
63         RSSVAL(ubuf,offset, nmb->header.name_trn_id);
64         ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
65         if (nmb->header.response) ubuf[offset+2] |= (1<<7);
66         if (nmb->header.nm_flags.authoritative &&
67             nmb->header.response) ubuf[offset+2] |= 0x4;
68         if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2;
69         if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1;
70         if (nmb->header.nm_flags.recursion_available &&
71             nmb->header.response) ubuf[offset+3] |= 0x80;
72         if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10;
73         ubuf[offset+3] |= (nmb->header.rcode & 0xF);
74
75         RSSVAL(ubuf, offset+4, nmb->header.qdcount);
76         RSSVAL(ubuf, offset+6, nmb->header.ancount);
77         RSSVAL(ubuf, offset+8, nmb->header.nscount);
78         RSSVAL(ubuf, offset+10, nmb->header.arcount);
79
80         offset += 12;
81         if (nmb->header.qdcount) {
82                 /* XXXX this doesn't handle a qdcount of > 1 */
83                 offset += put_nmb_name((char *)ubuf, offset, &nmb->question.question_name);
84                 RSSVAL(ubuf,offset, nmb->question.question_type);
85                 RSSVAL(ubuf,offset+2, nmb->question.question_class);
86                 offset += 4;
87         }
88         return offset;
89 }
90
91 int parse_nmb(char *inbuf, int length, struct nmb_packet *nmb)
92 {
93         int nm_flags, offset;
94
95         memset((char *)nmb, 0, sizeof(*nmb));
96
97         if (length < 12) return(0);
98
99         /* parse the header */
100         nmb->header.name_trn_id = RSVAL(inbuf, 0);
101
102         nmb->header.opcode = (CVAL(inbuf, 2) >> 3) & 0xF;
103         nmb->header.response = ((CVAL(inbuf, 2) >> 7) & 1) ? 1 : 0;
104         nm_flags = ((CVAL(inbuf, 2) & 0x7) << 4) + (CVAL(inbuf, 3) >> 4);
105         nmb->header.nm_flags.bcast = (nm_flags & 1) ? 1 : 0;
106         nmb->header.nm_flags.recursion_available = (nm_flags & 8) ? 1 : 0;
107         nmb->header.nm_flags.recursion_desired = (nm_flags & 0x10) ? 1 : 0;
108         nmb->header.nm_flags.trunc = (nm_flags & 0x20) ? 1 : 0;
109         nmb->header.nm_flags.authoritative = (nm_flags & 0x40) ? 1 : 0;
110         nmb->header.rcode = CVAL(inbuf, 3) & 0xF;
111         nmb->header.qdcount = RSVAL(inbuf, 4);
112         nmb->header.ancount = RSVAL(inbuf, 6);
113         nmb->header.nscount = RSVAL(inbuf, 8);
114         nmb->header.arcount = RSVAL(inbuf, 10);
115
116         if (nmb->header.qdcount) {
117                 offset = parse_nmb_name(inbuf, 12, length, &nmb->question.question_name);
118                 if (!offset) return 0;
119
120                 if (length - (12+offset) < 4) return 0;
121                 nmb->question.question_type = RSVAL(inbuf, 12+offset);
122                 nmb->question.question_class = RSVAL(inbuf, 12+offset+2);
123
124                 offset += 12+4;
125         } else {
126                 offset = 12;
127         }
128
129         /* and any resource records */
130         if (nmb->header.ancount &&
131                 !parse_alloc_res_rec(inbuf, &offset, length, &nmb->answers,
132                                      nmb->header.ancount)) {
133                 return 0;
134         }
135
136         if (nmb->header.nscount &&
137                 !parse_alloc_res_rec(inbuf, &offset, length, &nmb->nsrecs,
138                                      nmb->header.nscount)) {
139                 return 0;
140         }
141
142         if (nmb->header.arcount &&
143                 !parse_alloc_res_rec(inbuf, &offset, length, &nmb->additional,
144                                      nmb->header.arcount)) {
145                 return 0;
146         }
147
148         return 1;
149 }
150
151 void make_nmb_name(struct nmb_name *n, const char *name, int type, const char *this_scope)
152 {
153         memset((char *)n, 0, sizeof(struct nmb_name));
154         strncpy(n->name, name, 15);
155         strupper(n->name);
156         n->name_type = (unsigned int)type & 0xFF;
157         strncpy(n->scope, this_scope, 63);
158         strupper(n->scope);
159 }
160
161 int parse_nmb_name(char *inbuf, int offset, int length, struct nmb_name *name)
162 {
163         int m, n = 0;
164         unsigned char *ubuf = (unsigned char *)inbuf;
165         int ret = 0;
166         int got_pointer = 0;
167         int loop_count = 0;
168
169         if (length - offset < 2)
170                 return 0;
171
172         /* handle initial name pointers */
173         if (!handle_name_ptrs(ubuf, &offset, length, &got_pointer, &ret))
174                 return 0;
175
176         m = ubuf[offset];
177
178         if (!m)
179                 return 0;
180         if ((m & 0xC0) || offset+m+2 > length)
181                 return 0;
182
183         memset((char *)name, 0, sizeof(*name));
184
185         /* the "compressed" part */
186         if (!got_pointer)
187                 ret += m + 2;
188         offset++;
189
190         while (m > 0) {
191                 unsigned char c1,c2;
192                 c1 = ubuf[offset++]-'A';
193                 c2 = ubuf[offset++]-'A';
194                 if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
195                         return 0;
196                 name->name[n++] = (c1<<4) | c2;
197                 m -= 2;
198         }
199         name->name[n] = 0;
200
201         if (n==16) {
202                 /* parse out the name type,
203                    its always in the 16th byte of the name */
204                 name->name_type = ((unsigned char)name->name[15]) & 0xff;
205
206                 /* remove trailing spaces */
207                 name->name[15] = 0;
208                 n = 14;
209                 while (n && name->name[n]==' ')
210                         name->name[n--] = 0;
211         }
212
213         /* now the domain parts (if any) */
214         n = 0;
215         while (ubuf[offset]) {
216                 /* we can have pointers within the domain part as well */
217                 if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
218                         return 0;
219
220                 m = ubuf[offset];
221                 /*
222                  * Don't allow null domain parts.
223                  */
224                 if (!m)
225                         return 0;
226                 if (!got_pointer)
227                         ret += m+1;
228                 if (n)
229                         name->scope[n++] = '.';
230                 if (m + 2 + offset > length || n + m + 1 > sizeof(name->scope))
231                         return 0;
232                 offset++;
233                 while (m--)
234                         name->scope[n++] = (char)ubuf[offset++];
235
236                 /*
237                  * Watch for malicious loops.
238                  */
239                 if (loop_count++ == 10)
240                         return 0;
241         }
242         name->scope[n++] = 0;
243
244         return ret;
245 }
246
247 int put_nmb_name(char *buf, int offset, struct nmb_name *name)
248 {
249         int ret,m;
250         char buf1[128];
251         char *p;
252
253         if (strcmp(name->name,"*") == 0) {
254                 /* special case for wildcard name */
255                 memset(buf1,'\0',20);
256                 buf1[0] = '*';
257                 buf1[15] = name->name_type;
258         } else {
259                 snprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type);
260         }
261
262         buf[offset] = 0x20;
263         ret = 34;
264
265         for (m=0; m<16; m++) {
266                 buf[offset + 1 + 2*m] = 'A' + ((buf1[m] >> 4) & 0xF);
267                 buf[offset + 2 + 2*m] = 'A' + ( buf1[m]       & 0xF);
268         }
269         offset += 33;
270
271         buf[offset] = 0;
272
273         if (name->scope[0]) {
274                 /* XXXX this scope handling needs testing */
275                 ret += strlen(name->scope) + 1;
276                 strcpy(&buf[offset + 1], name->scope);
277
278                 p = &buf[offset + 1];
279                 while ((p = strchr(p, '.'))) {
280                         buf[offset] = PTR_DIFF(p, &buf[offset]);
281                         offset += buf[offset];
282                         p = &buf[offset+1];
283                 }
284                 buf[offset] = strlen(&buf[offset+1]);
285         }
286
287         return ret;
288 }
289
290 int handle_name_ptrs(unsigned char *ubuf, int *offset, int length,
291                              int *got_pointer, int *ret)
292 {
293         int loop_count=0;
294
295         while ((ubuf[*offset] & 0xC0) == 0xC0) {
296                 if (!*got_pointer) (*ret) += 2;
297                 (*got_pointer) = 1;
298                 (*offset) = ((ubuf[*offset] & ~0xC0) << 8) | ubuf[(*offset)+1];
299                 if (loop_count++ == 10 || (*offset) < 0 || (*offset) > (length-2)) {
300                         return 0;
301                 }
302         }
303         return 1;
304 }
305
306 int parse_alloc_res_rec(char *inbuf, int *offset, int length,
307                         struct res_rec **recs, int count)
308 {
309         int i;
310         *recs = (struct res_rec *)malloc(sizeof(**recs) * count);
311         if (!*recs) return 0;
312
313         memset((char *)*recs, 0, sizeof(**recs) * count);
314
315         for (i=0; i<count; i++) {
316                 int l = parse_nmb_name(inbuf, *offset, length, &(*recs)[i].rr_name);
317                 (*offset) += l;
318                 if (!l || (*offset)+10 > length) {
319                         free(*recs);
320                         *recs = NULL;
321                         return 0;
322                 }
323                 (*recs)[i].rr_type = RSVAL(inbuf, (*offset));
324                 (*recs)[i].rr_class = RSVAL(inbuf, (*offset)+2);
325                 (*recs)[i].ttl = RIVAL(inbuf, (*offset)+4);
326                 (*recs)[i].rdlength = RSVAL(inbuf, (*offset)+8);
327                 (*offset) += 10;
328                 if ((*recs)[i].rdlength > sizeof((*recs)[i].rdata) ||
329                     (*offset)+(*recs)[i].rdlength > length) {
330                         free(*recs);
331                         *recs = NULL;
332                         return 0;
333                 }
334                 memcpy((*recs)[i].rdata, inbuf+(*offset), (*recs)[i].rdlength);
335                 (*offset) += (*recs)[i].rdlength;
336         }
337         return 0;
338 }
339
340 void free_nmb_packet(struct nmb_packet *nmb)
341 {
342         if (nmb->answers) {
343                 free(nmb->answers);
344                 nmb->answers = NULL;
345         }
346         if (nmb->nsrecs) {
347                 free(nmb->nsrecs);
348                 nmb->nsrecs = NULL;
349         }
350         if (nmb->additional) {
351                 free(nmb->additional);
352                 nmb->additional = NULL;
353         }
354         free(nmb);
355 }
356