LCOV - code coverage report
Current view: top level - libcli/auth - msrpc_parse.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 170 238 71.4 %
Date: 2024-06-13 04:01:37 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    simple kerberos5/SPNEGO routines
       4             :    Copyright (C) Andrew Tridgell 2001
       5             :    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
       6             :    Copyright (C) Andrew Bartlett 2002-2003
       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             : #include "includes.h"
      23             : #include "libcli/auth/msrpc_parse.h"
      24             : 
      25             : /*
      26             :   this is a tiny msrpc packet generator. I am only using this to
      27             :   avoid tying this code to a particular varient of our rpc code. This
      28             :   generator is not general enough for all our rpc needs, its just
      29             :   enough for the spnego/ntlmssp code
      30             : 
      31             :   format specifiers are:
      32             : 
      33             :   U = unicode string (input is unix string)
      34             :   a = address (input is char *unix_string)
      35             :       (1 byte type, 1 byte length, unicode/ASCII string, all inline)
      36             :   A = ASCII string (input is unix string)
      37             :   B = data blob (pointer + length)
      38             :   b = data blob in header (pointer + length)
      39             :   D
      40             :   d = word (4 bytes)
      41             :   C = constant ascii string
      42             :  */
      43       50451 : NTSTATUS msrpc_gen(TALLOC_CTX *mem_ctx, 
      44             :                DATA_BLOB *blob,
      45             :                const char *format, ...)
      46             : {
      47             :         int i, j;
      48             :         bool ret;
      49             :         va_list ap;
      50             :         char *s;
      51             :         uint8_t *b;
      52       50451 :         int head_size=0, data_size=0;
      53             :         int head_ofs, data_ofs;
      54             :         int *intargs;
      55             :         size_t n;
      56             : 
      57             :         DATA_BLOB *pointers;
      58             : 
      59       50451 :         pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format));
      60       50451 :         if (!pointers) {
      61           0 :                 return NT_STATUS_NO_MEMORY;
      62             :         }
      63       50451 :         intargs = talloc_array(pointers, int, strlen(format));
      64       50451 :         if (!intargs) {
      65           0 :                 return NT_STATUS_NO_MEMORY;
      66             :         }
      67             : 
      68             :         /* first scan the format to work out the header and body size */
      69       50451 :         va_start(ap, format);
      70      418483 :         for (i=0; format[i]; i++) {
      71      368032 :                 switch (format[i]) {
      72       40730 :                 case 'U':
      73       40730 :                         s = va_arg(ap, char *);
      74       40730 :                         head_size += 8;
      75       40730 :                         ret = push_ucs2_talloc(
      76             :                                 pointers,
      77       40730 :                                 (smb_ucs2_t **)(void *)&pointers[i].data,
      78             :                                 s, &n);
      79       40730 :                         if (!ret) {
      80           0 :                                 va_end(ap);
      81           0 :                                 return map_nt_error_from_unix_common(errno);
      82             :                         }
      83       40730 :                         pointers[i].length = n;
      84       40730 :                         pointers[i].length -= 2;
      85       40730 :                         data_size += pointers[i].length;
      86      120870 :                         break;
      87       20380 :                 case 'A':
      88       20380 :                         s = va_arg(ap, char *);
      89       20380 :                         head_size += 8;
      90       20380 :                         ret = push_ascii_talloc(
      91       20380 :                                 pointers, (char **)(void *)&pointers[i].data,
      92             :                                 s, &n);
      93       20380 :                         if (!ret) {
      94           0 :                                 va_end(ap);
      95           0 :                                 return map_nt_error_from_unix_common(errno);
      96             :                         }
      97       20380 :                         pointers[i].length = n;
      98       20380 :                         pointers[i].length -= 1;
      99       20380 :                         data_size += pointers[i].length;
     100       20380 :                         break;
     101       13548 :                 case 'a':
     102       13548 :                         j = va_arg(ap, int);
     103       13548 :                         intargs[i] = j;
     104       13548 :                         s = va_arg(ap, char *);
     105       13548 :                         ret = push_ucs2_talloc(
     106             :                                 pointers,
     107       13548 :                                 (smb_ucs2_t **)(void *)&pointers[i].data,
     108             :                                 s, &n);
     109       13548 :                         if (!ret) {
     110           0 :                                 va_end(ap);
     111           0 :                                 return map_nt_error_from_unix_common(errno);
     112             :                         }
     113       13548 :                         pointers[i].length = n;
     114       13548 :                         pointers[i].length -= 2;
     115       13548 :                         data_size += pointers[i].length + 4;
     116       13548 :                         break;
     117       40730 :                 case 'B':
     118       40730 :                         b = va_arg(ap, uint8_t *);
     119       40730 :                         head_size += 8;
     120       40730 :                         pointers[i].data = b;
     121       40730 :                         pointers[i].length = va_arg(ap, int);
     122       40730 :                         data_size += pointers[i].length;
     123       40730 :                         break;
     124       93173 :                 case 'b':
     125       93173 :                         b = va_arg(ap, uint8_t *);
     126       93173 :                         pointers[i].data = b;
     127       93173 :                         pointers[i].length = va_arg(ap, int);
     128       93173 :                         head_size += pointers[i].length;
     129       93173 :                         break;
     130      128911 :                 case 'd':
     131      128911 :                         j = va_arg(ap, int);
     132      128911 :                         intargs[i] = j;
     133      128911 :                         head_size += 4;
     134      128911 :                         break;
     135       30560 :                 case 'C':
     136       30560 :                         s = va_arg(ap, char *);
     137       30560 :                         pointers[i].data = (uint8_t *)s;
     138       30560 :                         pointers[i].length = strlen(s)+1;
     139       30560 :                         head_size += pointers[i].length;
     140       30560 :                         break;
     141           0 :                 default:
     142           0 :                         va_end(ap);
     143           0 :                         return NT_STATUS_INVALID_PARAMETER;
     144             :                 }
     145             :         }
     146       50451 :         va_end(ap);
     147             : 
     148       50451 :         if (head_size + data_size == 0) {
     149           0 :                 return NT_STATUS_INVALID_PARAMETER;
     150             :         }
     151             : 
     152             :         /* allocate the space, then scan the format again to fill in the values */
     153       50451 :         *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
     154       50451 :         if (!blob->data) {
     155           0 :                 return NT_STATUS_NO_MEMORY;
     156             :         }
     157       50451 :         head_ofs = 0;
     158       50451 :         data_ofs = head_size;
     159             : 
     160       50451 :         va_start(ap, format);
     161      418483 :         for (i=0; format[i]; i++) {
     162      368032 :                 switch (format[i]) {
     163      101840 :                 case 'U':
     164             :                 case 'A':
     165             :                 case 'B':
     166      101840 :                         n = pointers[i].length;
     167      101840 :                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
     168      101840 :                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
     169      101840 :                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
     170      101840 :                         if (pointers[i].data && n) /* don't follow null pointers... */
     171       78760 :                                 memcpy(blob->data+data_ofs, pointers[i].data, n);
     172      101840 :                         data_ofs += n;
     173      164734 :                         break;
     174       13548 :                 case 'a':
     175       13548 :                         j = intargs[i];
     176       13548 :                         SSVAL(blob->data, data_ofs, j); data_ofs += 2;
     177             : 
     178       13548 :                         n = pointers[i].length;
     179       13548 :                         SSVAL(blob->data, data_ofs, n); data_ofs += 2;
     180       13548 :                         memcpy(blob->data+data_ofs, pointers[i].data, n);
     181       13548 :                         data_ofs += n;
     182       13548 :                         break;
     183      128911 :                 case 'd':
     184      128911 :                         j = intargs[i];
     185      128911 :                         SIVAL(blob->data, head_ofs, j); 
     186      128911 :                         head_ofs += 4;
     187      128911 :                         break;
     188       93173 :                 case 'b':
     189       93173 :                         n = pointers[i].length;
     190       93173 :                         if (pointers[i].data && n) {
     191             :                                 /* don't follow null pointers... */
     192       93173 :                                 memcpy(blob->data + head_ofs, pointers[i].data, n);
     193             :                         }
     194       93173 :                         head_ofs += n;
     195       93173 :                         break;
     196       30560 :                 case 'C':
     197       30560 :                         n = pointers[i].length;
     198       30560 :                         memcpy(blob->data + head_ofs, pointers[i].data, n);
     199       30560 :                         head_ofs += n;
     200       30560 :                         break;
     201           0 :                 default:
     202           0 :                         va_end(ap);
     203           0 :                         return NT_STATUS_INVALID_PARAMETER;
     204             :                 }
     205             :         }
     206       50451 :         va_end(ap);
     207             :         
     208       50451 :         talloc_free(pointers);
     209             : 
     210       50451 :         return NT_STATUS_OK;
     211             : }
     212             : 
     213             : 
     214             : /* a helpful macro to avoid running over the end of our blob */
     215             : #define NEED_DATA(amount) \
     216             : if ((head_ofs + amount) > blob->length) { \
     217             :         va_end(ap); \
     218             :         return false; \
     219             : }
     220             : 
     221             : /**
     222             :   this is a tiny msrpc packet parser. This the the partner of msrpc_gen
     223             : 
     224             :   format specifiers are:
     225             : 
     226             :   U = unicode string (output is unix string)
     227             :   A = ascii string
     228             :   B = data blob
     229             :   b = data blob in header
     230             :   d = word (4 bytes)
     231             :   C = constant ascii string
     232             :  */
     233             : 
     234       71306 : bool msrpc_parse(TALLOC_CTX *mem_ctx, 
     235             :                  const DATA_BLOB *blob,
     236             :                  const char *format, ...)
     237             : {
     238             :         int i;
     239             :         va_list ap;
     240             :         char **ps, *s;
     241             :         DATA_BLOB *b;
     242       71306 :         size_t head_ofs = 0;
     243             :         uint16_t len1, len2;
     244             :         uint32_t ptr;
     245             :         uint32_t *v;
     246       71306 :         bool ret = true;
     247             : 
     248       71306 :         va_start(ap, format);
     249      397123 :         for (i=0; format[i]; i++) {
     250      325817 :                 switch (format[i]) {
     251       40681 :                 case 'U':
     252       40681 :                         NEED_DATA(8);
     253       40681 :                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
     254       40681 :                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
     255       40681 :                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
     256             : 
     257       40681 :                         ps = va_arg(ap, char **);
     258       40681 :                         if (len1 == 0 && len2 == 0) {
     259        1718 :                                 *ps = talloc_strdup(mem_ctx, "");
     260        3077 :                                 if (*ps == NULL) {
     261           0 :                                         ret = false;
     262           0 :                                         goto cleanup;
     263             :                                 }
     264             :                         } else {
     265             :                                 /* make sure its in the right format - be strict */
     266       38963 :                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
     267           0 :                                         ret = false;
     268           0 :                                         goto cleanup;
     269             :                                 }
     270       38963 :                                 if (len1 & 1) {
     271             :                                         /* if odd length and unicode */
     272           0 :                                         ret = false;
     273           0 :                                         goto cleanup;
     274             :                                 }
     275       66809 :                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
     276       27846 :                                                 blob->data + ptr < blob->data) {
     277           0 :                                         ret = false;
     278           0 :                                         goto cleanup;
     279             :                                 }
     280             : 
     281       38963 :                                 if (0 < len1) {
     282             :                                         size_t pull_len;
     283       94655 :                                         if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
     284       66809 :                                                                    blob->data + ptr, len1, 
     285             :                                                                    ps, &pull_len)) {
     286           0 :                                                 ret = false;
     287           0 :                                                 goto cleanup;
     288             :                                         }
     289             :                                 } else {
     290           0 :                                         *ps = talloc_strdup(mem_ctx, "");
     291           0 :                                         if (*ps == NULL) {
     292           0 :                                                 ret = false;
     293           0 :                                                 goto cleanup;
     294             :                                         }
     295             :                                 }
     296             :                         }
     297       40681 :                         break;
     298           0 :                 case 'A':
     299           0 :                         NEED_DATA(8);
     300           0 :                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
     301           0 :                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
     302           0 :                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
     303             : 
     304           0 :                         ps = (char **)va_arg(ap, char **);
     305             :                         /* make sure its in the right format - be strict */
     306           0 :                         if (len1 == 0 && len2 == 0) {
     307           0 :                                 *ps = talloc_strdup(mem_ctx, "");
     308           0 :                                 if (*ps == NULL) {
     309           0 :                                         ret = false;
     310           0 :                                         goto cleanup;
     311             :                                 }
     312             :                         } else {
     313           0 :                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
     314           0 :                                         ret = false;
     315           0 :                                         goto cleanup;
     316             :                                 }
     317             : 
     318           0 :                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
     319           0 :                                                 blob->data + ptr < blob->data) {
     320           0 :                                         ret = false;
     321           0 :                                         goto cleanup;
     322             :                                 }
     323             : 
     324           0 :                                 if (0 < len1) {
     325             :                                         size_t pull_len;
     326             : 
     327           0 :                                         if (!convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, 
     328           0 :                                                                    blob->data + ptr, len1, 
     329             :                                                                    ps, &pull_len)) {
     330           0 :                                                 ret = false;
     331           0 :                                                 goto cleanup;
     332             :                                         }
     333             :                                 } else {
     334           0 :                                         *ps = talloc_strdup(mem_ctx, "");
     335           0 :                                         if (*ps == NULL) {
     336           0 :                                                 ret = false;
     337           0 :                                                 goto cleanup;
     338             :                                         }
     339             :                                 }
     340             :                         }
     341           0 :                         break;
     342       50873 :                 case 'B':
     343       50873 :                         NEED_DATA(8);
     344       50873 :                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
     345       50873 :                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
     346       50873 :                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
     347             : 
     348       50873 :                         b = (DATA_BLOB *)va_arg(ap, void *);
     349       50873 :                         if (len1 == 0 && len2 == 0) {
     350        1008 :                                 *b = data_blob_talloc(mem_ctx, NULL, 0);
     351             :                         } else {
     352             :                                 /* make sure its in the right format - be strict */
     353       49865 :                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
     354           0 :                                         ret = false;
     355           0 :                                         goto cleanup;
     356             :                                 }
     357             : 
     358       85626 :                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
     359       35761 :                                                 blob->data + ptr < blob->data) {
     360           0 :                                         ret = false;
     361           0 :                                         goto cleanup;
     362             :                                 }
     363             : 
     364       49865 :                                 *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
     365             :                         }
     366       50873 :                         break;
     367       30518 :                 case 'b':
     368       30518 :                         b = (DATA_BLOB *)va_arg(ap, void *);
     369       30518 :                         len1 = va_arg(ap, unsigned int);
     370             :                         /* make sure its in the right format - be strict */
     371       30518 :                         NEED_DATA(len1);
     372       52426 :                         if (blob->data + head_ofs < (uint8_t *)head_ofs ||
     373       30518 :                                         blob->data + head_ofs < blob->data) {
     374           0 :                                 ret = false;
     375           0 :                                 goto cleanup;
     376             :                         }
     377             : 
     378       30518 :                         *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
     379       30518 :                         head_ofs += len1;
     380       30518 :                         break;
     381      132439 :                 case 'd':
     382      132439 :                         v = va_arg(ap, uint32_t *);
     383      132439 :                         NEED_DATA(4);
     384      132439 :                         *v = IVAL(blob->data, head_ofs); head_ofs += 4;
     385      132439 :                         break;
     386       71306 :                 case 'C':
     387       71306 :                         s = va_arg(ap, char *);
     388             : 
     389      122486 :                         if (blob->data + head_ofs < (uint8_t *)head_ofs ||
     390      122486 :                                         blob->data + head_ofs < blob->data ||
     391       71306 :                             (head_ofs + (strlen(s) + 1)) > blob->length) {
     392           0 :                                 ret = false;
     393           0 :                                 goto cleanup;
     394             :                         }
     395             : 
     396       71306 :                         if (memcmp(blob->data + head_ofs, s, strlen(s)+1) != 0) {
     397           0 :                                 ret = false;
     398           0 :                                 goto cleanup;
     399             :                         }
     400       71306 :                         head_ofs += (strlen(s) + 1);
     401             : 
     402       71306 :                         break;
     403             :                 }
     404             :         }
     405             : 
     406       71306 : cleanup:
     407       71306 :         va_end(ap);
     408       71306 :         return ret;
     409             : }

Generated by: LCOV version 1.13