LCOV - code coverage report
Current view: top level - libcli/nbt - nbtname.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 176 224 78.6 %
Date: 2024-04-13 12:30:31 Functions: 12 14 85.7 %

          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       20213 : static bool decompress_name(char *name, enum nbt_name_type *type)
      37             : {
      38         197 :         int i;
      39      343621 :         for (i=0;name[2*i];i++) {
      40      323408 :                 uint8_t c1 = name[2*i];
      41      323408 :                 uint8_t c2 = name[1+(2*i)];
      42      323408 :                 if (c1 < 'A' || c1 > 'P' ||
      43      323408 :                     c2 < 'A' || c2 > 'P') {
      44           0 :                         return false;
      45             :                 }
      46      323408 :                 name[i] = ((c1-'A')<<4) | (c2-'A');
      47             :         }
      48       20213 :         name[i] = 0;
      49       20213 :         if (i == 16) {
      50       20213 :                 *type = (enum nbt_name_type)(name[15]);
      51       20213 :                 name[15] = 0;
      52       20213 :                 i--;
      53             :         } else {
      54           0 :                 *type = NBT_NAME_CLIENT;
      55             :         }
      56             : 
      57             :         /* trim trailing spaces */
      58      131466 :         for (;i>0 && name[i-1]==' ';i--) {
      59      111253 :                 name[i-1] = 0;
      60             :         }
      61             : 
      62       20016 :         return true;
      63             : }
      64             : 
      65             : 
      66             : /*
      67             :   compress a name component
      68             :  */
      69       14681 : static uint8_t *compress_name(TALLOC_CTX *mem_ctx,
      70             :                               const uint8_t *name, enum nbt_name_type type)
      71             : {
      72         125 :         uint8_t *cname;
      73         125 :         int i;
      74         125 :         uint8_t pad_char;
      75             : 
      76       14681 :         if (strlen((const char *)name) > 15) {
      77           0 :                 return NULL;
      78             :         }
      79             : 
      80       14681 :         cname = talloc_array(mem_ctx, uint8_t, 33);
      81       14681 :         if (cname == NULL) return NULL;
      82             : 
      83      131705 :         for (i=0;name[i];i++) {
      84      117024 :                 cname[2*i]   = 'A' + (name[i]>>4);
      85      117024 :                 cname[1+2*i] = 'A' + (name[i]&0xF);
      86             :         }
      87       14681 :         if (strcmp((const char *)name, "*") == 0) {
      88         133 :                 pad_char = 0;
      89             :         } else {
      90       14673 :                 pad_char = ' ';
      91             :         }
      92      117872 :         for (;i<15;i++) {
      93      103191 :                 cname[2*i]   = 'A' + (pad_char>>4);
      94      103191 :                 cname[1+2*i] = 'A' + (pad_char&0xF);
      95             :         }
      96             : 
      97       14681 :         pad_char = type;
      98       14681 :         cname[2*i]   = 'A' + (pad_char>>4);
      99       14681 :         cname[1+2*i] = 'A' + (pad_char&0xF);
     100             : 
     101       14681 :         cname[32] = 0;
     102       14681 :         return cname;
     103             : }
     104             : 
     105             : 
     106             : /**
     107             :   pull a nbt name from the wire
     108             : */
     109       20213 : _PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct nbt_name *r)
     110             : {
     111         197 :         uint8_t *scope;
     112         197 :         char *cname;
     113         197 :         const char *s;
     114         197 :         bool ok;
     115             : 
     116       20213 :         if (!(ndr_flags & NDR_SCALARS)) {
     117           0 :                 return NDR_ERR_SUCCESS;
     118             :         }
     119             : 
     120       20213 :         NDR_CHECK(ndr_pull_nbt_string(ndr, ndr_flags, &s));
     121             : 
     122       20213 :         scope = (uint8_t *)strchr(s, '.');
     123       20213 :         if (scope) {
     124         255 :                 *scope = 0;
     125         255 :                 r->scope = talloc_strdup(ndr->current_mem_ctx, (const char *)&scope[1]);
     126         255 :                 NDR_ERR_HAVE_NO_MEMORY(r->scope);
     127             :         } else {
     128       19958 :                 r->scope = NULL;
     129             :         }
     130             : 
     131       20213 :         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       20213 :         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       20213 :         ok = decompress_name(cname, &r->type);
     142       20213 :         if (!ok) {
     143           0 :                 return ndr_pull_error(ndr, NDR_ERR_STRING,
     144             :                                       "NBT NAME failed to decompress");
     145             :         }
     146             : 
     147       20213 :         r->name = talloc_strdup(ndr->current_mem_ctx, cname);
     148       20213 :         NDR_ERR_HAVE_NO_MEMORY(r->name);
     149             : 
     150       20213 :         talloc_free(cname);
     151             : 
     152       20213 :         return NDR_ERR_SUCCESS;
     153             : }
     154             : 
     155             : /**
     156             :   push a nbt name to the wire
     157             : */
     158       14681 : _PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct nbt_name *r)
     159             : {
     160         125 :         uint8_t *cname, *fullname;
     161         125 :         enum ndr_err_code ndr_err;
     162             : 
     163       14681 :         if (!(ndr_flags & NDR_SCALARS)) {
     164           0 :                 return NDR_ERR_SUCCESS;
     165             :         }
     166             : 
     167       14681 :         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       14681 :         cname = compress_name(ndr, (const uint8_t *)r->name, r->type);
     174       14681 :         NDR_ERR_HAVE_NO_MEMORY(cname);
     175             : 
     176       14681 :         if (r->scope) {
     177         255 :                 fullname = (uint8_t *)talloc_asprintf(ndr, "%s.%s", cname, r->scope);
     178         255 :                 NDR_ERR_HAVE_NO_MEMORY(fullname);
     179         255 :                 talloc_free(cname);
     180             :         } else {
     181       14301 :                 fullname = cname;
     182             :         }
     183             : 
     184       14681 :         ndr_err = ndr_push_nbt_string(ndr, ndr_flags, (const char *)fullname);
     185             : 
     186       14681 :         return ndr_err;
     187             : }
     188             : 
     189             : 
     190             : /**
     191             :   copy a nbt name structure
     192             : */
     193      158669 : _PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx,
     194             :                                const struct nbt_name *name,
     195             :                                struct nbt_name *newname)
     196             : {
     197      158669 :         *newname = *name;
     198      158669 :         newname->name = talloc_strdup(mem_ctx, newname->name);
     199      158669 :         NT_STATUS_HAVE_NO_MEMORY(newname->name);
     200      158669 :         newname->scope = talloc_strdup(mem_ctx, newname->scope);
     201      158669 :         if (name->scope) {
     202          33 :                 NT_STATUS_HAVE_NO_MEMORY(newname->scope);
     203             :         }
     204      158669 :         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           0 :         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          12 : _PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name)
     226             : {
     227           0 :         enum ndr_err_code ndr_err;
     228             : 
     229          12 :         ndr_err = ndr_pull_struct_blob(blob, mem_ctx, name,
     230             :                                        (ndr_pull_flags_fn_t)ndr_pull_nbt_name);
     231          12 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     232           0 :                 return ndr_map_error2ntstatus(ndr_err);
     233             :         }
     234             : 
     235          12 :         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       22313 : _PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx,
     246             :                             struct nbt_name *n, const char *name, int type)
     247             : {
     248       22313 :         n->scope = NULL;
     249       22313 :         n->type = type;
     250             : 
     251       22313 :         if ((name == NULL) || is_ipaddress(name)) {
     252        6065 :                 n->name = "*SMBSERVER";
     253        6065 :                 return;
     254             :         }
     255       16248 :         if (strlen(name) > 15) {
     256         523 :                 const char *p = strchr(name, '.');
     257           0 :                 char *s;
     258         523 :                 if (p - name > 15) {
     259           0 :                         n->name = "*SMBSERVER";
     260           0 :                         return;
     261             :                 }
     262         523 :                 s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
     263         523 :                 n->name = talloc_strdup_upper(mem_ctx, s);
     264         523 :                 return;
     265             :         }
     266             : 
     267       15725 :         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         600 : static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
     276             : {
     277          13 :         int i, len;
     278          13 :         char *ret;
     279         600 :         const char *valid_chars = "_-.$@ ";
     280             : #define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c))
     281             : 
     282        7122 :         for (len=i=0;s[i];i++,len++) {
     283        6522 :                 if (!NBT_CHAR_ALLOW(s[i])) {
     284          10 :                         len += 2;
     285             :                 }
     286             :         }
     287             : 
     288         600 :         ret = talloc_array(mem_ctx, char, len+1);
     289         600 :         if (ret == NULL) return NULL;
     290             : 
     291        7122 :         for (len=i=0;s[i];i++) {
     292        6522 :                 if (NBT_CHAR_ALLOW(s[i])) {
     293        6512 :                         ret[len++] = s[i];
     294             :                 } else {
     295          10 :                         snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]);
     296          10 :                         len += 3;
     297             :                 }
     298             :         }
     299         600 :         ret[len] = 0;
     300             : 
     301         600 :         return ret;
     302             : }
     303             : 
     304             : 
     305             : /**
     306             :   form a string for a NBT name
     307             : */
     308         580 : _PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
     309             : {
     310         580 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     311          13 :         char *ret;
     312         580 :         if (name->scope) {
     313          20 :                 ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
     314          20 :                                       nbt_hex_encode(tmp_ctx, name->name),
     315          20 :                                       name->type,
     316          20 :                                       nbt_hex_encode(tmp_ctx, name->scope));
     317             :         } else {
     318         560 :                 ret = talloc_asprintf(mem_ctx, "%s<%02x>",
     319         560 :                                       nbt_hex_encode(tmp_ctx, name->name),
     320         560 :                                       name->type);
     321             :         }
     322         580 :         talloc_free(tmp_ctx);
     323         580 :         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, ndr_flags_type ndr_flags, struct nbt_name **_r)
     330             : {
     331           0 :         struct nbt_name *r;
     332           0 :         uint8_t *namebuf;
     333           0 :         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 (%"PRIu32") out of range (1 - 255)", namebuf_len);
     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           0 :                 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, ndr_flags_type ndr_flags, const struct nbt_name *r)
     404             : {
     405           0 :         uint8_t *namebuf;
     406           0 :         uint32_t namebuf_len;
     407           0 :         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        2404 :                                              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       14514 : _PUBLIC_ enum ndr_err_code ndr_push_nbt_qtype(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum nbt_qtype r)
     482             : {
     483             :         /* For WACK replies, we need to send NBT_QTYPE_NETBIOS on the wire. */
     484       14639 :         NDR_CHECK(ndr_push_enum_uint16(ndr, NDR_SCALARS, (r == NBT_QTYPE_WACK) ? NBT_QTYPE_NETBIOS : r));
     485       14389 :         return NDR_ERR_SUCCESS;
     486             : }

Generated by: LCOV version 1.14