Coverage Report

Created: 2026-06-07 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/libcli/nbt/nbtname.c
Line
Count
Source
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
static bool decompress_name(char *name, enum nbt_name_type *type)
37
271k
{
38
271k
  int i;
39
299k
  for (i=0;name[2*i];i++) {
40
28.6k
    uint8_t c1 = name[2*i];
41
28.6k
    uint8_t c2 = name[1+(2*i)];
42
28.6k
    if (c1 < 'A' || c1 > 'P' ||
43
28.6k
        c2 < 'A' || c2 > 'P') {
44
89
      return false;
45
89
    }
46
28.5k
    name[i] = ((c1-'A')<<4) | (c2-'A');
47
28.5k
  }
48
270k
  name[i] = 0;
49
270k
  if (i == 16) {
50
1.74k
    *type = (enum nbt_name_type)(name[15]);
51
1.74k
    name[15] = 0;
52
1.74k
    i--;
53
269k
  } else {
54
269k
    *type = NBT_NAME_CLIENT;
55
269k
  }
56
57
  /* trim trailing spaces */
58
272k
  for (;i>0 && name[i-1]==' ';i--) {
59
1.43k
    name[i-1] = 0;
60
1.43k
  }
61
62
270k
  return true;
63
271k
}
64
65
66
/*
67
  compress a name component
68
 */
69
static uint8_t *compress_name(TALLOC_CTX *mem_ctx,
70
            const uint8_t *name, enum nbt_name_type type)
71
136k
{
72
136k
  uint8_t *cname;
73
136k
  int i;
74
136k
  uint8_t pad_char;
75
76
136k
  if (strlen((const char *)name) > 15) {
77
0
    return NULL;
78
0
  }
79
80
136k
  cname = talloc_array(mem_ctx, uint8_t, 33);
81
136k
  if (cname == NULL) return NULL;
82
83
158k
  for (i=0;name[i];i++) {
84
21.2k
    cname[2*i]   = 'A' + (name[i]>>4);
85
21.2k
    cname[1+2*i] = 'A' + (name[i]&0xF);
86
21.2k
  }
87
136k
  if (strcmp((const char *)name, "*") == 0) {
88
42
    pad_char = 0;
89
136k
  } else {
90
136k
    pad_char = ' ';
91
136k
  }
92
2.16M
  for (;i<15;i++) {
93
2.03M
    cname[2*i]   = 'A' + (pad_char>>4);
94
2.03M
    cname[1+2*i] = 'A' + (pad_char&0xF);
95
2.03M
  }
96
97
136k
  pad_char = type;
98
136k
  cname[2*i]   = 'A' + (pad_char>>4);
99
136k
  cname[1+2*i] = 'A' + (pad_char&0xF);
100
101
136k
  cname[32] = 0;
102
136k
  return cname;
103
136k
}
104
105
106
/**
107
  pull a nbt name from the wire
108
*/
109
_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct nbt_name *r)
110
271k
{
111
271k
  char *scope;
112
271k
  char *cname;
113
271k
  const char *s;
114
271k
  bool ok;
115
116
271k
  if (!(ndr_flags & NDR_SCALARS)) {
117
0
    return NDR_ERR_SUCCESS;
118
0
  }
119
120
271k
  NDR_CHECK(ndr_pull_nbt_string(ndr, ndr_flags, &s));
121
271k
  cname = discard_const_p(char, s);
122
123
271k
  scope = strchr(cname, '.');
124
271k
  if (scope) {
125
667
    *scope = 0;
126
667
    r->scope = talloc_strdup(ndr->current_mem_ctx, &scope[1]);
127
667
    NDR_ERR_HAVE_NO_MEMORY(r->scope);
128
270k
  } else {
129
270k
    r->scope = NULL;
130
270k
  }
131
132
  /* the first component is limited to 16 bytes in the DOS charset,
133
     which is 32 in the 'compressed' form */
134
271k
  if (strlen(cname) > 32) {
135
11
    return ndr_pull_error(ndr, NDR_ERR_STRING,
136
11
              "NBT NAME cname > 32");
137
11
  }
138
139
  /* decompress the first component */
140
271k
  ok = decompress_name(cname, &r->type);
141
271k
  if (!ok) {
142
89
    return ndr_pull_error(ndr, NDR_ERR_STRING,
143
89
              "NBT NAME failed to decompress");
144
89
  }
145
146
270k
  r->name = talloc_strdup(ndr->current_mem_ctx, cname);
147
270k
  NDR_ERR_HAVE_NO_MEMORY(r->name);
148
149
270k
  talloc_free(cname);
150
151
270k
  return NDR_ERR_SUCCESS;
152
270k
}
153
154
/**
155
  push a nbt name to the wire
156
*/
157
_PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct nbt_name *r)
158
136k
{
159
136k
  uint8_t *cname, *fullname;
160
136k
  enum ndr_err_code ndr_err;
161
162
136k
  if (!(ndr_flags & NDR_SCALARS)) {
163
0
    return NDR_ERR_SUCCESS;
164
0
  }
165
166
136k
  if (strlen(r->name) > 15) {
167
0
    return ndr_push_error(ndr, NDR_ERR_STRING,
168
0
              "nbt_name longer as 15 chars: %s",
169
0
              r->name);
170
0
  }
171
172
136k
  cname = compress_name(ndr, (const uint8_t *)r->name, r->type);
173
136k
  NDR_ERR_HAVE_NO_MEMORY(cname);
174
175
136k
  if (r->scope) {
176
473
    fullname = (uint8_t *)talloc_asprintf(ndr, "%s.%s", cname, r->scope);
177
473
    NDR_ERR_HAVE_NO_MEMORY(fullname);
178
473
    talloc_free(cname);
179
136k
  } else {
180
136k
    fullname = cname;
181
136k
  }
182
183
136k
  ndr_err = ndr_push_nbt_string(ndr, ndr_flags, (const char *)fullname);
184
185
136k
  return ndr_err;
186
136k
}
187
188
189
/**
190
  copy a nbt name structure
191
*/
192
_PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx,
193
             const struct nbt_name *name,
