2 * nbtscanner -- a tool for scanning large networks for SMB servers.
4 * nmb.c: Most functions directly related to the NMB protocol.
6 * Large amounts of code adapted from Samba (http://www.samba.org/)
7 * Copyright (C) Andrew Tridgell 1994-1998, and others.
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.
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.
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.
31 #include "byteorder.h"
34 void build_nbt_packet(struct nmb_packet *nmb, int name_trn_id)
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;
51 make_nmb_name(&(nmb->question.question_name), "*", 0x0, "");
53 nmb->question.question_type = 0x21;
54 nmb->question.question_class = 0x1;
57 int build_nmb(char *buf, struct nmb_packet *nmb)
59 unsigned char *ubuf = (unsigned char *)buf;
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);
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);
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);
91 int parse_nmb(char *inbuf, int length, struct nmb_packet *nmb)
95 memset((char *)nmb, 0, sizeof(*nmb));
97 if (length < 12) return(0);
99 /* parse the header */
100 nmb->header.name_trn_id = RSVAL(inbuf, 0);
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);
116 if (nmb->header.qdcount) {
117 offset = parse_nmb_name(inbuf, 12, length, &nmb->question.question_name);
118 if (!offset) return 0;
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);
129 /* and any resource records */
130 if (nmb->header.ancount &&
131 !parse_alloc_res_rec(inbuf, &offset, length, &nmb->answers,
132 nmb->header.ancount)) {
136 if (nmb->header.nscount &&
137 !parse_alloc_res_rec(inbuf, &offset, length, &nmb->nsrecs,
138 nmb->header.nscount)) {
142 if (nmb->header.arcount &&
143 !parse_alloc_res_rec(inbuf, &offset, length, &nmb->additional,
144 nmb->header.arcount)) {
151 void make_nmb_name(struct nmb_name *n, const char *name, int type, const char *this_scope)
153 memset((char *)n, 0, sizeof(struct nmb_name));
154 strncpy(n->name, name, 15);
156 n->name_type = (unsigned int)type & 0xFF;
157 strncpy(n->scope, this_scope, 63);
161 int parse_nmb_name(char *inbuf, int offset, int length, struct nmb_name *name)
164 unsigned char *ubuf = (unsigned char *)inbuf;
169 if (length - offset < 2)
172 /* handle initial name pointers */
173 if (!handle_name_ptrs(ubuf, &offset, length, &got_pointer, &ret))
180 if ((m & 0xC0) || offset+m+2 > length)
183 memset((char *)name, 0, sizeof(*name));
185 /* the "compressed" part */
192 c1 = ubuf[offset++]-'A';
193 c2 = ubuf[offset++]-'A';
194 if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
196 name->name[n++] = (c1<<4) | c2;
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;
206 /* remove trailing spaces */
209 while (n && name->name[n]==' ')
213 /* now the domain parts (if any) */
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))
222 * Don't allow null domain parts.
229 name->scope[n++] = '.';
230 if (m + 2 + offset > length || n + m + 1 > sizeof(name->scope))
234 name->scope[n++] = (char)ubuf[offset++];
237 * Watch for malicious loops.
239 if (loop_count++ == 10)
242 name->scope[n++] = 0;
247 int put_nmb_name(char *buf, int offset, struct nmb_name *name)
253 if (strcmp(name->name,"*") == 0) {
254 /* special case for wildcard name */
255 memset(buf1,'\0',20);
257 buf1[15] = name->name_type;
259 snprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type);
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);
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);
278 p = &buf[offset + 1];
279 while ((p = strchr(p, '.'))) {
280 buf[offset] = PTR_DIFF(p, &buf[offset]);
281 offset += buf[offset];
284 buf[offset] = strlen(&buf[offset+1]);
290 int handle_name_ptrs(unsigned char *ubuf, int *offset, int length,
291 int *got_pointer, int *ret)
295 while ((ubuf[*offset] & 0xC0) == 0xC0) {
296 if (!*got_pointer) (*ret) += 2;
298 (*offset) = ((ubuf[*offset] & ~0xC0) << 8) | ubuf[(*offset)+1];
299 if (loop_count++ == 10 || (*offset) < 0 || (*offset) > (length-2)) {
306 int parse_alloc_res_rec(char *inbuf, int *offset, int length,
307 struct res_rec **recs, int count)
310 *recs = (struct res_rec *)malloc(sizeof(**recs) * count);
311 if (!*recs) return 0;
313 memset((char *)*recs, 0, sizeof(**recs) * count);
315 for (i=0; i<count; i++) {
316 int l = parse_nmb_name(inbuf, *offset, length, &(*recs)[i].rr_name);
318 if (!l || (*offset)+10 > length) {
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);
328 if ((*recs)[i].rdlength > sizeof((*recs)[i].rdata) ||
329 (*offset)+(*recs)[i].rdlength > length) {
334 memcpy((*recs)[i].rdata, inbuf+(*offset), (*recs)[i].rdlength);
335 (*offset) += (*recs)[i].rdlength;
340 void free_nmb_packet(struct nmb_packet *nmb)
350 if (nmb->additional) {
351 free(nmb->additional);
352 nmb->additional = NULL;