Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : manipulate nbt name structures
5 :
6 : Copyright (C) Andrew Tridgell 2005
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : /*
23 : see rfc1002 for the detailed format of compressed names
24 : */
25 :
26 : #include "includes.h"
27 : #include "librpc/gen_ndr/ndr_nbt.h"
28 : #include "librpc/gen_ndr/ndr_misc.h"
29 : #include "system/locale.h"
30 : #include "lib/util/util_net.h"
31 : #include "libcli/nbt/libnbt.h"
32 :
33 : /*
34 : decompress a 'compressed' name component
35 : */
36 18648 : static bool decompress_name(char *name, enum nbt_name_type *type)
37 : {
38 : int i;
39 317016 : for (i=0;name[2*i];i++) {
40 298368 : uint8_t c1 = name[2*i];
41 298368 : uint8_t c2 = name[1+(2*i)];
42 298368 : if (c1 < 'A' || c1 > 'P' ||
43 298368 : c2 < 'A' || c2 > 'P') {
44 0 : return false;
45 : }
46 298368 : name[i] = ((c1-'A')<<4) | (c2-'A');
47 : }
48 18648 : name[i] = 0;
49 18648 : if (i == 16) {
50 18648 : *type = (enum nbt_name_type)(name[15]);
51 18648 : name[15] = 0;
52 18648 : i--;
53 : } else {
54 0 : *type = NBT_NAME_CLIENT;
55 : }
56 :
57 : /* trim trailing spaces */
58 128190 : for (;i>0 && name[i-1]==' ';i--) {
59 109542 : name[i-1] = 0;
60 : }
61 :
62 18648 : return true;
63 : }
64 :
65 :
66 : /*
67 : compress a name component
68 : */
69 11734 : static uint8_t *compress_name(TALLOC_CTX *mem_ctx,
70 : const uint8_t *name, enum nbt_name_type type)
71 : {
72 : uint8_t *cname;
73 : int i;
74 : uint8_t pad_char;
75 :
76 11734 : if (strlen((const char *)name) > 15) {
77 0 : return NULL;
78 : }
79 :
80 11734 : cname = talloc_array(mem_ctx, uint8_t, 33);
81 11734 : if (cname == NULL) return NULL;
82 :
83 102952 : for (i=0;name[i];i++) {
84 91218 : cname[2*i] = 'A' + (name[i]>>4);
85 91218 : cname[1+2*i] = 'A' + (name[i]&0xF);
86 : }
87 11734 : if (strcmp((const char *)name, "*") == 0) {
88 6 : pad_char = 0;
89 : } else {
90 11728 : pad_char = ' ';
91 : }
92 96526 : for (;i<15;i++) {
93 84792 : cname[2*i] = 'A' + (pad_char>>4);
94 84792 : cname[1+2*i] = 'A' + (pad_char&0xF);
95 : }
96 :
97 11734 : pad_char = type;
98 11734 : cname[2*i] = 'A' + (pad_char>>4);
99 11734 : cname[1+2*i] = 'A' + (pad_char&0xF);
100 :
101 11734 : cname[32] = 0;
102 11734 : return cname;
103 : }
104 :
105 :
106 : /**
107 : pull a nbt name from the wire
108 : */
109 18648 : _PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r)
110 : {
111 : uint8_t *scope;
112 : char *cname;
113 : const char *s;
114 : bool ok;
115 :
116 18648 : if (!(ndr_flags & NDR_SCALARS)) {
117 0 : return NDR_ERR_SUCCESS;
118 : }
119 :
120 18648 : NDR_CHECK(ndr_pull_nbt_string(ndr, ndr_flags, &s));
121 :
122 18648 : scope = (uint8_t *)strchr(s, '.');
123 18648 : if (scope) {
124 239 : *scope = 0;
125 239 : r->scope = talloc_strdup(ndr->current_mem_ctx, (const char *)&scope[1]);
126 239 : NDR_ERR_HAVE_NO_MEMORY(r->scope);
127 : } else {
128 18409 : r->scope = NULL;
129 : }
130 :
131 18648 : cname = discard_const_p(char, s);
132 :
133 : /* the first component is limited to 16 bytes in the DOS charset,
134 : which is 32 in the 'compressed' form */
135 18648 : if (strlen(cname) > 32) {
136 0 : return ndr_pull_error(ndr, NDR_ERR_STRING,
137 : "NBT NAME cname > 32");
138 : }
139 :
140 : /* decompress the first component */
141 18648 : ok = decompress_name(cname, &r->type);
142 18648 : if (!ok) {
143 0 : return ndr_pull_error(ndr, NDR_ERR_STRING,
144 : "NBT NAME failed to decompress");
145 : }
146 :
147 18648 : r->name = talloc_strdup(ndr->current_mem_ctx, cname);
148 18648 : NDR_ERR_HAVE_NO_MEMORY(r->name);
149 :
150 18648 : talloc_free(cname);
151 :
152 18648 : return NDR_ERR_SUCCESS;
153 : }
154 :
155 : /**
156 : push a nbt name to the wire
157 : */
158 11734 : _PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r)
159 : {
160 : uint8_t *cname, *fullname;
161 : enum ndr_err_code ndr_err;
162 :
163 11734 : if (!(ndr_flags & NDR_SCALARS)) {
164 0 : return NDR_ERR_SUCCESS;
165 : }
166 :
167 11734 : if (strlen(r->name) > 15) {
168 0 : return ndr_push_error(ndr, NDR_ERR_STRING,
169 : "nbt_name longer as 15 chars: %s",
170 : r->name);
171 : }
172 :
173 11734 : cname = compress_name(ndr, (const uint8_t *)r->name, r->type);
174 11734 : NDR_ERR_HAVE_NO_MEMORY(cname);
175 :
176 11734 : if (r->scope) {
177 239 : fullname = (uint8_t *)talloc_asprintf(ndr, "%s.%s", cname, r->scope);
178 239 : NDR_ERR_HAVE_NO_MEMORY(fullname);
179 239 : talloc_free(cname);
180 : } else {
181 11495 : fullname = cname;
182 : }
183 :
184 11734 : ndr_err = ndr_push_nbt_string(ndr, ndr_flags, (const char *)fullname);
185 :
186 11734 : return ndr_err;
187 : }
188 :
189 :
190 : /**
191 : copy a nbt name structure
192 : */
193 101020 : _PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx,
194 : const struct nbt_name *name,
195 : struct nbt_name *newname)
196 : {
197 101020 : *newname = *name;
198 101020 : newname->name = talloc_strdup(mem_ctx, newname->name);
199 101020 : NT_STATUS_HAVE_NO_MEMORY(newname->name);
200 101020 : newname->scope = talloc_strdup(mem_ctx, newname->scope);
201 101020 : if (name->scope) {
202 9 : NT_STATUS_HAVE_NO_MEMORY(newname->scope);
203 : }
204 101020 : return NT_STATUS_OK;
205 : }
206 :
207 : /**
208 : push a nbt name into a blob
209 : */
210 0 : _PUBLIC_ NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name)
211 : {
212 : enum ndr_err_code ndr_err;
213 :
214 0 : ndr_err = ndr_push_struct_blob(blob, mem_ctx, name, (ndr_push_flags_fn_t)ndr_push_nbt_name);
215 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
216 0 : return ndr_map_error2ntstatus(ndr_err);
217 : }
218 :
219 0 : return NT_STATUS_OK;
220 : }
221 :
222 : /**
223 : pull a nbt name from a blob
224 : */
225 18 : _PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name)
226 : {
227 : enum ndr_err_code ndr_err;
228 :
229 18 : ndr_err = ndr_pull_struct_blob(blob, mem_ctx, name,
230 : (ndr_pull_flags_fn_t)ndr_pull_nbt_name);
231 18 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
232 0 : return ndr_map_error2ntstatus(ndr_err);
233 : }
234 :
235 18 : return NT_STATUS_OK;
236 : }
237 :
238 :
239 : /**
240 : choose a name to use when calling a server in a NBT session request.
241 : we use heuristics to see if the name we have been given is a IP
242 : address, or a too-long name. If it is then use *SMBSERVER, or a
243 : truncated name
244 : */
245 8936 : _PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx,
246 : struct nbt_name *n, const char *name, int type)
247 : {
248 8936 : n->scope = NULL;
249 8936 : n->type = type;
250 :
251 8936 : if ((name == NULL) || is_ipaddress(name)) {
252 141 : n->name = "*SMBSERVER";
253 141 : return;
254 : }
255 8795 : if (strlen(name) > 15) {
256 190 : const char *p = strchr(name, '.');
257 : char *s;
258 190 : if (p - name > 15) {
259 0 : n->name = "*SMBSERVER";
260 0 : return;
261 : }
262 190 : s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
263 190 : n->name = talloc_strdup_upper(mem_ctx, s);
264 190 : return;
265 : }
266 :
267 8605 : n->name = talloc_strdup_upper(mem_ctx, name);
268 : }
269 :
270 :
271 : /*
272 : escape a string into a form containing only a small set of characters,
273 : the rest is hex encoded. This is similar to URL encoding
274 : */
275 527 : static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
276 : {
277 : int i, len;
278 : char *ret;
279 527 : const char *valid_chars = "_-.$@ ";
280 : #define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c))
281 :
282 6345 : for (len=i=0;s[i];i++,len++) {
283 5818 : if (!NBT_CHAR_ALLOW(s[i])) {
284 10 : len += 2;
285 : }
286 : }
287 :
288 527 : ret = talloc_array(mem_ctx, char, len+1);
289 527 : if (ret == NULL) return NULL;
290 :
291 6345 : for (len=i=0;s[i];i++) {
292 5818 : if (NBT_CHAR_ALLOW(s[i])) {
293 5808 : ret[len++] = s[i];
294 : } else {
295 10 : snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]);
296 10 : len += 3;
297 : }
298 : }
299 527 : ret[len] = 0;
300 :
301 527 : return ret;
302 : }
303 :
304 :
305 : /**
306 : form a string for a NBT name
307 : */
308 507 : _PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
309 : {
310 507 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
311 : char *ret;
312 507 : if (name->scope) {
313 40 : ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
314 0 : nbt_hex_encode(tmp_ctx, name->name),
315 20 : name->type,
316 0 : nbt_hex_encode(tmp_ctx, name->scope));
317 : } else {
318 487 : ret = talloc_asprintf(mem_ctx, "%s<%02x>",
319 90 : nbt_hex_encode(tmp_ctx, name->name),
320 487 : name->type);
321 : }
322 507 : talloc_free(tmp_ctx);
323 507 : return ret;
324 : }
325 :
326 : /**
327 : pull a nbt name, WINS Replication uses another on wire format for nbt name
328 : */
329 1202 : _PUBLIC_ enum ndr_err_code ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name **_r)
330 : {
331 : struct nbt_name *r;
332 : uint8_t *namebuf;
333 : uint32_t namebuf_len;
334 :
335 1202 : if (!(ndr_flags & NDR_SCALARS)) {
336 0 : return NDR_ERR_SUCCESS;
337 : }
338 :
339 1202 : NDR_CHECK(ndr_pull_align(ndr, 4));
340 1202 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &namebuf_len));
341 1202 : if (namebuf_len < 1 || namebuf_len > 255) {
342 0 : return ndr_pull_error(ndr, NDR_ERR_ALLOC, "value out of range");
343 : }
344 1202 : NDR_PULL_ALLOC_N(ndr, namebuf, namebuf_len);
345 1202 : NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
346 :
347 1202 : if ((namebuf_len % 4) == 0) {
348 : /*
349 : * [MS-WINSRA] — v20091104 was wrong
350 : * regarding section "2.2.10.1 Name Record"
351 : *
352 : * If the name buffer is already 4 byte aligned
353 : * Windows (at least 2003 SP1 and 2008) add 4 extra
354 : * bytes. This can happen when the name has a scope.
355 : */
356 : uint32_t pad;
357 46 : NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &pad));
358 : }
359 :
360 1202 : NDR_PULL_ALLOC(ndr, r);
361 :
362 : /* oh wow, what a nasty bug in windows ... */
363 1202 : if (namebuf[0] == 0x1b && namebuf_len >= 16) {
364 0 : namebuf[0] = namebuf[15];
365 0 : namebuf[15] = 0x1b;
366 : }
367 :
368 1202 : if (namebuf_len < 17) {
369 0 : r->type = 0x00;
370 :
371 0 : r->name = talloc_strndup(r, (char *)namebuf, namebuf_len);
372 0 : if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
373 :
374 0 : r->scope= NULL;
375 :
376 0 : talloc_free(namebuf);
377 0 : *_r = r;
378 0 : return NDR_ERR_SUCCESS;
379 : }
380 :
381 1202 : r->type = namebuf[15];
382 :
383 1202 : namebuf[15] = '\0';
384 1202 : trim_string((char *)namebuf, NULL, " ");
385 1202 : r->name = talloc_strdup(r, (char *)namebuf);
386 1202 : if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
387 :
388 1202 : if (namebuf_len > 17) {
389 253 : r->scope = talloc_strndup(r, (char *)(namebuf+16), namebuf_len-17);
390 253 : if (!r->scope) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
391 : } else {
392 949 : r->scope = NULL;
393 : }
394 :
395 1202 : talloc_free(namebuf);
396 1202 : *_r = r;
397 1202 : return NDR_ERR_SUCCESS;
398 : }
399 :
400 : /**
401 : push a nbt name, WINS Replication uses another on wire format for nbt name
402 : */
403 2404 : _PUBLIC_ enum ndr_err_code ndr_push_wrepl_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r)
404 : {
405 : uint8_t *namebuf;
406 : uint32_t namebuf_len;
407 : uint32_t _name_len;
408 2404 : uint32_t scope_len = 0;
409 :
410 2404 : if (r == NULL) {
411 0 : return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER,
412 : "wrepl_nbt_name NULL pointer");
413 : }
414 :
415 2404 : if (!(ndr_flags & NDR_SCALARS)) {
416 0 : return NDR_ERR_SUCCESS;
417 : }
418 :
419 2404 : _name_len = strlen(r->name);
420 2404 : if (_name_len > 15) {
421 0 : return ndr_push_error(ndr, NDR_ERR_STRING,
422 : "wrepl_nbt_name longer as 15 chars: %s",
423 : r->name);
424 : }
425 :
426 2404 : if (r->scope) {
427 506 : scope_len = strlen(r->scope);
428 : }
429 2404 : if (scope_len > 238) {
430 0 : return ndr_push_error(ndr, NDR_ERR_STRING,
431 : "wrepl_nbt_name scope longer as 238 chars: %s",
432 : r->scope);
433 : }
434 :
435 2404 : namebuf = (uint8_t *)talloc_asprintf(ndr, "%-15s%c%s",
436 0 : r->name, 'X',
437 2404 : (r->scope?r->scope:""));
438 2404 : if (!namebuf) return ndr_push_error(ndr, NDR_ERR_ALLOC, "out of memory");
439 :
440 2404 : namebuf_len = strlen((char *)namebuf) + 1;
441 :
442 : /*
443 : * we need to set the type here, and use a place-holder in the talloc_asprintf()
444 : * as the type can be 0x00, and then the namebuf_len = strlen(namebuf); would give wrong results
445 : */
446 2404 : namebuf[15] = r->type;
447 :
448 : /* oh wow, what a nasty bug in windows ... */
449 2404 : if (r->type == 0x1b) {
450 0 : namebuf[15] = namebuf[0];
451 0 : namebuf[0] = 0x1b;
452 : }
453 :
454 2404 : NDR_CHECK(ndr_push_align(ndr, 4));
455 2404 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, namebuf_len));
456 2404 : NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
457 :
458 2404 : if ((namebuf_len % 4) == 0) {
459 : /*
460 : * [MS-WINSRA] — v20091104 was wrong
461 : * regarding section "2.2.10.1 Name Record"
462 : *
463 : * If the name buffer is already 4 byte aligned
464 : * Windows (at least 2003 SP1 and 2008) add 4 extra
465 : * bytes. This can happen when the name has a scope.
466 : */
467 92 : NDR_CHECK(ndr_push_zero(ndr, 4));
468 : }
469 :
470 2404 : talloc_free(namebuf);
471 2404 : return NDR_ERR_SUCCESS;
472 : }
473 :
474 0 : _PUBLIC_ void ndr_print_wrepl_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r)
475 : {
476 0 : char *s = nbt_name_string(ndr, r);
477 0 : ndr_print_string(ndr, name, s);
478 0 : talloc_free(s);
479 0 : }
480 :
481 3014 : _PUBLIC_ enum ndr_err_code ndr_push_nbt_res_rec(struct ndr_push *ndr, int ndr_flags, const struct nbt_res_rec *r)
482 : {
483 : {
484 3014 : uint32_t _flags_save_STRUCT = ndr->flags;
485 3014 : ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
486 3014 : if (ndr_flags & NDR_SCALARS) {
487 3014 : NDR_CHECK(ndr_push_align(ndr, 4));
488 3014 : NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->name));
489 3014 : NDR_CHECK(ndr_push_nbt_qtype(ndr, NDR_SCALARS, r->rr_type));
490 3014 : NDR_CHECK(ndr_push_nbt_qclass(ndr, NDR_SCALARS, r->rr_class));
491 3014 : NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl));
492 3014 : NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata, ((((r->rr_type) == NBT_QTYPE_NETBIOS) && ((r->rdata).data.length == 2))?0:r->rr_type)));
493 3014 : NDR_CHECK(ndr_push_nbt_rdata(ndr, NDR_SCALARS, &r->rdata));
494 : }
495 3014 : if (ndr_flags & NDR_BUFFERS) {
496 : }
497 3014 : ndr->flags = _flags_save_STRUCT;
498 : }
499 3014 : return NDR_ERR_SUCCESS;
500 : }
|