194
             struct nbt_name *newname)
195
0
{
196
0
  *newname = *name;
197
0
  newname->name = talloc_strdup(mem_ctx, newname->name);
198
0
  NT_STATUS_HAVE_NO_MEMORY(newname->name);
199
0
  newname->scope = talloc_strdup(mem_ctx, newname->scope);
200
0
  if (name->scope) {
201
0
    NT_STATUS_HAVE_NO_MEMORY(newname->scope);
202
0
  }
203
0
  return NT_STATUS_OK;
204
0
}
205
206
/**
207
  push a nbt name into a blob
208
*/
209
_PUBLIC_ NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name)
210
0
{
211
0
  enum ndr_err_code ndr_err;
212
213
0
  ndr_err = ndr_push_struct_blob(blob, mem_ctx, name, (ndr_push_flags_fn_t)ndr_push_nbt_name);
214
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
215
0
    return ndr_map_error2ntstatus(ndr_err);
216
0
  }
217
218
0
  return NT_STATUS_OK;
219
0
}
220
221
/**
222
  pull a nbt name from a blob
223
*/
224
_PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name)
225
0
{
226
0
  enum ndr_err_code ndr_err;
227
228
0
  ndr_err = ndr_pull_struct_blob(blob, mem_ctx, name,
229
0
               (ndr_pull_flags_fn_t)ndr_pull_nbt_name);
230
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
231
0
    return ndr_map_error2ntstatus(ndr_err);
232
0
  }
233
234
0
  return NT_STATUS_OK;
235
0
}
236
237
238
/**
239
  choose a name to use when calling a server in a NBT session request.
240
  we use heuristics to see if the name we have been given is a IP
241
  address, or a too-long name. If it is then use *SMBSERVER, or a
242
  truncated name
243
*/
244
_PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx,
245
          struct nbt_name *n, const char *name, int type)
246
0
{
247
0
  n->scope = NULL;
248
0
  n->type = type;
249
250
0
  if ((name == NULL) || is_ipaddress(name)) {
251
0
    n->name = "*SMBSERVER";
252
0
    return;
253
0
  }
254
0
  if (strlen(name) > 15) {
255
0
    const char *p = strchr(name, '.');
256
0
    char *s;
257
0
    if (p - name > 15) {
258
0
      n->name = "*SMBSERVER";
259
0
      return;
260
0
    }
261
0
    s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
262
0
    n->name = talloc_strdup_upper(mem_ctx, s);
263
0
    return;
264
0
  }
265
266
0
  n->name = talloc_strdup_upper(mem_ctx, name);
267
0
}
268
269
270
/*
271
  escape a string into a form containing only a small set of characters,
272
  the rest is hex encoded. This is similar to URL encoding
273
*/
274
static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
275
9.93k
{
276
9.93k
  int i, len;
277
9.93k
  char *ret;
278
9.93k
  const char *valid_chars = "_-.$@ ";
279
36.5k
#define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c))
280
281
28.2k
  for (len=i=0;s[i];i++,len++) {
282
18.2k
    if (!NBT_CHAR_ALLOW(s[i])) {
283
15.9k
      len += 2;
284
15.9k
    }
285
18.2k
  }
286
287
9.93k
  ret = talloc_array(mem_ctx, char, len+1);
288
9.93k
  if (ret == NULL) return NULL;
289
290
28.2k
  for (len=i=0;s[i];i++) {
291
18.2k
    if (NBT_CHAR_ALLOW(s[i])) {
292
2.38k
      ret[len++] = s[i];
293
15.9k
    } else {
294
15.9k
      snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]);
295
15.9k
      len += 3;
296
15.9k
    }
