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.
30 #include "byteorder.h"
33 void build_nbt_packet(struct nmb_packet *nmb, int name_trn_id)
35 nmb->header.name_trn_id = name_trn_id;
36 nmb->header.opcode = 0;
37 nmb->header.response = 0;
38 nmb->header.nm_flags.bcast = 0;
39 nmb->header.nm_flags.recursion_available = 0;
40 nmb->header.nm_flags.recursion_desired = 0;
41 nmb->header.nm_flags.trunc = 0;
42 nmb->header.nm_flags.authoritative = 0;
43 nmb->header.rcode = 0;
44 nmb->header.qdcount = 1;
45 nmb->header.ancount = 0;
46 nmb->header.nscount = 0;
47 nmb->header.arcount = 0;
49 make_nmb_name(&(nmb->question.question_name), "*", 0x0, "");
51 nmb->question.question_type = 0x21;
52 nmb->question.question_class = 0x1;
55 int build_nmb(char *buf, struct nmb_packet *nmb)
57 unsigned char *ubuf = (unsigned char *)buf;
60 /* put in the header */
61 RSSVAL(ubuf,offset, nmb->header.name_trn_id);
62 ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
63 if (nmb->header.response) ubuf[offset+2] |= (1<<7);
64 if (nmb->header.nm_flags.authoritative &&
65 nmb->header.response) ubuf[offset+2] |= 0x4;
66 if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2;
67 if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1;
68 if (nmb->header.nm_flags.recursion_available &&
69 nmb->header.response) ubuf[offset+3] |= 0x80;
70 if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10;
71 ubuf[offset+3] |= (nmb->header.rcode & 0xF);
73 RSSVAL(ubuf, offset+4, nmb->header.qdcount);
74 RSSVAL(ubuf, offset+6, nmb->header.ancount);
75 RSSVAL(ubuf, offset+8, nmb->header.nscount);
76 RSSVAL(ubuf, offset+10, nmb->header.arcount);
79 if (nmb->header.qdcount) {
80 /* XXXX this doesn't handle a qdcount of > 1 */
81 offset += put_nmb_name((char *)ubuf, offset, &nmb->question.question_name);
82 RSSVAL(ubuf,offset, nmb->question.question_type);
83 RSSVAL(ubuf,offset+2, nmb->question.question_class);
89 int parse_nmb(char *inbuf, int length, struct nmb_packet *nmb)
93 memset((char *)nmb, 0, sizeof(*nmb));
95 if (length < 12) return(0);
97 /* parse the header */
98 nmb->header.name_trn_id = RSVAL(inbuf, 0);
100 nmb->header.opcode = (CVAL(inbuf, 2) >> 3) & 0xF;
101 nmb->header.response = ((CVAL(inbuf, 2) >> 7) & 1) ? 1 : 0;
102 nm_flags = ((CVAL(inbuf, 2) & 0x7) << 4) + (CVAL(inbuf, 3) >> 4);
103 nmb->header.nm_flags.bcast = (nm_flags & 1) ? 1 : 0;
104 nmb->header.nm_flags.recursion_available = (nm_flags & 8) ? 1 : 0;
105 nmb->header.nm_flags.recursion_desired = (nm_flags & 0x10) ? 1 : 0;
106 nmb->header.nm_flags.trunc = (nm_flags & 0x20) ? 1 : 0;
107 nmb->header.nm_flags.authoritative = (nm_flags & 0x40) ? 1 : 0;
108 nmb->header.rcode = CVAL(inbuf, 3) & 0xF;
109 nmb->header.qdcount = RSVAL(inbuf, 4);
110 nmb->header.ancount = RSVAL(inbuf, 6);
111 nmb->header.nscount = RSVAL(inbuf, 8);
112 nmb->header.arcount = RSVAL(inbuf, 10);
114 if (nmb->header.qdcount) {
115 offset = parse_nmb_name(inbuf, 12, length, &nmb->question.question_name);
116 if (!offset) return 0;
118 if (length - (12+offset) < 4) return 0;
119 nmb->question.question_type = RSVAL(inbuf, 12+offset);
120 nmb->question.question_class = RSVAL(inbuf, 12+offset+2);
127 /* and any resource records */
128 if (nmb->header.ancount &&
129 !parse_alloc_res_rec(inbuf, &offset, length, &nmb->answers,
130 nmb->header.ancount)) {
134 if (nmb->header.nscount &&
135 !parse_alloc_res_rec(inbuf, &offset, length, &nmb->nsrecs,
136 nmb->header.nscount)) {
140 if (nmb->header.arcount &&
141 !parse_alloc_res_rec(inbuf, &offset, length, &nmb->additional,
142 nmb->header.arcount)) {
149 void make_nmb_name(struct nmb_name *n, const char *name, int type, const char *this_scope)
151 memset((char *)n, 0, sizeof(struct nmb_name));
152 strncpy(n->name, name, 15);
154 n->name_type = (unsigned int)type & 0xFF;
155 strncpy(n->scope, this_scope, 63);
159 int parse_nmb_name(char *inbuf, int offset, int length, struct nmb_name *name)
162 unsigned char *ubuf = (unsigned char *)inbuf;
167 if (length - offset < 2)
170 /* handle initial name pointers */
171 if (!handle_name_ptrs(ubuf, &offset, length, &got_pointer, &ret))
178 if ((m & 0xC0) || offset+m+2 > length)
181 memset((char *)name, 0, sizeof(*name));
183 /* the "compressed" part */
190 c1 = ubuf[offset++]-'A';
191 c2 = ubuf[offset++]-'A';
192 if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
194 name->name[n++] = (c1<<4) | c2;
200 /* parse out the name type,
201 its always in the 16th byte of the name */
202 name->name_type = ((unsigned char)name->name[15]) & 0xff;
204 /* remove trailing spaces */
207 while (n && name->name[n]==' ')
211 /* now the domain parts (if any) */
213 while (ubuf[offset]) {
214 /* we can have pointers within the domain part as well */
215 if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
220 * Don't allow null domain parts.
227 name->scope[n++] = '.';
228 if (m + 2 + offset > length || n + m + 1 > sizeof(name->scope))
232 name->scope[n++] = (char)ubuf[offset++];
235 * Watch for malicious loops.
237 if (loop_count++ == 10)
240 name->scope[n++] = 0;
245 int put_nmb_name(char *buf, int offset, struct nmb_name *name)
251 if (strcmp(name->name,"*") == 0) {
252 /* special case for wildcard name */
253 memset(buf1,'\0',20);
255 buf1[15] = name->name_type;
257 snprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type);
263 for (m=0; m<16; m++) {
264 buf[offset + 1 + 2*m] = 'A' + ((buf1[m] >> 4) & 0xF);
265 buf[offset + 2 + 2*m] = 'A' + ( buf1[m] & 0xF);
271 if (name->scope[0]) {
272 /* XXXX this scope handling needs testing */
273 ret += strlen(name->scope) + 1;
274 strcpy(&buf[offset + 1], name->scope);
276 p = &buf[offset + 1];
277 while ((p = strchr(p, '.'))) {
278 buf[offset] = PTR_DIFF(p, &buf[offset]);
279 offset += buf[offset];
282 buf[offset] = strlen(&buf[offset+1]);
288 int handle_name_ptrs(unsigned char *ubuf, int *offset, int length,
289 int *got_pointer, int *ret)
293 while ((ubuf[*offset] & 0xC0) == 0xC0) {
294 if (!*got_pointer) (*ret) += 2;
296 (*offset) = ((ubuf[*offset] & ~0xC0) << 8) | ubuf[(*offset)+1];
297 if (loop_count++ == 10 || (*offset) < 0 || (*offset) > (length-2)) {
304 int parse_alloc_res_rec(char *inbuf, int *offset, int length,
305 struct res_rec **recs, int count)
308 *recs = (struct res_rec *)malloc(sizeof(**recs) * count);
309 if (!*recs) return 0;
311 memset((char *)*recs, 0, sizeof(**recs) * count);
313 for (i=0; i<count; i++) {
314 int l = parse_nmb_name(inbuf, *offset, length, &(*recs)[i].rr_name);
316 if (!l || (*offset)+10 > length) {
321 (*recs)[i].rr_type = RSVAL(inbuf, (*offset));
322 (*recs)[i].rr_class = RSVAL(inbuf, (*offset)+2);
323 (*recs)[i].ttl = RIVAL(inbuf, (*offset)+4);
324 (*recs)[i].rdlength = RSVAL(inbuf, (*offset)+8);
326 if ((*recs)[i].rdlength > sizeof((*recs)[i].rdata) ||
327 (*offset)+(*recs)[i].rdlength > length) {
332 memcpy((*recs)[i].rdata, inbuf+(*offset), (*recs)[i].rdlength);
333 (*offset) += (*recs)[i].rdlength;
338 void free_nmb_packet(struct nmb_packet *nmb)
348 if (nmb->additional) {
349 free(nmb->additional);
350 nmb->additional = NULL;