LCOV - code coverage report
Current view: top level - libcli/nbt - nbtname.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 171 212 80.7 %
Date: 2021-09-23 10:06:22 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       19412 : static bool decompress_name(char *name, enum nbt_name_type *type)
      37             : {
      38             :         int i;
      39      330004 :         for (i=0;name[2*i];i++) {
      40      310592 :                 uint8_t c1 = name[2*i];
      41      310592 :                 uint8_t c2 = name[1+(2*i)];
      42      310592 :                 if (c1 < 'A' || c1 > 'P' ||
      43      310592 :                     c2 < 'A' || c2 > 'P') {
      44           0 :                         return false;
      45             :                 }
      46      310592 :                 name[i] = ((c1-'A')<<4) | (c2-'A');
      47             :         }
      48       19412 :         name[i] = 0;
      49       19412 :         if (i == 16) {
      50       19412 :                 *type = (enum nbt_name_type)(name[15]);
      51       19412 :                 name[15] = 0;
      52       19412 :                 i--;
      53             :         } else {
      54           0 :                 *type = NBT_NAME_CLIENT;
      55             :         }
      56             : 
      57             :         /* trim trailing spaces */
      58      133646 :         for (;i>0 && name[i-1]==' ';i--) {
      59      114431 :                 name[i-1] = 0;
      60             :         }
      61             : 
      62       19215 :         return true;
      63             : }
      64             : 
      65             : 
      66             : /*
      67             :   compress a name component
      68             :  */
      69       13625 : 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       13625 :         if (strlen((const char *)name) > 15) {
      77           0 :                 return NULL;
      78             :         }
      79             : 
      80       13625 :         cname = talloc_array(mem_ctx, uint8_t, 33);
      81       13625 :         if (cname == NULL) return NULL;
      82             : 
      83      116571 :         for (i=0;name[i];i++) {
      84      103071 :                 cname[2*i]   = 'A' + (name[i]>>4);
      85      103071 :                 cname[1+2*i] = 'A' + (name[i]&0xF);
      86             :         }
      87       13625 :         if (strcmp((const char *)name, "*") == 0) {
      88           9 :                 pad_char = 0;
      89             :         } else {
      90       13616 :                 pad_char = ' ';
      91             :         }
      92      114804 :         for (;i<15;i++) {
      93      101304 :                 cname[2*i]   = 'A' + (pad_char>>4);
      94      101304 :                 cname[1+2*i] = 'A' + (pad_char&0xF);
      95             :         }
      96             : 
      97       13625 :         pad_char = type;
      98       13625 :         cname[2*i]   = 'A' + (pad_char>>4);
      99       13625 :         cname[1+2*i] = 'A' + (pad_char&0xF);
     100             : 
     101       13625 :         cname[32] = 0;
     102       13625 :         return cname;
     103             : }
     104             : 
     105             : 
     106             : /**
     107             :   pull a nbt name from the wire
     108             : */
     109       19412 : _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       19412 :         if (!(ndr_flags & NDR_SCALARS)) {
     117           0 :                 return NDR_ERR_SUCCESS;
     118             :         }
     119             : 
     120       19412 :         NDR_CHECK(ndr_pull_nbt_string(ndr, ndr_flags, &s));
     121             : 
     122       19412 :         scope = (uint8_t *)strchr(s, '.');
     123       19412 :         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       19157 :                 r->scope = NULL;
     129             :         }
     130             : 
     131       19412 :         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       19412 :         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       19412 :         ok = decompress_name(cname, &r->type);
     142       19412 :         if (!ok) {
     143           0 :                 return ndr_pull_error(ndr, NDR_ERR_STRING,
     144             :                                       "NBT NAME failed to decompress");
     145             :         }
     146             : 
     147       19412 :         r->name = talloc_strdup(ndr->current_mem_ctx, cname);
     148       19412 :         NDR_ERR_HAVE_NO_MEMORY(r->name);
     149             : 
     150       19412 :         talloc_free(cname);
     151             : 
     152       19412 :         return NDR_ERR_SUCCESS;
     153             : }
     154             : 
     155             : /**
     156             :   push a nbt name to the wire
     157             : */
     158       13625 : _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       13625 :         if (!(ndr_flags & NDR_SCALARS)) {
     164           0 :                 return NDR_ERR_SUCCESS;
     165             :         }
     166             : 
     167       13625 :         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       13625 :         cname = compress_name(ndr, (const uint8_t *)r->name, r->type);
     174       13625 :         NDR_ERR_HAVE_NO_MEMORY(cname);
     175             : 
     176       13625 :         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       13245 :                 fullname = cname;
     182             :         }
     183             : 
     184       13625 :         ndr_err = ndr_push_nbt_string(ndr, ndr_flags, (const char *)fullname);
     185             : 
     186       13625 :         return ndr_err;
     187             : }
     188             : 
     189             : 
     190             : /**
     191             :   copy a nbt name structure
     192             : */
     193      133942 : _PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx,
     194             :                                const struct nbt_name *name,
     195             :                                struct nbt_name *newname)
     196             : {
     197      133942 :         *newname = *name;
     198      133942 :         newname->name = talloc_strdup(mem_ctx, newname->name);
     199      133942 :         NT_STATUS_HAVE_NO_MEMORY(newname->name);
     200      133942 :         newname->scope = talloc_strdup(mem_ctx, newname->scope);
     201      133942 :         if (name->scope) {
     202          33 :                 NT_STATUS_HAVE_NO_MEMORY(newname->scope);
     203             :         }
     204      133942 :         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       21107 : _PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx,
     246             :                             struct nbt_name *n, const char *name, int type)
     247             : {
     248       21107 :         n->scope = NULL;
     249       21107 :         n->type = type;
     250             : 
     251       21107 :         if ((name == NULL) || is_ipaddress(name)) {
     252        5382 :                 n->name = "*SMBSERVER";
     253        5382 :                 return;
     254             :         }
     255       15725 :         if (strlen(name) > 15) {
     256         169 :                 const char *p = strchr(name, '.');
     257             :                 char *s;
     258         169 :                 if (p - name > 15) {
     259           0 :                         n->name = "*SMBSERVER";
     260           0 :                         return;
     261             :                 }
     262         169 :                 s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
     263         169 :                 n->name = talloc_strdup_upper(mem_ctx, s);
     264         169 :                 return;
     265             :         }
     266             : 
     267       15556 :         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         590 : static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
     276             : {
     277             :         int i, len;
     278             :         char *ret;
     279         590 :         const char *valid_chars = "_-.$@ ";
     280             : #define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c))
     281             : 
     282        6984 :         for (len=i=0;s[i];i++,len++) {
     283        6394 :                 if (!NBT_CHAR_ALLOW(s[i])) {
     284          10 :                         len += 2;
     285             :                 }
     286             :         }
     287             : 
     288         590 :         ret = talloc_array(mem_ctx, char, len+1);
     289         590 :         if (ret == NULL) return NULL;
     290             : 
     291        6971 :         for (len=i=0;s[i];i++) {
     292        6394 :                 if (NBT_CHAR_ALLOW(s[i])) {
     293        6384 :                         ret[len++] = s[i];
     294             :                 } else {
     295          10 :                         snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]);
     296          10 :                         len += 3;
     297             :                 }
     298             :         }
     299         590 :         ret[len] = 0;
     300             : 
     301         590 :         return ret;
     302             : }
     303             : 
     304             : 
     305             : /**
     306             :   form a string for a NBT name
     307             : */
     308         570 : _PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
     309             : {
     310         570 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     311             :         char *ret;
     312         570 :         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         550 :                 ret = talloc_asprintf(mem_ctx, "%s<%02x>",
     319         115 :                                       nbt_hex_encode(tmp_ctx, name->name),
     320         550 :                                       name->type);
     321             :         }
     322         570 :         talloc_free(tmp_ctx);
     323         570 :         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        3384 : _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        3384 :                 uint32_t _flags_save_STRUCT = ndr->flags;
     485        3384 :                 ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
     486        3384 :                 if (ndr_flags & NDR_SCALARS) {
     487        3384 :                         NDR_CHECK(ndr_push_align(ndr, 4));
     488        3384 :                         NDR_CHECK(ndr_push_nbt_name(ndr, NDR_SCALARS, &r->name));
     489        3380 :                         NDR_CHECK(ndr_push_nbt_qtype(ndr, NDR_SCALARS, r->rr_type));
     490        3380 :                         NDR_CHECK(ndr_push_nbt_qclass(ndr, NDR_SCALARS, r->rr_class));
     491        3380 :                         NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl));
     492        3380 :                         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        3380 :                         NDR_CHECK(ndr_push_nbt_rdata(ndr, NDR_SCALARS, &r->rdata));
     494             :                 }
     495        3320 :                 if (ndr_flags & NDR_BUFFERS) {
     496             :                 }
     497        3380 :                 ndr->flags = _flags_save_STRUCT;
     498             :         }
     499        3380 :         return NDR_ERR_SUCCESS;
     500             : }

Generated by: LCOV version 1.13