297
18.2k
  }
298
9.93k
  ret[len] = 0;
299
300
9.93k
  return ret;
301
9.93k
}
302
303
304
/**
305
  form a string for a NBT name
306
*/
307
_PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
308
8.93k
{
309
8.93k
  TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
310
8.93k
  char *ret;
311
8.93k
  if (name->scope) {
312
1.00k
    ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
313
1.00k
              nbt_hex_encode(tmp_ctx, name->name),
314
1.00k
              name->type,
315
1.00k
              nbt_hex_encode(tmp_ctx, name->scope));
316
7.92k
  } else {
317
7.92k
    ret = talloc_asprintf(mem_ctx, "%s<%02x>",
318
7.92k
              nbt_hex_encode(tmp_ctx, name->name),
319
7.92k
              name->type);
320
7.92k
  }
321
8.93k
  talloc_free(tmp_ctx);
322
8.93k
  return ret;
323
8.93k
}
324
325
/**
326
  pull a nbt name, WINS Replication uses another on wire format for nbt name
327
*/
328
_PUBLIC_ enum ndr_err_code ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct nbt_name **_r)
329
60.2k
{
330
60.2k
  struct nbt_name *r;
331
60.2k
  uint8_t *namebuf;
332
60.2k
  uint32_t namebuf_len;
333
334
60.2k
  if (!(ndr_flags & NDR_SCALARS)) {
335
0
    return NDR_ERR_SUCCESS;
336
0
  }
337
338
60.2k
  NDR_CHECK(ndr_pull_align(ndr, 4));
339
60.2k
  NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &namebuf_len));
340
60.2k
  if (namebuf_len < 1 || namebuf_len > 255) {
341
59
    return ndr_pull_error(ndr, NDR_ERR_ALLOC, "value (%"PRIu32") out of range (1 - 255)", namebuf_len);
342
59
  }
343
60.1k
  NDR_PULL_ALLOC_N(ndr, namebuf, namebuf_len);
344
60.1k
  NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
345
346
60.1k
  if ((namebuf_len % 4) == 0) {
347
    /*
348
     * [MS-WINSRA] — v20091104 was wrong
349
     * regarding section "2.2.10.1 Name Record"
350
     *
351
     * If the name buffer is already 4 byte aligned
352
     * Windows (at least 2003 SP1 and 2008) add 4 extra
353
     * bytes. This can happen when the name has a scope.
354
     */
355
10.4k
    uint32_t pad;
356
10.4k
    NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &pad));
357
10.4k
  }
358
359
60.1k
  NDR_PULL_ALLOC(ndr, r);
360
361
  /* oh wow, what a nasty bug in windows ... */
362
60.1k
  if (namebuf[0] == 0x1b && namebuf_len >= 16) {
363
1.12k
    namebuf[0] = namebuf[15];
364
1.12k
    namebuf[15] = 0x1b;
365
1.12k
  }
366
367
60.1k
  if (namebuf_len < 17) {
368
42.5k
    r->type = 0x00;
369
370
42.5k
    r->name = talloc_strndup(r, (char *)namebuf, namebuf_len);
371
42.5k
    if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
372
373
42.5k
    r->scope= NULL;
374
375
42.5k
    talloc_free(namebuf);
376
42.5k
    *_r = r;
377
42.5k
    return NDR_ERR_SUCCESS;
378
42.5k
  }
379
380
17.6k
  r->type = namebuf[15];
381
382
17.6k
  namebuf[15] = '\0';
383
17.6k
  trim_string((char *)namebuf, NULL, " ");
384
17.6k
  r->name = talloc_strdup(r, (char *)namebuf);
385
17.6k
  if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
