/src/samba/source3/libsmb/nmblib.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | NBT netbios library routines |
4 | | Copyright (C) Andrew Tridgell 1994-1998 |
5 | | Copyright (C) Jeremy Allison 2007 |
6 | | |
7 | | This program is free software; you can redistribute it and/or modify |
8 | | it under the terms of the GNU General Public License as published by |
9 | | the Free Software Foundation; either version 3 of the License, or |
10 | | (at your option) any later version. |
11 | | |
12 | | This program is distributed in the hope that it will be useful, |
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | GNU General Public License for more details. |
16 | | |
17 | | You should have received a copy of the GNU General Public License |
18 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | | |
20 | | */ |
21 | | |
22 | | #include "includes.h" |
23 | | #include "libsmb/nmblib.h" |
24 | | #include "lib/util/string_wrappers.h" |
25 | | |
26 | | const char *global_nmbd_socket_dir(void) |
27 | 0 | { |
28 | 0 | return lp_parm_const_string(-1, "nmbd", "socket dir", |
29 | 0 | get_dyn_NMBDSOCKETDIR()); |
30 | 0 | } |
31 | | |
32 | | static const struct opcode_names { |
33 | | const char *nmb_opcode_name; |
34 | | int opcode; |
35 | | } nmb_header_opcode_names[] = { |
36 | | {"Query", 0 }, |
37 | | {"Registration", 5 }, |
38 | | {"Release", 6 }, |
39 | | {"WACK", 7 }, |
40 | | {"Refresh", 8 }, |
41 | | {"Refresh(altcode)", 9 }, |
42 | | {"Multi-homed Registration", 15 }, |
43 | | {0, -1 } |
44 | | }; |
45 | | |
46 | | /**************************************************************************** |
47 | | Lookup a nmb opcode name. |
48 | | ****************************************************************************/ |
49 | | |
50 | | static const char *lookup_opcode_name( int opcode ) |
51 | 0 | { |
52 | 0 | const struct opcode_names *op_namep; |
53 | 0 | int i; |
54 | |
|
55 | 0 | for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) { |
56 | 0 | op_namep = &nmb_header_opcode_names[i]; |
57 | 0 | if(opcode == op_namep->opcode) |
58 | 0 | return op_namep->nmb_opcode_name; |
59 | 0 | } |
60 | 0 | return "<unknown opcode>"; |
61 | 0 | } |
62 | | |
63 | | /**************************************************************************** |
64 | | Print out a res_rec structure. |
65 | | ****************************************************************************/ |
66 | | |
67 | | static void debug_nmb_res_rec(struct res_rec *res, const char *hdr) |
68 | 0 | { |
69 | 0 | int i, j; |
70 | |
|
71 | 0 | DEBUGADD( 4, ( " %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n", |
72 | 0 | hdr, |
73 | 0 | nmb_namestr(&res->rr_name), |
74 | 0 | res->rr_type, |
75 | 0 | res->rr_class, |
76 | 0 | res->ttl ) ); |
77 | |
|
78 | 0 | if (res->rdlength == 0) { |
79 | 0 | return; |
80 | 0 | } |
81 | | |
82 | 0 | for (i = 0; i < res->rdlength; i+= MAX_NETBIOSNAME_LEN) { |
83 | 0 | DEBUGADD(4, (" %s %3x char ", hdr, i)); |
84 | |
|
85 | 0 | for (j = 0; j < MAX_NETBIOSNAME_LEN; j++) { |
86 | 0 | unsigned char x = res->rdata[i+j]; |
87 | 0 | if (x < 32 || x > 127) |
88 | 0 | x = '.'; |
89 | |
|
90 | 0 | if (i+j >= res->rdlength) |
91 | 0 | break; |
92 | 0 | DEBUGADD(4, ("%c", x)); |
93 | 0 | } |
94 | |
|
95 | 0 | DEBUGADD(4, (" hex ")); |
96 | |
|
97 | 0 | for (j = 0; j < MAX_NETBIOSNAME_LEN; j++) { |
98 | 0 | if (i+j >= res->rdlength) |
99 | 0 | break; |
100 | 0 | DEBUGADD(4, ("%02X", (unsigned char)res->rdata[i+j])); |
101 | 0 | } |
102 | |
|
103 | 0 | DEBUGADD(4, ("\n")); |
104 | 0 | } |
105 | 0 | } |
106 | | |
107 | | /**************************************************************************** |
108 | | Process a nmb packet. |
109 | | ****************************************************************************/ |
110 | | |
111 | | void debug_nmb_packet(struct packet_struct *p) |
112 | 0 | { |
113 | 0 | struct nmb_packet *nmb = &p->packet.nmb; |
114 | |
|
115 | 0 | if( DEBUGLVL( 4 ) ) { |
116 | 0 | dbgtext( "nmb packet from %s(%d) header: id=%d " |
117 | 0 | "opcode=%s(%d) response=%s\n", |
118 | 0 | inet_ntoa(p->ip), p->port, |
119 | 0 | nmb->header.name_trn_id, |
120 | 0 | lookup_opcode_name(nmb->header.opcode), |
121 | 0 | nmb->header.opcode, |
122 | 0 | BOOLSTR(nmb->header.response) ); |
123 | 0 | dbgtext( " header: flags: bcast=%s rec_avail=%s " |
124 | 0 | "rec_des=%s trunc=%s auth=%s\n", |
125 | 0 | BOOLSTR(nmb->header.nm_flags.bcast), |
126 | 0 | BOOLSTR(nmb->header.nm_flags.recursion_available), |
127 | 0 | BOOLSTR(nmb->header.nm_flags.recursion_desired), |
128 | 0 | BOOLSTR(nmb->header.nm_flags.trunc), |
129 | 0 | BOOLSTR(nmb->header.nm_flags.authoritative) ); |
130 | 0 | dbgtext( " header: rcode=%d qdcount=%d ancount=%d " |
131 | 0 | "nscount=%d arcount=%d\n", |
132 | 0 | nmb->header.rcode, |
133 | 0 | nmb->header.qdcount, |
134 | 0 | nmb->header.ancount, |
135 | 0 | nmb->header.nscount, |
136 | 0 | nmb->header.arcount ); |
137 | 0 | } |
138 | |
|
139 | 0 | if (nmb->header.qdcount) { |
140 | 0 | DEBUGADD( 4, ( " question: q_name=%s q_type=%d q_class=%d\n", |
141 | 0 | nmb_namestr(&nmb->question.question_name), |
142 | 0 | nmb->question.question_type, |
143 | 0 | nmb->question.question_class) ); |
144 | 0 | } |
145 | |
|
146 | 0 | if (nmb->answers && nmb->header.ancount) { |
147 | 0 | debug_nmb_res_rec(nmb->answers,"answers"); |
148 | 0 | } |
149 | 0 | if (nmb->nsrecs && nmb->header.nscount) { |
150 | 0 | debug_nmb_res_rec(nmb->nsrecs,"nsrecs"); |
151 | 0 | } |
152 | 0 | if (nmb->additional && nmb->header.arcount) { |
153 | 0 | debug_nmb_res_rec(nmb->additional,"additional"); |
154 | 0 | } |
155 | 0 | } |
156 | | |
157 | | /******************************************************************* |
158 | | Handle "compressed" name pointers. |
159 | | ******************************************************************/ |
160 | | |
161 | | static bool handle_name_ptrs(unsigned char *ubuf,int *offset,int length, |
162 | | bool *got_pointer,int *ret) |
163 | 425k | { |
164 | 425k | int loop_count=0; |
165 | | |
166 | 518k | while ((ubuf[*offset] & 0xC0) == 0xC0) { |
167 | 93.6k | if (!*got_pointer) |
168 | 89.9k | (*ret) += 2; |
169 | 93.6k | (*got_pointer)=True; |
170 | 93.6k | if (*offset > length - 2) { |
171 | 9 | return False; |
172 | 9 | } |
173 | 93.6k | (*offset) = ((ubuf[*offset] & ~0xC0)<<8) | ubuf[(*offset)+1]; |
174 | 93.6k | if (loop_count++ == 10 || |
175 | 93.6k | (*offset) < 0 || (*offset)>(length-2)) { |
176 | 23 | return False; |
177 | 23 | } |
178 | 93.6k | } |
179 | 425k | return True; |
180 | 425k | } |
181 | | |
182 | | /******************************************************************* |
183 | | Parse a nmb name from "compressed" format to something readable |
184 | | return the space taken by the name, or 0 if the name is invalid |
185 | | ******************************************************************/ |
186 | | |
187 | | static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name) |
188 | 355k | { |
189 | 355k | size_t m,n=0; |
190 | 355k | unsigned char *ubuf = (unsigned char *)inbuf; |
191 | 355k | int ret = 0; |
192 | 355k | bool got_pointer=False; |
193 | 355k | size_t loop_count=0; |
194 | 355k | int offset = ofs; |
195 | | |
196 | 355k | if (length - offset < 2) |
197 | 92 | return(0); |
198 | | |
199 | | /* handle initial name pointers */ |
200 | 355k | if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) |
201 | 15 | return(0); |
202 | | |
203 | 355k | m = ubuf[offset]; |
204 | | |
205 | | /* m must be 32 to exactly fill in the 16 bytes of the netbios name */ |
206 | 355k | if (m != 32) { |
207 | 52 | return 0; |
208 | 52 | } |
209 | | /* Cannot go past length. */ |
210 | 355k | if (offset+m+2 > length) { |
211 | 14 | return 0; |
212 | 14 | } |
213 | | |
214 | 355k | memset((char *)name,'\0',sizeof(*name)); |
215 | | |
216 | | /* the "compressed" part */ |
217 | 355k | if (!got_pointer) |
218 | 266k | ret += m + 2; |
219 | 355k | offset++; |
220 | 6.03M | while (m > 0) { |
221 | 5.68M | unsigned char c1,c2; |
222 | 5.68M | c1 = ubuf[offset++]-'A'; |
223 | 5.68M | c2 = ubuf[offset++]-'A'; |
224 | 5.68M | if ((c1 & 0xF0) || (c2 & 0xF0)) { |
225 | 30 | return(0); |
226 | 30 | } |
227 | 5.68M | if (n >= sizeof(name->name)) { |
228 | 0 | return 0; |
229 | 0 | } |
230 | 5.68M | name->name[n++] = (c1<<4) | c2; |
231 | 5.68M | m -= 2; |
232 | 5.68M | } |
233 | | /* |
234 | | * RFC1002: For a valid NetBIOS name, exiting from the above, |
235 | | * n *must* be MAX_NETBIOSNAME_LEN (16). |
236 | | */ |
237 | 355k | if (n != MAX_NETBIOSNAME_LEN) { |
238 | 0 | return 0; |
239 | 0 | } |
240 | | |
241 | | /* parse out the name type, its always |
242 | | * in the 16th byte of the name */ |
243 | 355k | name->name_type = ((unsigned char)name->name[15]) & 0xff; |
244 | | |
245 | | /* remove trailing spaces */ |
246 | 355k | name->name[15] = 0; |
247 | 355k | n = 14; |
248 | 4.67M | while (n && name->name[n]==' ') |
249 | 4.32M | name->name[n--] = 0; |
250 | | |
251 | | /* now the domain parts (if any) */ |
252 | 355k | n = 0; |
253 | 425k | while (ubuf[offset]) { |
254 | | /* we can have pointers within the domain part as well */ |
255 | 69.8k | if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) |
256 | 17 | return(0); |
257 | | |
258 | 69.8k | m = ubuf[offset]; |
259 | | /* |
260 | | * Don't allow null domain parts. |
261 | | */ |
262 | 69.8k | if (!m) |
263 | 2 | return(0); |
264 | 69.8k | if (!got_pointer) |
265 | 1.21k | ret += m+1; |
266 | 69.8k | if (n) |
267 | 23.1k | name->scope[n++] = '.'; |
268 | 69.8k | if (m+2+offset>length || n+m+1>sizeof(name->scope)) |
269 | 51 | return(0); |
270 | 69.7k | offset++; |
271 | 1.64M | while (m--) |
272 | 1.57M | name->scope[n++] = (char)ubuf[offset++]; |
273 | | |
274 | | /* |
275 | | * Watch for malicious loops. |
276 | | */ |
277 | 69.7k | if (loop_count++ == 10) |
278 | 3 | return 0; |
279 | 69.7k | } |
280 | 355k | name->scope[n++] = 0; |
281 | | |
282 | 355k | return(ret); |
283 | 355k | } |
284 | | |
285 | | /**************************************************************************** |
286 | | Put a netbios name, padding(s) and a name type into a 16 character buffer. |
287 | | name is already in DOS charset. |
288 | | [15 bytes name + padding][1 byte name type]. |
289 | | ****************************************************************************/ |
290 | | |
291 | | void put_name(char *dest, const char *name, int pad, unsigned int name_type) |
292 | 485k | { |
293 | 485k | size_t len = strlen(name); |
294 | | |
295 | 485k | memcpy(dest, name, (len < MAX_NETBIOSNAME_LEN) ? |
296 | 485k | len : MAX_NETBIOSNAME_LEN - 1); |
297 | 485k | if (len < MAX_NETBIOSNAME_LEN - 1) { |
298 | 479k | memset(dest + len, pad, MAX_NETBIOSNAME_LEN - 1 - len); |
299 | 479k | } |
300 | 485k | dest[MAX_NETBIOSNAME_LEN - 1] = name_type; |
301 | 485k | } |
302 | | |
303 | | /******************************************************************* |
304 | | Put a compressed nmb name into a buffer. Return the length of the |
305 | | compressed name. |
306 | | |
307 | | Compressed names are really weird. The "compression" doubles the |
308 | | size. The idea is that it also means that compressed names conform |
309 | | to the domain name system. See RFC1002. |
310 | | |
311 | | If buf == NULL this is a length calculation. |
312 | | ******************************************************************/ |
313 | | |
314 | | static int put_nmb_name(char *buf, size_t buflen, int offset,struct nmb_name *name) |
315 | 485k | { |
316 | 485k | int ret,m; |
317 | 485k | nstring buf1; |
318 | 485k | char *p; |
319 | | |
320 | 485k | if (strcmp(name->name,"*") == 0) { |
321 | | /* special case for wildcard name */ |
322 | 4.40k | put_name(buf1, "*", '\0', name->name_type); |
323 | 481k | } else { |
324 | 481k | put_name(buf1, name->name, ' ', name->name_type); |
325 | 481k | } |
326 | | |
327 | 485k | if (buf) { |
328 | 242k | if (offset >= buflen) { |
329 | 0 | return 0; |
330 | 0 | } |
331 | 242k | buf[offset] = 0x20; |
332 | 242k | } |
333 | | |
334 | 485k | ret = 34; |
335 | | |
336 | 8.25M | for (m=0;m<MAX_NETBIOSNAME_LEN;m++) { |
337 | 7.76M | if (buf) { |
338 | 3.88M | if (offset+2+2*m >= buflen) { |
339 | 0 | return 0; |
340 | 0 | } |
341 | 3.88M | buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF); |
342 | 3.88M | buf[offset+2+2*m] = 'A' + (buf1[m]&0xF); |
343 | 3.88M | } |
344 | 7.76M | } |
345 | 485k | offset += 33; |
346 | | |
347 | 485k | if (buf) { |
348 | 242k | if (offset >= buflen) { |
349 | 0 | return 0; |
350 | 0 | } |
351 | 242k | buf[offset] = 0; |
352 | 242k | } |
353 | | |
354 | 485k | if (name->scope[0]) { |
355 | | /* XXXX this scope handling needs testing */ |
356 | 81.1k | size_t scopenamelen = strlen(name->scope) + 1; |
357 | 81.1k | ret += scopenamelen; |
358 | 81.1k | if (buf) { |
359 | 40.5k | if (offset+1+scopenamelen >= buflen) { |
360 | 0 | return 0; |
361 | 0 | } |
362 | 40.5k | strlcpy(&buf[offset+1],name->scope, |
363 | 40.5k | buflen - (offset+1)); |
364 | | |
365 | 40.5k | p = &buf[offset+1]; |
366 | 63.1k | while ((p = strchr_m(p,'.'))) { |
367 | 22.5k | buf[offset] = PTR_DIFF(p,&buf[offset+1]); |
368 | 22.5k | offset += (buf[offset] + 1); |
369 | 22.5k | if (offset+1 >= buflen) { |
370 | 0 | return 0; |
371 | 0 | } |
372 | 22.5k | p = &buf[offset+1]; |
373 | 22.5k | } |
374 | 40.5k | buf[offset] = strlen(&buf[offset+1]); |
375 | 40.5k | } |
376 | 81.1k | } |
377 | | |
378 | 485k | return ret; |
379 | 485k | } |
380 | | |
381 | | /******************************************************************* |
382 | | Useful for debugging messages. |
383 | | ******************************************************************/ |
384 | | |
385 | | char *nmb_namestr(const struct nmb_name *n) |
386 | 0 | { |
387 | 0 | fstring name; |
388 | 0 | char *result; |
389 | |
|
390 | 0 | pull_ascii_fstring(name, n->name); |
391 | 0 | if (!n->scope[0]) |
392 | 0 | result = talloc_asprintf(talloc_tos(), "%s<%02x>", name, |
393 | 0 | n->name_type); |
394 | 0 | else |
395 | 0 | result = talloc_asprintf(talloc_tos(), "%s<%02x>.%s", name, |
396 | 0 | n->name_type, n->scope); |
397 | |
|
398 | 0 | SMB_ASSERT(result != NULL); |
399 | 0 | return result; |
400 | 0 | } |
401 | | |
402 | | /******************************************************************* |
403 | | Allocate and parse some resource records. |
404 | | ******************************************************************/ |
405 | | |
406 | | static bool parse_alloc_res_rec(char *inbuf,int *offset,int length, |
407 | | struct res_rec **recs, int count) |
408 | 697 | { |
409 | 697 | int i; |
410 | | |
411 | 697 | *recs = SMB_MALLOC_ARRAY(struct res_rec, count); |
412 | 697 | if (!*recs) |
413 | 0 | return(False); |
414 | | |
415 | 697 | memset((char *)*recs,'\0',sizeof(**recs)*count); |
416 | | |
417 | 355k | for (i=0;i<count;i++) { |
418 | 355k | int l = parse_nmb_name(inbuf,*offset,length, |
419 | 355k | &(*recs)[i].rr_name); |
420 | 355k | (*offset) += l; |
421 | 355k | if (!l || (*offset)+10 > length) { |
422 | 235 | SAFE_FREE(*recs); |
423 | 235 | return(False); |
424 | 235 | } |
425 | 354k | (*recs)[i].rr_type = RSVAL(inbuf,(*offset)); |
426 | 354k | (*recs)[i].rr_class = RSVAL(inbuf,(*offset)+2); |
427 | 354k | (*recs)[i].ttl = RIVAL(inbuf,(*offset)+4); |
428 | 354k | (*recs)[i].rdlength = RSVAL(inbuf,(*offset)+8); |
429 | 354k | (*offset) += 10; |
430 | 354k | if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) || |
431 | 354k | (*offset)+(*recs)[i].rdlength > length) { |
432 | 45 | SAFE_FREE(*recs); |
433 | 45 | return(False); |
434 | 45 | } |
435 | 354k | memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength); |
436 | 354k | (*offset) += (*recs)[i].rdlength; |
437 | 354k | } |
438 | 417 | return(True); |
439 | 697 | } |
440 | | |
441 | | /******************************************************************* |
442 | | Put a resource record into a packet. |
443 | | If buf == NULL this is a length calculation. |
444 | | ******************************************************************/ |
445 | | |
446 | | static int put_res_rec(char *buf, size_t buflen, int offset,struct res_rec *recs,int count) |
447 | 706 | { |
448 | 706 | int ret=0; |
449 | 706 | int i; |
450 | | |
451 | 486k | for (i=0;i<count;i++) { |
452 | 485k | int l = put_nmb_name(buf,buflen,offset,&recs[i].rr_name); |
453 | 485k | offset += l; |
454 | 485k | ret += l; |
455 | 485k | if (buf) { |
456 | 242k | RSSVAL(buf,offset,recs[i].rr_type); |
457 | 242k | RSSVAL(buf,offset+2,recs[i].rr_class); |
458 | 242k | RSIVAL(buf,offset+4,(unsigned int)recs[i].ttl); |
459 | 242k | RSSVAL(buf,offset+8,recs[i].rdlength); |
460 | 242k | memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength); |
461 | 242k | } |
462 | 485k | offset += 10+recs[i].rdlength; |
463 | 485k | ret += 10+recs[i].rdlength; |
464 | 485k | } |
465 | | |
466 | 706 | return ret; |
467 | 706 | } |
468 | | |
469 | | /******************************************************************* |
470 | | Put a compressed name pointer record into a packet. |
471 | | If buf == NULL this is a length calculation. |
472 | | ******************************************************************/ |
473 | | |
474 | | static int put_compressed_name_ptr(unsigned char *buf, |
475 | | int offset, |
476 | | struct res_rec *rec, |
477 | | int ptr_offset) |
478 | 70 | { |
479 | 70 | int ret=offset; |
480 | 70 | if (buf) { |
481 | 35 | buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF)); |
482 | 35 | buf[offset+1] = (ptr_offset & 0xFF); |
483 | 35 | } |
484 | 70 | offset += 2; |
485 | 70 | if (buf) { |
486 | 35 | RSSVAL(buf,offset,rec->rr_type); |
487 | 35 | RSSVAL(buf,offset+2,rec->rr_class); |
488 | 35 | RSIVAL(buf,offset+4,rec->ttl); |
489 | 35 | RSSVAL(buf,offset+8,rec->rdlength); |
490 | 35 | memcpy(buf+offset+10,rec->rdata,rec->rdlength); |
491 | 35 | } |
492 | 70 | offset += 10+rec->rdlength; |
493 | 70 | ret = (offset - ret); |
494 | | |
495 | 70 | return ret; |
496 | 70 | } |
497 | | |
498 | | /******************************************************************* |
499 | | Parse a dgram packet. Return False if the packet can't be parsed |
500 | | or is invalid for some reason, True otherwise. |
501 | | |
502 | | This is documented in section 4.4.1 of RFC1002. |
503 | | ******************************************************************/ |
504 | | |
505 | | static bool parse_dgram(char *inbuf,int length,struct dgram_packet *dgram) |
506 | 0 | { |
507 | 0 | size_t offset; |
508 | 0 | int flags; |
509 | |
|
510 | 0 | memset((char *)dgram,'\0',sizeof(*dgram)); |
511 | |
|
512 | 0 | if (length < 14) |
513 | 0 | return(False); |
514 | | |
515 | 0 | dgram->header.msg_type = CVAL(inbuf,0); |
516 | 0 | flags = CVAL(inbuf,1); |
517 | 0 | dgram->header.flags.node_type = (enum node_type)((flags>>2)&3); |
518 | 0 | if (flags & 1) |
519 | 0 | dgram->header.flags.more = True; |
520 | 0 | if (flags & 2) |
521 | 0 | dgram->header.flags.first = True; |
522 | 0 | dgram->header.dgm_id = RSVAL(inbuf,2); |
523 | 0 | putip((char *)&dgram->header.source_ip,inbuf+4); |
524 | 0 | dgram->header.source_port = RSVAL(inbuf,8); |
525 | 0 | dgram->header.dgm_length = RSVAL(inbuf,10); |
526 | 0 | dgram->header.packet_offset = RSVAL(inbuf,12); |
527 | |
|
528 | 0 | offset = 14; |
529 | |
|
530 | 0 | if (dgram->header.msg_type == 0x10 || |
531 | 0 | dgram->header.msg_type == 0x11 || |
532 | 0 | dgram->header.msg_type == 0x12) { |
533 | 0 | offset += parse_nmb_name(inbuf,offset,length, |
534 | 0 | &dgram->source_name); |
535 | 0 | offset += parse_nmb_name(inbuf,offset,length, |
536 | 0 | &dgram->dest_name); |
537 | 0 | } |
538 | |
|
539 | 0 | if (offset >= length || (length-offset > sizeof(dgram->data))) |
540 | 0 | return(False); |
541 | | |
542 | 0 | dgram->datasize = length-offset; |
543 | 0 | memcpy(dgram->data,inbuf+offset,dgram->datasize); |
544 | | |
545 | | /* Paranioa. Ensure the last 2 bytes in the dgram buffer are |
546 | | zero. This should be true anyway, just enforce it for |
547 | | paranioa sake. JRA. */ |
548 | 0 | SMB_ASSERT(dgram->datasize <= (sizeof(dgram->data)-2)); |
549 | 0 | memset(&dgram->data[sizeof(dgram->data)-2], '\0', 2); |
550 | |
|
551 | 0 | return(True); |
552 | 0 | } |
553 | | |
554 | | /******************************************************************* |
555 | | Parse a nmb packet. Return False if the packet can't be parsed |
556 | | or is invalid for some reason, True otherwise. |
557 | | ******************************************************************/ |
558 | | |
559 | | static bool parse_nmb(char *inbuf,int length,struct nmb_packet *nmb) |
560 | 742 | { |
561 | 742 | int nm_flags,offset; |
562 | | |
563 | 742 | memset((char *)nmb,'\0',sizeof(*nmb)); |
564 | | |
565 | 742 | if (length < 12) |
566 | 5 | return(False); |
567 | | |
568 | | /* parse the header */ |
569 | 737 | nmb->header.name_trn_id = RSVAL(inbuf,0); |
570 | | |
571 | 737 | DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id)); |
572 | | |
573 | 737 | nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF; |
574 | 737 | nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False; |
575 | 737 | nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4); |
576 | 737 | nmb->header.nm_flags.bcast = (nm_flags&1)?True:False; |
577 | 737 | nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False; |
578 | 737 | nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False; |
579 | 737 | nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False; |
580 | 737 | nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False; |
581 | 737 | nmb->header.rcode = CVAL(inbuf,3) & 0xF; |
582 | 737 | nmb->header.qdcount = RSVAL(inbuf,4); |
583 | 737 | nmb->header.ancount = RSVAL(inbuf,6); |
584 | 737 | nmb->header.nscount = RSVAL(inbuf,8); |
585 | 737 | nmb->header.arcount = RSVAL(inbuf,10); |
586 | | |
587 | 737 | if (nmb->header.qdcount) { |
588 | 315 | offset = parse_nmb_name(inbuf,12,length, |
589 | 315 | &nmb->question.question_name); |
590 | 315 | if (!offset) |
591 | 104 | return(False); |
592 | | |
593 | 211 | if (length - (12+offset) < 4) |
594 | 11 | return(False); |
595 | 200 | nmb->question.question_type = RSVAL(inbuf,12+offset); |
596 | 200 | nmb->question.question_class = RSVAL(inbuf,12+offset+2); |
597 | | |
598 | 200 | offset += 12+4; |
599 | 422 | } else { |
600 | 422 | offset = 12; |
601 | 422 | } |
602 | | |
603 | | /* and any resource records */ |
604 | 622 | if (nmb->header.ancount && |
605 | 287 | !parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers, |
606 | 287 | nmb->header.ancount)) |
607 | 145 | return(False); |
608 | | |
609 | 477 | if (nmb->header.nscount && |
610 | 189 | !parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs, |
611 | 189 | nmb->header.nscount)) |
612 | 71 | return(False); |
613 | | |
614 | 406 | if (nmb->header.arcount && |
615 | 221 | !parse_alloc_res_rec(inbuf,&offset,length, |
616 | 221 | &nmb->additional, nmb->header.arcount)) |
617 | 64 | return(False); |
618 | | |
619 | 342 | return(True); |
620 | 406 | } |
621 | | |
622 | | /******************************************************************* |
623 | | 'Copy constructor' for an nmb packet. |
624 | | ******************************************************************/ |
625 | | |
626 | | static struct packet_struct *copy_nmb_packet(struct packet_struct *packet) |
627 | 0 | { |
628 | 0 | struct nmb_packet *nmb; |
629 | 0 | struct nmb_packet *copy_nmb; |
630 | 0 | struct packet_struct *pkt_copy; |
631 | |
|
632 | 0 | if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == NULL) { |
633 | 0 | DEBUG(0,("copy_nmb_packet: malloc fail.\n")); |
634 | 0 | return NULL; |
635 | 0 | } |
636 | | |
637 | | /* Structure copy of entire thing. */ |
638 | | |
639 | 0 | *pkt_copy = *packet; |
640 | | |
641 | | /* Ensure this copy is not locked. */ |
642 | 0 | pkt_copy->locked = False; |
643 | 0 | pkt_copy->recv_fd = -1; |
644 | 0 | pkt_copy->send_fd = -1; |
645 | | |
646 | | /* Ensure this copy has no resource records. */ |
647 | 0 | nmb = &packet->packet.nmb; |
648 | 0 | copy_nmb = &pkt_copy->packet.nmb; |
649 | |
|
650 | 0 | copy_nmb->answers = NULL; |
651 | 0 | copy_nmb->nsrecs = NULL; |
652 | 0 | copy_nmb->additional = NULL; |
653 | | |
654 | | /* Now copy any resource records. */ |
655 | |
|
656 | 0 | if (nmb->answers) { |
657 | 0 | if((copy_nmb->answers = SMB_MALLOC_ARRAY( |
658 | 0 | struct res_rec,nmb->header.ancount)) == NULL) |
659 | 0 | goto free_and_exit; |
660 | 0 | memcpy((char *)copy_nmb->answers, (char *)nmb->answers, |
661 | 0 | nmb->header.ancount * sizeof(struct res_rec)); |
662 | 0 | } |
663 | 0 | if (nmb->nsrecs) { |
664 | 0 | if((copy_nmb->nsrecs = SMB_MALLOC_ARRAY( |
665 | 0 | struct res_rec, nmb->header.nscount)) == NULL) |
666 | 0 | goto free_and_exit; |
667 | 0 | memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs, |
668 | 0 | nmb->header.nscount * sizeof(struct res_rec)); |
669 | 0 | } |
670 | 0 | if (nmb->additional) { |
671 | 0 | if((copy_nmb->additional = SMB_MALLOC_ARRAY( |
672 | 0 | struct res_rec, nmb->header.arcount)) == NULL) |
673 | 0 | goto free_and_exit; |
674 | 0 | memcpy((char *)copy_nmb->additional, (char *)nmb->additional, |
675 | 0 | nmb->header.arcount * sizeof(struct res_rec)); |
676 | 0 | } |
677 | | |
678 | 0 | return pkt_copy; |
679 | | |
680 | 0 | free_and_exit: |
681 | |
|
682 | 0 | SAFE_FREE(copy_nmb->answers); |
683 | 0 | SAFE_FREE(copy_nmb->nsrecs); |
684 | 0 | SAFE_FREE(copy_nmb->additional); |
685 | 0 | SAFE_FREE(pkt_copy); |
686 | |
|
687 | 0 | DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n")); |
688 | 0 | return NULL; |
689 | 0 | } |
690 | | |
691 | | /******************************************************************* |
692 | | 'Copy constructor' for a dgram packet. |
693 | | ******************************************************************/ |
694 | | |
695 | | static struct packet_struct *copy_dgram_packet(struct packet_struct *packet) |
696 | 0 | { |
697 | 0 | struct packet_struct *pkt_copy; |
698 | |
|
699 | 0 | if(( pkt_copy = SMB_MALLOC_P(struct packet_struct)) == NULL) { |
700 | 0 | DEBUG(0,("copy_dgram_packet: malloc fail.\n")); |
701 | 0 | return NULL; |
702 | 0 | } |
703 | | |
704 | | /* Structure copy of entire thing. */ |
705 | | |
706 | 0 | *pkt_copy = *packet; |
707 | | |
708 | | /* Ensure this copy is not locked. */ |
709 | 0 | pkt_copy->locked = False; |
710 | 0 | pkt_copy->recv_fd = -1; |
711 | 0 | pkt_copy->send_fd = -1; |
712 | | |
713 | | /* There are no additional pointers in a dgram packet, |
714 | | we are finished. */ |
715 | 0 | return pkt_copy; |
716 | 0 | } |
717 | | |
718 | | /******************************************************************* |
719 | | 'Copy constructor' for a generic packet. |
720 | | ******************************************************************/ |
721 | | |
722 | | struct packet_struct *copy_packet(struct packet_struct *packet) |
723 | 0 | { |
724 | 0 | if(packet->packet_type == NMB_PACKET) |
725 | 0 | return copy_nmb_packet(packet); |
726 | 0 | else if (packet->packet_type == DGRAM_PACKET) |
727 | 0 | return copy_dgram_packet(packet); |
728 | 0 | return NULL; |
729 | 0 | } |
730 | | |
731 | | /******************************************************************* |
732 | | Free up any resources associated with an nmb packet. |
733 | | ******************************************************************/ |
734 | | |
735 | | static void free_nmb_packet(struct nmb_packet *nmb) |
736 | 742 | { |
737 | 742 | SAFE_FREE(nmb->answers); |
738 | 742 | SAFE_FREE(nmb->nsrecs); |
739 | 742 | SAFE_FREE(nmb->additional); |
740 | 742 | } |
741 | | |
742 | | /******************************************************************* |
743 | | Free up any resources associated with a dgram packet. |
744 | | ******************************************************************/ |
745 | | |
746 | | static void free_dgram_packet(struct dgram_packet *nmb) |
747 | 0 | { |
748 | | /* We have nothing to do for a dgram packet. */ |
749 | 0 | } |
750 | | |
751 | | /******************************************************************* |
752 | | Free up any resources associated with a packet. |
753 | | ******************************************************************/ |
754 | | |
755 | | void free_packet(struct packet_struct *packet) |
756 | 742 | { |
757 | 742 | if (packet->locked) |
758 | 0 | return; |
759 | 742 | if (packet->packet_type == NMB_PACKET) |
760 | 742 | free_nmb_packet(&packet->packet.nmb); |
761 | 0 | else if (packet->packet_type == DGRAM_PACKET) |
762 | 0 | free_dgram_packet(&packet->packet.dgram); |
763 | 742 | ZERO_STRUCTPN(packet); |
764 | 742 | SAFE_FREE(packet); |
765 | 742 | } |
766 | | |
767 | | int packet_trn_id(struct packet_struct *p) |
768 | 0 | { |
769 | 0 | int result; |
770 | 0 | switch (p->packet_type) { |
771 | 0 | case NMB_PACKET: |
772 | 0 | result = p->packet.nmb.header.name_trn_id; |
773 | 0 | break; |
774 | 0 | case DGRAM_PACKET: |
775 | 0 | result = p->packet.dgram.header.dgm_id; |
776 | 0 | break; |
777 | 0 | default: |
778 | 0 | result = -1; |
779 | 0 | } |
780 | 0 | return result; |
781 | 0 | } |
782 | | |
783 | | /******************************************************************* |
784 | | Parse a packet buffer into a packet structure. |
785 | | ******************************************************************/ |
786 | | |
787 | | struct packet_struct *parse_packet(char *buf,int length, |
788 | | enum packet_type packet_type, |
789 | | struct in_addr ip, |
790 | | int port) |
791 | 742 | { |
792 | 742 | struct packet_struct *p; |
793 | 742 | bool ok=False; |
794 | | |
795 | 742 | p = SMB_MALLOC_P(struct packet_struct); |
796 | 742 | if (!p) |
797 | 0 | return(NULL); |
798 | | |
799 | 742 | ZERO_STRUCTP(p); /* initialize for possible padding */ |
800 | | |
801 | 742 | p->next = NULL; |
802 | 742 | p->prev = NULL; |
803 | 742 | p->ip = ip; |
804 | 742 | p->port = port; |
805 | 742 | p->locked = False; |
806 | 742 | p->timestamp = time(NULL); |
807 | 742 | p->packet_type = packet_type; |
808 | | |
809 | 742 | switch (packet_type) { |
810 | 742 | case NMB_PACKET: |
811 | 742 | ok = parse_nmb(buf,length,&p->packet.nmb); |
812 | 742 | break; |
813 | | |
814 | 0 | case DGRAM_PACKET: |
815 | 0 | ok = parse_dgram(buf,length,&p->packet.dgram); |
816 | 0 | break; |
817 | 742 | } |
818 | | |
819 | 742 | if (!ok) { |
820 | 400 | free_packet(p); |
821 | 400 | return NULL; |
822 | 400 | } |
823 | | |
824 | 342 | return p; |
825 | 742 | } |
826 | | |
827 | | static struct packet_struct *copy_packet_talloc( |
828 | | TALLOC_CTX *mem_ctx, const struct packet_struct *src) |
829 | 0 | { |
830 | 0 | struct packet_struct *pkt; |
831 | |
|
832 | 0 | pkt = talloc_memdup(mem_ctx, src, sizeof(struct packet_struct)); |
833 | 0 | if (pkt == NULL) { |
834 | 0 | return NULL; |
835 | 0 | } |
836 | 0 | pkt->locked = false; |
837 | 0 | pkt->recv_fd = -1; |
838 | 0 | pkt->send_fd = -1; |
839 | |
|
840 | 0 | if (src->packet_type == NMB_PACKET) { |
841 | 0 | const struct nmb_packet *nsrc = &src->packet.nmb; |
842 | 0 | struct nmb_packet *ndst = &pkt->packet.nmb; |
843 | |
|
844 | 0 | if (nsrc->answers != NULL) { |
845 | 0 | ndst->answers = talloc_memdup( |
846 | 0 | pkt, nsrc->answers, |
847 | 0 | sizeof(struct res_rec) * nsrc->header.ancount); |
848 | 0 | if (ndst->answers == NULL) { |
849 | 0 | goto fail; |
850 | 0 | } |
851 | 0 | } |
852 | 0 | if (nsrc->nsrecs != NULL) { |
853 | 0 | ndst->nsrecs = talloc_memdup( |
854 | 0 | pkt, nsrc->nsrecs, |
855 | 0 | sizeof(struct res_rec) * nsrc->header.nscount); |
856 | 0 | if (ndst->nsrecs == NULL) { |
857 | 0 | goto fail; |
858 | 0 | } |
859 | 0 | } |
860 | 0 | if (nsrc->additional != NULL) { |
861 | 0 | ndst->additional = talloc_memdup( |
862 | 0 | pkt, nsrc->additional, |
863 | 0 | sizeof(struct res_rec) * nsrc->header.arcount); |
864 | 0 | if (ndst->additional == NULL) { |
865 | 0 | goto fail; |
866 | 0 | } |
867 | 0 | } |
868 | 0 | } |
869 | | |
870 | 0 | return pkt; |
871 | | |
872 | | /* |
873 | | * DGRAM packets have no substructures |
874 | | */ |
875 | | |
876 | 0 | fail: |
877 | 0 | TALLOC_FREE(pkt); |
878 | 0 | return NULL; |
879 | 0 | } |
880 | | |
881 | | struct packet_struct *parse_packet_talloc(TALLOC_CTX *mem_ctx, |
882 | | char *buf,int length, |
883 | | enum packet_type packet_type, |
884 | | struct in_addr ip, |
885 | | int port) |
886 | 0 | { |
887 | 0 | struct packet_struct *pkt, *result; |
888 | |
|
889 | 0 | pkt = parse_packet(buf, length, packet_type, ip, port); |
890 | 0 | if (pkt == NULL) { |
891 | 0 | return NULL; |
892 | 0 | } |
893 | 0 | result = copy_packet_talloc(mem_ctx, pkt); |
894 | 0 | free_packet(pkt); |
895 | 0 | return result; |
896 | 0 | } |
897 | | |
898 | | /******************************************************************* |
899 | | Send a udp packet on a already open socket. |
900 | | ******************************************************************/ |
901 | | |
902 | | static bool send_udp(int fd,char *buf,int len,struct in_addr ip,int port) |
903 | 0 | { |
904 | 0 | bool ret = False; |
905 | 0 | int i; |
906 | 0 | struct sockaddr_in sock_out; |
907 | | |
908 | | /* set the address and port */ |
909 | 0 | memset((char *)&sock_out,'\0',sizeof(sock_out)); |
910 | 0 | putip((char *)&sock_out.sin_addr,(char *)&ip); |
911 | 0 | sock_out.sin_port = htons( port ); |
912 | 0 | sock_out.sin_family = AF_INET; |
913 | |
|
914 | 0 | DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n", |
915 | 0 | len, inet_ntoa(ip), port ) ); |
916 | | |
917 | | /* |
918 | | * Patch to fix asynch error notifications from Linux kernel. |
919 | | */ |
920 | |
|
921 | 0 | for (i = 0; i < 5; i++) { |
922 | 0 | ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, |
923 | 0 | sizeof(sock_out)) >= 0); |
924 | 0 | if (ret || errno != ECONNREFUSED) |
925 | 0 | break; |
926 | 0 | } |
927 | |
|
928 | 0 | if (!ret) |
929 | 0 | DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n", |
930 | 0 | inet_ntoa(ip),port,strerror(errno))); |
931 | |
|
932 | 0 | return(ret); |
933 | 0 | } |
934 | | |
935 | | /******************************************************************* |
936 | | Build a dgram packet ready for sending. |
937 | | If buf == NULL this is a length calculation. |
938 | | ******************************************************************/ |
939 | | |
940 | | static int build_dgram(char *buf, size_t len, struct dgram_packet *dgram) |
941 | 0 | { |
942 | 0 | unsigned char *ubuf = (unsigned char *)buf; |
943 | 0 | int offset=0; |
944 | | |
945 | | /* put in the header */ |
946 | 0 | if (buf) { |
947 | 0 | ubuf[0] = dgram->header.msg_type; |
948 | 0 | ubuf[1] = (((int)dgram->header.flags.node_type)<<2); |
949 | 0 | if (dgram->header.flags.more) |
950 | 0 | ubuf[1] |= 1; |
951 | 0 | if (dgram->header.flags.first) |
952 | 0 | ubuf[1] |= 2; |
953 | 0 | RSSVAL(ubuf,2,dgram->header.dgm_id); |
954 | 0 | putip(ubuf+4,(char *)&dgram->header.source_ip); |
955 | 0 | RSSVAL(ubuf,8,dgram->header.source_port); |
956 | 0 | RSSVAL(ubuf,12,dgram->header.packet_offset); |
957 | 0 | } |
958 | |
|
959 | 0 | offset = 14; |
960 | |
|
961 | 0 | if (dgram->header.msg_type == 0x10 || |
962 | 0 | dgram->header.msg_type == 0x11 || |
963 | 0 | dgram->header.msg_type == 0x12) { |
964 | 0 | offset += put_nmb_name((char *)ubuf,len,offset,&dgram->source_name); |
965 | 0 | offset += put_nmb_name((char *)ubuf,len,offset,&dgram->dest_name); |
966 | 0 | } |
967 | |
|
968 | 0 | if (buf) { |
969 | 0 | memcpy(ubuf+offset,dgram->data,dgram->datasize); |
970 | 0 | } |
971 | 0 | offset += dgram->datasize; |
972 | | |
973 | | /* automatically set the dgm_length |
974 | | * NOTE: RFC1002 says the dgm_length does *not* |
975 | | * include the fourteen-byte header. crh |
976 | | */ |
977 | 0 | dgram->header.dgm_length = (offset - 14); |
978 | 0 | if (buf) { |
979 | 0 | RSSVAL(ubuf,10,dgram->header.dgm_length); |
980 | 0 | } |
981 | |
|
982 | 0 | return offset; |
983 | 0 | } |
984 | | |
985 | | /******************************************************************* |
986 | | Build a nmb name |
987 | | *******************************************************************/ |
988 | | |
989 | | void make_nmb_name( struct nmb_name *n, const char *name, int type) |
990 | 0 | { |
991 | 0 | fstring unix_name; |
992 | 0 | memset( (char *)n, '\0', sizeof(struct nmb_name) ); |
993 | 0 | fstrcpy(unix_name, name); |
994 | 0 | (void)strupper_m(unix_name); |
995 | 0 | push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE); |
996 | 0 | n->name_type = (unsigned int)type & 0xFF; |
997 | 0 | push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE); |
998 | 0 | } |
999 | | |
1000 | | /******************************************************************* |
1001 | | Compare two nmb names |
1002 | | ******************************************************************/ |
1003 | | |
1004 | | bool nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2) |
1005 | 0 | { |
1006 | 0 | return ((n1->name_type == n2->name_type) && |
1007 | 0 | strequal(n1->name ,n2->name ) && |
1008 | 0 | strequal(n1->scope,n2->scope)); |
1009 | 0 | } |
1010 | | |
1011 | | /******************************************************************* |
1012 | | Build a nmb packet ready for sending. |
1013 | | If buf == NULL this is a length calculation. |
1014 | | ******************************************************************/ |
1015 | | |
1016 | | static int build_nmb(char *buf, size_t len, struct nmb_packet *nmb) |
1017 | 342 | { |
1018 | 342 | unsigned char *ubuf = (unsigned char *)buf; |
1019 | 342 | int offset=0; |
1020 | | |
1021 | 342 | if (len && len < 12) { |
1022 | 0 | return 0; |
1023 | 0 | } |
1024 | | |
1025 | | /* put in the header */ |
1026 | 342 | if (buf) { |
1027 | 342 | RSSVAL(ubuf,offset,nmb->header.name_trn_id); |
1028 | 342 | ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3; |
1029 | 342 | if (nmb->header.response) |
1030 | 48 | ubuf[offset+2] |= (1<<7); |
1031 | 342 | if (nmb->header.nm_flags.authoritative && |
1032 | 150 | nmb->header.response) |
1033 | 32 | ubuf[offset+2] |= 0x4; |
1034 | 342 | if (nmb->header.nm_flags.trunc) |
1035 | 126 | ubuf[offset+2] |= 0x2; |
1036 | 342 | if (nmb->header.nm_flags.recursion_desired) |
1037 | 111 | ubuf[offset+2] |= 0x1; |
1038 | 342 | if (nmb->header.nm_flags.recursion_available && |
1039 | 36 | nmb->header.response) |
1040 | 16 | ubuf[offset+3] |= 0x80; |
1041 | 342 | if (nmb->header.nm_flags.bcast) |
1042 | 82 | ubuf[offset+3] |= 0x10; |
1043 | 342 | ubuf[offset+3] |= (nmb->header.rcode & 0xF); |
1044 | | |
1045 | 342 | RSSVAL(ubuf,offset+4,nmb->header.qdcount); |
1046 | 342 | RSSVAL(ubuf,offset+6,nmb->header.ancount); |
1047 | 342 | RSSVAL(ubuf,offset+8,nmb->header.nscount); |
1048 | 342 | RSSVAL(ubuf,offset+10,nmb->header.arcount); |
1049 | 342 | } |
1050 | | |
1051 | 342 | offset += 12; |
1052 | 342 | if (nmb->header.qdcount) { |
1053 | | /* XXXX this doesn't handle a qdcount of > 1 */ |
1054 | 108 | if (len) { |
1055 | | /* Length check. */ |
1056 | 108 | int extra = put_nmb_name(NULL,0,offset, |
1057 | 108 | &nmb->question.question_name); |
1058 | 108 | if (offset + extra > len) { |
1059 | 0 | return 0; |
1060 | 0 | } |
1061 | 108 | } |
1062 | 108 | offset += put_nmb_name((char *)ubuf,len,offset, |
1063 | 108 | &nmb->question.question_name); |
1064 | 108 | if (buf) { |
1065 | 108 | RSSVAL(ubuf,offset,nmb->question.question_type); |
1066 | 108 | RSSVAL(ubuf,offset+2,nmb->question.question_class); |
1067 | 108 | } |
1068 | 108 | offset += 4; |
1069 | 108 | } |
1070 | | |
1071 | 342 | if (nmb->header.ancount) { |
1072 | 122 | if (len) { |
1073 | | /* Length check. */ |
1074 | 122 | int extra = put_res_rec(NULL,0,offset,nmb->answers, |
1075 | 122 | nmb->header.ancount); |
1076 | 122 | if (offset + extra > len) { |
1077 | 0 | return 0; |
1078 | 0 | } |
1079 | 122 | } |
1080 | 122 | offset += put_res_rec((char *)ubuf,len,offset,nmb->answers, |
1081 | 122 | nmb->header.ancount); |
1082 | 122 | } |
1083 | | |
1084 | 342 | if (nmb->header.nscount) { |
1085 | 109 | if (len) { |
1086 | | /* Length check. */ |
1087 | 109 | int extra = put_res_rec(NULL,0,offset,nmb->nsrecs, |
1088 | 109 | nmb->header.nscount); |
1089 | 109 | if (offset + extra > len) { |
1090 | 0 | return 0; |
1091 | 0 | } |
1092 | 109 | } |
1093 | 109 | offset += put_res_rec((char *)ubuf,len,offset,nmb->nsrecs, |
1094 | 109 | nmb->header.nscount); |
1095 | 109 | } |
1096 | | |
1097 | | /* |
1098 | | * The spec says we must put compressed name pointers |
1099 | | * in the following outgoing packets : |
1100 | | * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST, |
1101 | | * NAME_RELEASE_REQUEST. |
1102 | | */ |
1103 | | |
1104 | 342 | if((nmb->header.response == False) && |
1105 | 294 | ((nmb->header.opcode == NMB_NAME_REG_OPCODE) || |
1106 | 269 | (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) || |
1107 | 223 | (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) || |
1108 | 199 | (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) || |
1109 | 183 | (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) && |
1110 | 124 | (nmb->header.arcount == 1)) { |
1111 | | |
1112 | 35 | if (len) { |
1113 | | /* Length check. */ |
1114 | 35 | int extra = put_compressed_name_ptr(NULL,offset, |
1115 | 35 | nmb->additional,12); |
1116 | 35 | if (offset + extra > len) { |
1117 | 0 | return 0; |
1118 | 0 | } |
1119 | 35 | } |
1120 | 35 | offset += put_compressed_name_ptr(ubuf,offset, |
1121 | 35 | nmb->additional,12); |
1122 | 307 | } else if (nmb->header.arcount) { |
1123 | 122 | if (len) { |
1124 | | /* Length check. */ |
1125 | 122 | int extra = put_res_rec(NULL,0,offset,nmb->additional, |
1126 | 122 | nmb->header.arcount); |
1127 | 122 | if (offset + extra > len) { |
1128 | 0 | return 0; |
1129 | 0 | } |
1130 | 122 | } |
1131 | 122 | offset += put_res_rec((char *)ubuf,len,offset,nmb->additional, |
1132 | 122 | nmb->header.arcount); |
1133 | 122 | } |
1134 | 342 | return offset; |
1135 | 342 | } |
1136 | | |
1137 | | /******************************************************************* |
1138 | | Linearise a packet. |
1139 | | ******************************************************************/ |
1140 | | |
1141 | | int build_packet(char *buf, size_t buflen, struct packet_struct *p) |
1142 | 342 | { |
1143 | 342 | int len = 0; |
1144 | | |
1145 | 342 | switch (p->packet_type) { |
1146 | 342 | case NMB_PACKET: |
1147 | 342 | len = build_nmb(buf,buflen,&p->packet.nmb); |
1148 | 342 | break; |
1149 | | |
1150 | 0 | case DGRAM_PACKET: |
1151 | 0 | len = build_dgram(buf,buflen,&p->packet.dgram); |
1152 | 0 | break; |
1153 | 342 | } |
1154 | | |
1155 | 342 | return len; |
1156 | 342 | } |
1157 | | |
1158 | | /******************************************************************* |
1159 | | Send a packet_struct. |
1160 | | ******************************************************************/ |
1161 | | |
1162 | | bool send_packet(struct packet_struct *p) |
1163 | 0 | { |
1164 | 0 | char buf[1024]; |
1165 | 0 | int len=0; |
1166 | |
|
1167 | 0 | memset(buf,'\0',sizeof(buf)); |
1168 | |
|
1169 | 0 | len = build_packet(buf, sizeof(buf), p); |
1170 | |
|
1171 | 0 | if (!len) |
1172 | 0 | return(False); |
1173 | | |
1174 | 0 | return(send_udp(p->send_fd,buf,len,p->ip,p->port)); |
1175 | 0 | } |
1176 | | |
1177 | | /**************************************************************************** |
1178 | | Receive a UDP/138 packet either via UDP or from the unexpected packet |
1179 | | queue. The packet must be a reply packet and have the specified mailslot name |
1180 | | The timeout is in milliseconds. |
1181 | | ***************************************************************************/ |
1182 | | |
1183 | | /**************************************************************************** |
1184 | | See if a datagram has the right mailslot name. |
1185 | | ***************************************************************************/ |
1186 | | |
1187 | | bool match_mailslot_name(struct packet_struct *p, const char *mailslot_name) |
1188 | 0 | { |
1189 | 0 | struct dgram_packet *dgram = &p->packet.dgram; |
1190 | 0 | char *buf; |
1191 | |
|
1192 | 0 | buf = &dgram->data[0]; |
1193 | 0 | buf -= 4; |
1194 | |
|
1195 | 0 | buf = smb_buf(buf); |
1196 | |
|
1197 | 0 | if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) { |
1198 | 0 | return True; |
1199 | 0 | } |
1200 | | |
1201 | 0 | return False; |
1202 | 0 | } |
1203 | | |
1204 | | /**************************************************************************** |
1205 | | Return the number of bits that match between two len character buffers |
1206 | | ***************************************************************************/ |
1207 | | |
1208 | | int matching_len_bits(const unsigned char *p1, const unsigned char *p2, size_t len) |
1209 | 0 | { |
1210 | 0 | size_t i, j; |
1211 | 0 | int ret = 0; |
1212 | 0 | for (i=0; i<len; i++) { |
1213 | 0 | if (p1[i] != p2[i]) |
1214 | 0 | break; |
1215 | 0 | ret += 8; |
1216 | 0 | } |
1217 | |
|
1218 | 0 | if (i==len) |
1219 | 0 | return ret; |
1220 | | |
1221 | 0 | for (j=0; j<8; j++) { |
1222 | 0 | if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j)))) |
1223 | 0 | break; |
1224 | 0 | ret++; |
1225 | 0 | } |
1226 | |
|
1227 | 0 | return ret; |
1228 | 0 | } |
1229 | | |
1230 | | static unsigned char sort_ip[4]; |
1231 | | |
1232 | | /**************************************************************************** |
1233 | | Compare two query reply records. |
1234 | | ***************************************************************************/ |
1235 | | |
1236 | | static int name_query_comp(unsigned char *p1, unsigned char *p2) |
1237 | 0 | { |
1238 | 0 | int a = matching_len_bits(p1+2, sort_ip, 4); |
1239 | 0 | int b = matching_len_bits(p2+2, sort_ip, 4); |
1240 | | /* reverse sort -- p2 derived value comes first */ |
1241 | 0 | return NUMERIC_CMP(b, a); |
1242 | 0 | } |
1243 | | |
1244 | | /**************************************************************************** |
1245 | | Sort a set of 6 byte name query response records so that the IPs that |
1246 | | have the most leading bits in common with the specified address come first. |
1247 | | ***************************************************************************/ |
1248 | | |
1249 | | void sort_query_replies(char *data, int n, struct in_addr ip) |
1250 | 0 | { |
1251 | 0 | if (n <= 1) |
1252 | 0 | return; |
1253 | | |
1254 | 0 | putip(sort_ip, (char *)&ip); |
1255 | | |
1256 | | /* TODO: |
1257 | | this can't use TYPESAFE_QSORT() as the types are wrong. |
1258 | | It should be fixed to use a real type instead of char* |
1259 | | */ |
1260 | 0 | qsort(data, n, 6, QSORT_CAST name_query_comp); |
1261 | 0 | } |
1262 | | |
1263 | | /**************************************************************************** |
1264 | | Interpret the weird netbios "name" into a unix fstring. Return the name type. |
1265 | | Returns -1 on error. |
1266 | | ****************************************************************************/ |
1267 | | |
1268 | | static int name_interpret(unsigned char *buf, size_t buf_len, |
1269 | | unsigned char *in, fstring name) |
1270 | 0 | { |
1271 | 0 | unsigned char *end_ptr = buf + buf_len; |
1272 | 0 | int ret; |
1273 | 0 | unsigned int len; |
1274 | 0 | fstring out_string; |
1275 | 0 | unsigned char *out = (unsigned char *)out_string; |
1276 | |
|
1277 | 0 | *out=0; |
1278 | |
|
1279 | 0 | if (in >= end_ptr) { |
1280 | 0 | return -1; |
1281 | 0 | } |
1282 | 0 | len = (*in++) / 2; |
1283 | |
|
1284 | 0 | if (len<1) { |
1285 | 0 | return -1; |
1286 | 0 | } |
1287 | | |
1288 | 0 | while (len--) { |
1289 | 0 | if (&in[1] >= end_ptr) { |
1290 | 0 | return -1; |
1291 | 0 | } |
1292 | 0 | if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') { |
1293 | 0 | *out = 0; |
1294 | 0 | return(0); |
1295 | 0 | } |
1296 | 0 | *out = ((in[0]-'A')<<4) + (in[1]-'A'); |
1297 | 0 | in += 2; |
1298 | 0 | out++; |
1299 | 0 | if (PTR_DIFF(out,out_string) >= sizeof(fstring)) { |
1300 | 0 | return -1; |
1301 | 0 | } |
1302 | 0 | } |
1303 | 0 | ret = out[-1]; |
1304 | 0 | out[-1] = 0; |
1305 | |
|
1306 | 0 | pull_ascii_fstring(name, out_string); |
1307 | |
|
1308 | 0 | return(ret); |
1309 | 0 | } |
1310 | | |
1311 | | /**************************************************************************** |
1312 | | Mangle a name into netbios format. |
1313 | | Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum. |
1314 | | ****************************************************************************/ |
1315 | | |
1316 | | char *name_mangle(TALLOC_CTX *mem_ctx, const char *In, char name_type) |
1317 | 0 | { |
1318 | 0 | int i; |
1319 | 0 | int len; |
1320 | 0 | nstring buf; |
1321 | 0 | char *result; |
1322 | 0 | char *p; |
1323 | |
|
1324 | 0 | result = talloc_array(mem_ctx, char, 33 + strlen(lp_netbios_scope()) + 2); |
1325 | 0 | if (result == NULL) { |
1326 | 0 | return NULL; |
1327 | 0 | } |
1328 | 0 | p = result; |
1329 | | |
1330 | | /* Safely copy the input string, In, into buf[]. */ |
1331 | 0 | if (strcmp(In,"*") == 0) |
1332 | 0 | put_name(buf, "*", '\0', 0x00); |
1333 | 0 | else { |
1334 | | /* We use an fstring here as mb dos names can expend x3 when |
1335 | | going to utf8. */ |
1336 | 0 | fstring buf_unix; |
1337 | 0 | nstring buf_dos; |
1338 | |
|
1339 | 0 | pull_ascii_fstring(buf_unix, In); |
1340 | 0 | if (!strupper_m(buf_unix)) { |
1341 | 0 | return NULL; |
1342 | 0 | } |
1343 | | |
1344 | 0 | push_ascii_nstring(buf_dos, buf_unix); |
1345 | 0 | put_name(buf, buf_dos, ' ', name_type); |
1346 | 0 | } |
1347 | | |
1348 | | /* Place the length of the first field into the output buffer. */ |
1349 | 0 | p[0] = 32; |
1350 | 0 | p++; |
1351 | | |
1352 | | /* Now convert the name to the rfc1001/1002 format. */ |
1353 | 0 | for( i = 0; i < MAX_NETBIOSNAME_LEN; i++ ) { |
1354 | 0 | p[i*2] = ( (buf[i] >> 4) & 0x000F ) + 'A'; |
1355 | 0 | p[(i*2)+1] = (buf[i] & 0x000F) + 'A'; |
1356 | 0 | } |
1357 | 0 | p += 32; |
1358 | 0 | p[0] = '\0'; |
1359 | | |
1360 | | /* Add the scope string. */ |
1361 | 0 | for( i = 0, len = 0; *(lp_netbios_scope()) != '\0'; i++, len++ ) { |
1362 | 0 | switch( (lp_netbios_scope())[i] ) { |
1363 | 0 | case '\0': |
1364 | 0 | p[0] = len; |
1365 | 0 | if( len > 0 ) |
1366 | 0 | p[len+1] = 0; |
1367 | 0 | return result; |
1368 | 0 | case '.': |
1369 | 0 | p[0] = len; |
1370 | 0 | p += (len + 1); |
1371 | 0 | len = -1; |
1372 | 0 | break; |
1373 | 0 | default: |
1374 | 0 | p[len+1] = (lp_netbios_scope())[i]; |
1375 | 0 | break; |
1376 | 0 | } |
1377 | 0 | } |
1378 | | |
1379 | 0 | return result; |
1380 | 0 | } |
1381 | | |
1382 | | /**************************************************************************** |
1383 | | Find a pointer to a netbios name. |
1384 | | ****************************************************************************/ |
1385 | | |
1386 | | static unsigned char *name_ptr(unsigned char *buf, size_t buf_len, unsigned int ofs) |
1387 | 0 | { |
1388 | 0 | unsigned char c = 0; |
1389 | |
|
1390 | 0 | if (ofs > buf_len || buf_len < 1) { |
1391 | 0 | return NULL; |
1392 | 0 | } |
1393 | | |
1394 | 0 | c = *(unsigned char *)(buf+ofs); |
1395 | 0 | if ((c & 0xC0) == 0xC0) { |
1396 | 0 | uint16_t l = 0; |
1397 | |
|
1398 | 0 | if (ofs > buf_len - 1) { |
1399 | 0 | return NULL; |
1400 | 0 | } |
1401 | 0 | l = RSVAL(buf, ofs) & 0x3FFF; |
1402 | 0 | if (l > buf_len) { |
1403 | 0 | return NULL; |
1404 | 0 | } |
1405 | 0 | DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l)); |
1406 | 0 | return(buf + l); |
1407 | 0 | } else { |
1408 | 0 | return(buf+ofs); |
1409 | 0 | } |
1410 | 0 | } |
1411 | | |
1412 | | /**************************************************************************** |
1413 | | Extract a netbios name from a buf (into a unix string) return name type. |
1414 | | Returns -1 on error. |
1415 | | ****************************************************************************/ |
1416 | | |
1417 | | int name_extract(unsigned char *buf, size_t buf_len, unsigned int ofs, fstring name) |
1418 | 0 | { |
1419 | 0 | unsigned char *p = name_ptr(buf,buf_len,ofs); |
1420 | |
|
1421 | 0 | name[0] = '\0'; |
1422 | 0 | if (p == NULL) { |
1423 | 0 | return -1; |
1424 | 0 | } |
1425 | 0 | return(name_interpret(buf,buf_len,p,name)); |
1426 | 0 | } |
1427 | | |
1428 | | /**************************************************************************** |
1429 | | Return the total storage length of a mangled name. |
1430 | | Returns -1 on error. |
1431 | | ****************************************************************************/ |
1432 | | |
1433 | | int name_len(unsigned char *s1, size_t buf_len) |
1434 | 0 | { |
1435 | | /* NOTE: this argument _must_ be unsigned */ |
1436 | 0 | unsigned char *s = (unsigned char *)s1; |
1437 | 0 | int len = 0; |
1438 | |
|
1439 | 0 | if (buf_len < 1) { |
1440 | 0 | return -1; |
1441 | 0 | } |
1442 | | /* If the two high bits of the byte are set, return 2. */ |
1443 | 0 | if (0xC0 == (*s & 0xC0)) { |
1444 | 0 | if (buf_len < 2) { |
1445 | 0 | return -1; |
1446 | 0 | } |
1447 | 0 | return(2); |
1448 | 0 | } |
1449 | | |
1450 | | /* Add up the length bytes. */ |
1451 | 0 | for (len = 1; (*s); s += (*s) + 1) { |
1452 | 0 | len += *s + 1; |
1453 | 0 | if (len > buf_len) { |
1454 | 0 | return -1; |
1455 | 0 | } |
1456 | 0 | } |
1457 | | |
1458 | 0 | return(len); |
1459 | 0 | } |
1460 | | |
1461 | | /******************************************************************* |
1462 | | Setup the word count and byte count for a client smb message. |
1463 | | ********************************************************************/ |
1464 | | |
1465 | | int cli_set_message(char *buf,int num_words,int num_bytes,bool zero) |
1466 | 0 | { |
1467 | 0 | if (zero && (num_words || num_bytes)) { |
1468 | 0 | memset(buf + smb_size,'\0',num_words*2 + num_bytes); |
1469 | 0 | } |
1470 | 0 | SCVAL(buf,smb_wct,num_words); |
1471 | 0 | SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes); |
1472 | 0 | smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4); |
1473 | 0 | return (smb_size + num_words*2 + num_bytes); |
1474 | 0 | } |