root/source4/auth/ntlmssp/ntlmssp_parse.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. msrpc_gen
  2. msrpc_parse

   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 "auth/ntlmssp/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 bool msrpc_gen(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
  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         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         pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format));
  60         intargs = talloc_array(pointers, int, strlen(format));
  61 
  62         /* first scan the format to work out the header and body size */
  63         va_start(ap, format);
  64         for (i=0; format[i]; i++) {
  65                 switch (format[i]) {
  66                 case 'U':
  67                         s = va_arg(ap, char *);
  68                         head_size += 8;
  69                         ret = push_ucs2_talloc(pointers, (smb_ucs2_t **)&pointers[i].data, 
  70                                                                    s, &n);
  71                         if (!ret) {
  72                                 return false;
  73                         }
  74                         pointers[i].length = n;
  75                         pointers[i].length -= 2;
  76                         data_size += pointers[i].length;
  77                         break;
  78                 case 'A':
  79                         s = va_arg(ap, char *);
  80                         head_size += 8;
  81                         ret = push_ascii_talloc(pointers, (char **)&pointers[i].data, s,
  82                                                                         &n);
  83                         if (!ret) {
  84                                 return false;
  85                         }
  86                         pointers[i].length = n;
  87                         pointers[i].length -= 1;
  88                         data_size += pointers[i].length;
  89                         break;
  90                 case 'a':
  91                         j = va_arg(ap, int);
  92                         intargs[i] = j;
  93                         s = va_arg(ap, char *);
  94                         ret = push_ucs2_talloc(pointers, (smb_ucs2_t **)&pointers[i].data, 
  95                                                                    s, &n);
  96                         if (!ret) {
  97                                 return false;
  98                         }
  99                         pointers[i].length = n;
 100                         pointers[i].length -= 2;
 101                         data_size += pointers[i].length + 4;
 102                         break;
 103                 case 'B':
 104                         b = va_arg(ap, uint8_t *);
 105                         head_size += 8;
 106                         pointers[i].data = b;
 107                         pointers[i].length = va_arg(ap, int);
 108                         data_size += pointers[i].length;
 109                         break;
 110                 case 'b':
 111                         b = va_arg(ap, uint8_t *);
 112                         pointers[i].data = b;
 113                         pointers[i].length = va_arg(ap, int);
 114                         head_size += pointers[i].length;
 115                         break;
 116                 case 'd':
 117                         j = va_arg(ap, int);
 118                         intargs[i] = j;
 119                         head_size += 4;
 120                         break;
 121                 case 'C':
 122                         s = va_arg(ap, char *);
 123                         pointers[i].data = (uint8_t *)s;
 124                         pointers[i].length = strlen(s)+1;
 125                         head_size += pointers[i].length;
 126                         break;
 127                 }
 128         }
 129         va_end(ap);
 130 
 131         /* allocate the space, then scan the format again to fill in the values */
 132         *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
 133 
 134         head_ofs = 0;
 135         data_ofs = head_size;
 136 
 137         va_start(ap, format);
 138         for (i=0; format[i]; i++) {
 139                 switch (format[i]) {
 140                 case 'U':
 141                 case 'A':
 142                 case 'B':
 143                         n = pointers[i].length;
 144                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
 145                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
 146                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
 147                         if (pointers[i].data && n) /* don't follow null pointers... */
 148                                 memcpy(blob->data+data_ofs, pointers[i].data, n);
 149                         data_ofs += n;
 150                         break;
 151                 case 'a':
 152                         j = intargs[i];
 153                         SSVAL(blob->data, data_ofs, j); data_ofs += 2;
 154 
 155                         n = pointers[i].length;
 156                         SSVAL(blob->data, data_ofs, n); data_ofs += 2;
 157                         if (n >= 0) {
 158                                 memcpy(blob->data+data_ofs, pointers[i].data, n);
 159                         }
 160                         data_ofs += n;
 161                         break;
 162                 case 'd':
 163                         j = intargs[i];
 164                         SIVAL(blob->data, head_ofs, j); 
 165                         head_ofs += 4;
 166                         break;
 167                 case 'b':
 168                         n = pointers[i].length;
 169                         memcpy(blob->data + head_ofs, pointers[i].data, n);
 170                         head_ofs += n;
 171                         break;
 172                 case 'C':
 173                         n = pointers[i].length;
 174                         memcpy(blob->data + head_ofs, pointers[i].data, n);
 175                         head_ofs += n;
 176                         break;
 177                 }
 178         }
 179         va_end(ap);
 180         
 181         talloc_free(pointers);
 182 
 183         return true;
 184 }
 185 
 186 
 187 /* a helpful macro to avoid running over the end of our blob */
 188 #define NEED_DATA(amount) \
 189 if ((head_ofs + amount) > blob->length) { \
 190         return false; \
 191 }
 192 
 193 /**
 194   this is a tiny msrpc packet parser. This the the partner of msrpc_gen
 195 
 196   format specifiers are:
 197 
 198   U = unicode string (output is unix string)
 199   A = ascii string
 200   B = data blob
 201   b = data blob in header
 202   d = word (4 bytes)
 203   C = constant ascii string
 204  */
 205 
 206 bool msrpc_parse(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 207                  const DATA_BLOB *blob,
 208                  const char *format, ...)
 209 {
 210         int i;
 211         va_list ap;
 212         const char **ps, *s;
 213         DATA_BLOB *b;
 214         size_t head_ofs = 0;
 215         uint16_t len1, len2;
 216         uint32_t ptr;
 217         uint32_t *v;
 218         size_t p_len = 1024;
 219         char *p = talloc_array(mem_ctx, char, p_len);
 220         bool ret = true;
 221 
 222         va_start(ap, format);
 223         for (i=0; format[i]; i++) {
 224                 switch (format[i]) {
 225                 case 'U':
 226                         NEED_DATA(8);
 227                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
 228                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
 229                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 230 
 231                         ps = (const char **)va_arg(ap, char **);
 232                         if (len1 == 0 && len2 == 0) {
 233                                 *ps = "";
 234                         } else {
 235                                 /* make sure its in the right format - be strict */
 236                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
 237                                         ret = false;
 238                                         goto cleanup;
 239                                 }
 240                                 if (len1 & 1) {
 241                                         /* if odd length and unicode */
 242                                         ret = false;
 243                                         goto cleanup;
 244                                 }
 245                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
 246                                                 blob->data + ptr < blob->data) {
 247                                         ret = false;
 248                                         goto cleanup;
 249                                 }
 250 
 251                                 if (0 < len1) {
 252                                         pull_string(p, blob->data + ptr, p_len, 
 253                                                     len1, STR_UNICODE|STR_NOALIGN);
 254                                         (*ps) = talloc_strdup(mem_ctx, p);
 255                                         if (!(*ps)) {
 256                                                 ret = false;
 257                                                 goto cleanup;
 258                                         }
 259                                 } else {
 260                                         (*ps) = "";
 261                                 }
 262                         }
 263                         break;
 264                 case 'A':
 265                         NEED_DATA(8);
 266                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
 267                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
 268                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 269 
 270                         ps = (const char **)va_arg(ap, char **);
 271                         /* make sure its in the right format - be strict */
 272                         if (len1 == 0 && len2 == 0) {
 273                                 *ps = "";
 274                         } else {
 275                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
 276                                         ret = false;
 277                                         goto cleanup;
 278                                 }
 279 
 280                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
 281                                                 blob->data + ptr < blob->data) {
 282                                         ret = false;
 283                                         goto cleanup;
 284                                 }
 285 
 286                                 if (0 < len1) {
 287                                         pull_string(p, blob->data + ptr, p_len, 
 288                                                     len1, STR_ASCII|STR_NOALIGN);
 289                                         (*ps) = talloc_strdup(mem_ctx, p);
 290                                         if (!(*ps)) {
 291                                                 ret = false;
 292                                                 goto cleanup;
 293                                         }
 294                                 } else {
 295                                         (*ps) = "";
 296                                 }
 297                         }
 298                         break;
 299                 case 'B':
 300                         NEED_DATA(8);
 301                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
 302                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
 303                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 304 
 305                         b = (DATA_BLOB *)va_arg(ap, void *);
 306                         if (len1 == 0 && len2 == 0) {
 307                                 *b = data_blob_talloc(mem_ctx, NULL, 0);
 308                         } else {
 309                                 /* make sure its in the right format - be strict */
 310                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
 311                                         ret = false;
 312                                         goto cleanup;
 313                                 }
 314 
 315                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
 316                                                 blob->data + ptr < blob->data) {
 317                                         ret = false;
 318                                         goto cleanup;
 319                                 }
 320 
 321                                 *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
 322                         }
 323                         break;
 324                 case 'b':
 325                         b = (DATA_BLOB *)va_arg(ap, void *);
 326                         len1 = va_arg(ap, uint_t);
 327                         /* make sure its in the right format - be strict */
 328                         NEED_DATA(len1);
 329                         if (blob->data + head_ofs < (uint8_t *)head_ofs ||
 330                                         blob->data + head_ofs < blob->data) {
 331                                 ret = false;
 332                                 goto cleanup;
 333                         }
 334 
 335                         *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
 336                         head_ofs += len1;
 337                         break;
 338                 case 'd':
 339                         v = va_arg(ap, uint32_t *);
 340                         NEED_DATA(4);
 341                         *v = IVAL(blob->data, head_ofs); head_ofs += 4;
 342                         break;
 343                 case 'C':
 344                         s = va_arg(ap, char *);
 345 
 346                         if (blob->data + head_ofs < (uint8_t *)head_ofs ||
 347                                         blob->data + head_ofs < blob->data) {
 348                                 ret = false;
 349                                 goto cleanup;
 350                         }
 351 
 352                         head_ofs += pull_string(p,
 353                                         blob->data+head_ofs, p_len,
 354                                         blob->length - head_ofs,
 355                                         STR_ASCII|STR_TERMINATE);
 356                         if (strcmp(s, p) != 0) {
 357                                 ret = false;
 358                                 goto cleanup;
 359                         }
 360                         break;
 361                 }
 362         }
 363 
 364 cleanup:
 365         va_end(ap);
 366         talloc_free(p);
 367         return ret;
 368 }

/* [<][>][^][v][top][bottom][index][help] */