LCOV - code coverage report
Current view: top level - libcli/auth - msrpc_parse.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 170 238 71.4 %
Date: 2021-09-23 10:06:22 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      131614 : 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      131614 :         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      131614 :         pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format));
      60      131614 :         if (!pointers) {
      61           0 :                 return NT_STATUS_NO_MEMORY;
      62             :         }
      63      131614 :         intargs = talloc_array(pointers, int, strlen(format));
      64      131614 :         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      131614 :         va_start(ap, format);
      70     1129078 :         for (i=0; format[i]; i++) {
      71      997464 :                 switch (format[i]) {
      72      116801 :                 case 'U':
      73      116801 :                         s = va_arg(ap, char *);
      74      116801 :                         head_size += 8;
      75      116801 :                         ret = push_ucs2_talloc(
      76             :                                 pointers,
      77      116801 :                                 (smb_ucs2_t **)(void *)&pointers[i].data,
      78             :                                 s, &n);
      79      116801 :                         if (!ret) {
      80           0 :                                 va_end(ap);
      81           0 :                                 return map_nt_error_from_unix_common(errno);
      82             :                         }
      83      116801 :                         pointers[i].length = n;
      84      116801 :                         pointers[i].length -= 2;
      85      116801 :                         data_size += pointers[i].length;
      86      209713 :                         break;
      87       60300 :                 case 'A':
      88       60300 :                         s = va_arg(ap, char *);
      89       60300 :                         head_size += 8;
      90       60300 :                         ret = push_ascii_talloc(
      91       60300 :                                 pointers, (char **)(void *)&pointers[i].data,
      92             :                                 s, &n);
      93       60300 :                         if (!ret) {
      94           0 :                                 va_end(ap);
      95           0 :                                 return map_nt_error_from_unix_common(errno);
      96             :                         }
      97       60300 :                         pointers[i].length = n;
      98       60300 :                         pointers[i].length -= 1;
      99       60300 :                         data_size += pointers[i].length;
     100       60300 :                         break;
     101       18465 :                 case 'a':
     102       18465 :                         j = va_arg(ap, int);
     103       18465 :                         intargs[i] = j;
     104       18465 :                         s = va_arg(ap, char *);
     105       18465 :                         ret = push_ucs2_talloc(
     106             :                                 pointers,
     107       18465 :                                 (smb_ucs2_t **)(void *)&pointers[i].data,
     108             :                                 s, &n);
     109       18465 :                         if (!ret) {
     110           0 :                                 va_end(ap);
     111           0 :                                 return map_nt_error_from_unix_common(errno);
     112             :                         }
     113       18465 :                         pointers[i].length = n;
     114       18465 :                         pointers[i].length -= 2;
     115       18465 :                         data_size += pointers[i].length + 4;
     116       18465 :                         break;
     117      116801 :                 case 'B':
     118      116801 :                         b = va_arg(ap, uint8_t *);
     119      116801 :                         head_size += 8;
     120      116801 :                         pointers[i].data = b;
     121      116801 :                         pointers[i].length = va_arg(ap, int);
     122      116801 :                         data_size += pointers[i].length;
     123      116801 :                         break;
     124      247731 :                 case 'b':
     125      247731 :                         b = va_arg(ap, uint8_t *);
     126      247731 :                         pointers[i].data = b;
     127      247731 :                         pointers[i].length = va_arg(ap, int);
     128      247731 :                         head_size += pointers[i].length;
     129      247731 :                         break;
     130      349073 :                 case 'd':
     131      349073 :                         j = va_arg(ap, int);
     132      349073 :                         intargs[i] = j;
     133      349073 :                         head_size += 4;
     134      349073 :                         break;
     135       88293 :                 case 'C':
     136       88293 :                         s = va_arg(ap, char *);
     137       88293 :                         pointers[i].data = (uint8_t *)s;
     138       88293 :                         pointers[i].length = strlen(s)+1;
     139       88293 :                         head_size += pointers[i].length;
     140       88293 :                         break;
     141           0 :                 default:
     142           0 :                         va_end(ap);
     143           0 :                         return NT_STATUS_INVALID_PARAMETER;
     144             :                 }
     145             :         }
     146      131614 :         va_end(ap);
     147             : 
     148      131614 :         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      131614 :         *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
     154      131614 :         if (!blob->data) {
     155           0 :                 return NT_STATUS_NO_MEMORY;
     156             :         }
     157      131614 :         head_ofs = 0;
     158      131614 :         data_ofs = head_size;
     159             : 
     160      131614 :         va_start(ap, format);
     161     1129078 :         for (i=0; format[i]; i++) {
     162      997464 :                 switch (format[i]) {
     163      293902 :                 case 'U':
     164             :                 case 'A':
     165             :                 case 'B':
     166      293902 :                         n = pointers[i].length;
     167      293902 :                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
     168      293902 :                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
     169      293902 :                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
     170      293902 :                         if (pointers[i].data && n) /* don't follow null pointers... */
     171      228928 :                                 memcpy(blob->data+data_ofs, pointers[i].data, n);
     172      293902 :                         data_ofs += n;
     173      367523 :                         break;
     174       18465 :                 case 'a':
     175       18465 :                         j = intargs[i];
     176       18465 :                         SSVAL(blob->data, data_ofs, j); data_ofs += 2;
     177             : 
     178       18465 :                         n = pointers[i].length;
     179       18465 :                         SSVAL(blob->data, data_ofs, n); data_ofs += 2;
     180       19406 :                         memcpy(blob->data+data_ofs, pointers[i].data, n);
     181       18465 :                         data_ofs += n;
     182       18465 :                         break;
     183      349073 :                 case 'd':
     184      349073 :                         j = intargs[i];
     185      349073 :                         SIVAL(blob->data, head_ofs, j); 
     186      349073 :                         head_ofs += 4;
     187      349073 :                         break;
     188      247731 :                 case 'b':
     189      247731 :                         n = pointers[i].length;
     190      247731 :                         if (pointers[i].data && n) {
     191             :                                 /* don't follow null pointers... */
     192      247731 :                                 memcpy(blob->data + head_ofs, pointers[i].data, n);
     193             :                         }
     194      247731 :                         head_ofs += n;
     195      247731 :                         break;
     196       88293 :                 case 'C':
     197       88293 :                         n = pointers[i].length;
     198       88299 :                         memcpy(blob->data + head_ofs, pointers[i].data, n);
     199       88293 :                         head_ofs += n;
     200       88293 :                         break;
     201           0 :                 default:
     202           0 :                         va_end(ap);
     203           0 :                         return NT_STATUS_INVALID_PARAMETER;
     204             :                 }
     205             :         }
     206      131614 :         va_end(ap);
     207             :         
     208      131614 :         talloc_free(pointers);
     209             : 
     210      131614 :         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      203507 : 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      203507 :         size_t head_ofs = 0;
     243             :         uint16_t len1, len2;
     244             :         uint32_t ptr;
     245             :         uint32_t *v;
     246      203507 :         bool ret = true;
     247             : 
     248      203507 :         va_start(ap, format);
     249     1133711 :         for (i=0; format[i]; i++) {
     250      930204 :                 switch (format[i]) {
     251      115792 :                 case 'U':
     252      115792 :                         NEED_DATA(8);
     253      115792 :                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
     254      115792 :                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
     255      115792 :                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
     256             : 
     257      115792 :                         ps = va_arg(ap, char **);
     258      115792 :                         if (len1 == 0 && len2 == 0) {
     259        2755 :                                 *ps = talloc_strdup(mem_ctx, "");
     260        5069 :                                 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      113037 :                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
     267           0 :                                         ret = false;
     268           0 :                                         goto cleanup;
     269             :                                 }
     270      113037 :                                 if (len1 & 1) {
     271             :                                         /* if odd length and unicode */
     272           0 :                                         ret = false;
     273           0 :                                         goto cleanup;
     274             :                                 }
     275      213883 :                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
     276      100846 :                                                 blob->data + ptr < blob->data) {
     277           0 :                                         ret = false;
     278           0 :                                         goto cleanup;
     279             :                                 }
     280             : 
     281      113037 :                                 if (0 < len1) {
     282             :                                         size_t pull_len;
     283      314729 :                                         if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
     284      213881 :                                                                    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      115784 :                         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      145181 :                 case 'B':
     343      145181 :                         NEED_DATA(8);
     344      145181 :                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
     345      145181 :                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
     346      145181 :                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
     347             : 
     348      145181 :                         b = (DATA_BLOB *)va_arg(ap, void *);
     349      145181 :                         if (len1 == 0 && len2 == 0) {
     350        1856 :                                 *b = data_blob_talloc(mem_ctx, NULL, 0);
     351             :                         } else {
     352             :                                 /* make sure its in the right format - be strict */
     353      143325 :                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
     354           0 :                                         ret = false;
     355           0 :                                         goto cleanup;
     356             :                                 }
     357             : 
     358      271140 :                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
     359      127815 :                                                 blob->data + ptr < blob->data) {
     360           0 :                                         ret = false;
     361           0 :                                         goto cleanup;
     362             :                                 }
     363             : 
     364      143325 :                                 *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
     365             :                         }
     366      145171 :                         break;
     367       86991 :                 case 'b':
     368       86991 :                         b = (DATA_BLOB *)va_arg(ap, void *);
     369       86991 :                         len1 = va_arg(ap, unsigned int);
     370             :                         /* make sure its in the right format - be strict */
     371       86991 :                         NEED_DATA(len1);
     372      164508 :                         if (blob->data + head_ofs < (uint8_t *)head_ofs ||
     373       86991 :                                         blob->data + head_ofs < blob->data) {
     374           0 :                                 ret = false;
     375           0 :                                 goto cleanup;
     376             :                         }
     377             : 
     378       86991 :                         *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
     379       86991 :                         head_ofs += len1;
     380       86991 :                         break;
     381      378733 :                 case 'd':
     382      378733 :                         v = va_arg(ap, uint32_t *);
     383      378733 :                         NEED_DATA(4);
     384      378733 :                         *v = IVAL(blob->data, head_ofs); head_ofs += 4;
     385      378733 :                         break;
     386      203507 :                 case 'C':
     387      203507 :                         s = va_arg(ap, char *);
     388             : 
     389      384882 :                         if (blob->data + head_ofs < (uint8_t *)head_ofs ||
     390      384882 :                                         blob->data + head_ofs < blob->data ||
     391      203507 :                             (head_ofs + (strlen(s) + 1)) > blob->length) {
     392           0 :                                 ret = false;
     393           0 :                                 goto cleanup;
     394             :                         }
     395             : 
     396      203507 :                         if (memcmp(blob->data + head_ofs, s, strlen(s)+1) != 0) {
     397           0 :                                 ret = false;
     398           0 :                                 goto cleanup;
     399             :                         }
     400      203493 :                         head_ofs += (strlen(s) + 1);
     401             : 
     402      203493 :                         break;
     403             :                 }
     404             :         }
     405             : 
     406      203507 : cleanup:
     407      203507 :         va_end(ap);
     408      203507 :         return ret;
     409             : }

Generated by: LCOV version 1.13