386
387
17.6k
  if (namebuf_len > 17) {
388
17.0k
    r->scope = talloc_strndup(r, (char *)(namebuf+16), namebuf_len-17);
389
17.0k
    if (!r->scope) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
390
17.0k
  } else {
391
605
    r->scope = NULL;
392
605
  }
393
394
17.6k
  talloc_free(namebuf);
395
17.6k
  *_r = r;
396
17.6k
  return NDR_ERR_SUCCESS;
397
17.6k
}
398
399
/**
400
  push a nbt name, WINS Replication uses another on wire format for nbt name
401
*/
402
_PUBLIC_ enum ndr_err_code ndr_push_wrepl_nbt_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct nbt_name *r)
403
14.7k
{
404
14.7k
  uint8_t *namebuf;
405
14.7k
  uint32_t namebuf_len;
406
14.7k
  uint32_t _name_len;
407
14.7k
  uint32_t scope_len = 0;
408
409
14.7k
  if (r == NULL) {
410
0
    return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER,
411
0
              "wrepl_nbt_name NULL pointer");
412
0
  }
413
414
14.7k
  if (!(ndr_flags & NDR_SCALARS)) {
415
0
    return NDR_ERR_SUCCESS;
416
0
  }
417
418
14.7k
  _name_len = strlen(r->name);
419
14.7k
  if (_name_len > 15) {
420
4
    return ndr_push_error(ndr, NDR_ERR_STRING,
421
4
              "wrepl_nbt_name longer as 15 chars: %s",
422
4
              r->name);
423
4
  }
424
425
14.7k
  if (r->scope) {
426
1.58k
    scope_len = strlen(r->scope);
427
1.58k
  }
428
14.7k
  if (scope_len > 238) {
429
0
    return ndr_push_error(ndr, NDR_ERR_STRING,
430
0
              "wrepl_nbt_name scope longer as 238 chars: %s",
431
0
              r->scope);
432
0
  }
433
434
14.7k
  namebuf = (uint8_t *)talloc_asprintf(ndr, "%-15s%c%s",
435
14.7k
               r->name, 'X',
436
14.7k
               (r->scope?r->scope:""));
437
14.7k
  if (!namebuf) return ndr_push_error(ndr, NDR_ERR_ALLOC, "out of memory");
438
439
14.7k
  namebuf_len = strlen((char *)namebuf) + 1;
440
441
  /*
442
   * we need to set the type here, and use a place-holder in the talloc_asprintf()
443
   * as the type can be 0x00, and then the namebuf_len = strlen(namebuf); would give wrong results
444
   */
445
14.7k
  namebuf[15] = r->type;
446
447
  /* oh wow, what a nasty bug in windows ... */
448
14.7k
  if (r->type == 0x1b) {
449
929
    namebuf[15] = namebuf[0];
450
929
    namebuf[0] = 0x1b;
451
929
  }
452
453
14.7k
  NDR_CHECK(ndr_push_align(ndr, 4));
454
14.7k
  NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, namebuf_len));
455
14.7k
  NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
456
457
14.7k
  if ((namebuf_len % 4) == 0) {
458
    /*
459
     * [MS-WINSRA] — v20091104 was wrong
460
     * regarding section "2.2.10.1 Name Record"
461
     *
462
     * If the name buffer is already 4 byte aligned
463
     * Windows (at least 2003 SP1 and 2008) add 4 extra
464
     * bytes. This can happen when the name has a scope.
465
     */
466
436
    NDR_CHECK(ndr_push_zero(ndr, 4));
467
436
  }
468
469
14.7k
  talloc_free(namebuf);
470
14.7k
  return NDR_ERR_SUCCESS;
471
14.7k
}
472
473
_PUBLIC_ void ndr_print_wrepl_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r)
474
8.93k
{
475
8.93k
  char *s = nbt_name_string(ndr, r);
476
8.93k
  ndr_print_string(ndr, name, s);
477
8.93k
  talloc_free(s);
478
8.93k
}
479
480
_PUBLIC_ enum ndr_err_code ndr_push_nbt_qtype(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum nbt_qtype r)
481
127k
{
482
  /* For WACK replies, we need to send NBT_QTYPE_NETBIOS on the wire. */
483
127k
  NDR_CHECK(ndr_push_enum_uint16(ndr, NDR_SCALARS, (r == NBT_QTYPE_WACK) ? NBT_QTYPE_NETBIOS : r));
484
127k
  return NDR_ERR_SUCCESS;
485
127k
}