root/source3/libsmb/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 
  24 /*
  25   this is a tiny msrpc packet generator. I am only using this to
  26   avoid tying this code to a particular varient of our rpc code. This
  27   generator is not general enough for all our rpc needs, its just
  28   enough for the spnego/ntlmssp code
  29 
  30   format specifiers are:
  31 
  32   U = unicode string (input is unix string)
  33   a = address (input is char *unix_string)
  34       (1 byte type, 1 byte length, unicode/ASCII string, all inline)
  35   A = ASCII string (input is unix string)
  36   B = data blob (pointer + length)
  37   b = data blob in header (pointer + length)
  38   D
  39   d = word (4 bytes)
  40   C = constant ascii string
  41  */
  42 bool msrpc_gen(DATA_BLOB *blob,
     /* [<][>][^][v][top][bottom][index][help] */
  43                const char *format, ...)
  44 {
  45         int i, n;
  46         va_list ap;
  47         char *s;
  48         uint8 *b;
  49         int head_size=0, data_size=0;
  50         int head_ofs, data_ofs;
  51 
  52         /* first scan the format to work out the header and body size */
  53         va_start(ap, format);
  54         for (i=0; format[i]; i++) {
  55                 switch (format[i]) {
  56                 case 'U':
  57                         s = va_arg(ap, char *);
  58                         head_size += 8;
  59                         data_size += str_charnum(s) * 2;
  60                         break;
  61                 case 'A':
  62                         s = va_arg(ap, char *);
  63                         head_size += 8;
  64                         data_size += str_ascii_charnum(s);
  65                         break;
  66                 case 'a':
  67                         n = va_arg(ap, int);
  68                         s = va_arg(ap, char *);
  69                         data_size += (str_charnum(s) * 2) + 4;
  70                         break;
  71                 case 'B':
  72                         b = va_arg(ap, uint8 *);
  73                         head_size += 8;
  74                         data_size += va_arg(ap, int);
  75                         break;
  76                 case 'b':
  77                         b = va_arg(ap, uint8 *);
  78                         head_size += va_arg(ap, int);
  79                         break;
  80                 case 'd':
  81                         n = va_arg(ap, int);
  82                         head_size += 4;
  83                         break;
  84                 case 'C':
  85                         s = va_arg(ap, char *);
  86                         head_size += str_charnum(s) + 1;
  87                         break;
  88                 }
  89         }
  90         va_end(ap);
  91 
  92         /* allocate the space, then scan the format
  93          * again to fill in the values */
  94 
  95         *blob = data_blob(NULL, head_size + data_size);
  96 
  97         head_ofs = 0;
  98         data_ofs = head_size;
  99 
 100         va_start(ap, format);
 101         for (i=0; format[i]; i++) {
 102                 switch (format[i]) {
 103                 case 'U':
 104                         s = va_arg(ap, char *);
 105                         n = str_charnum(s);
 106                         SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
 107                         SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
 108                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
 109                         push_string(NULL, blob->data+data_ofs,
 110                                         s, n*2, STR_UNICODE|STR_NOALIGN);
 111                         data_ofs += n*2;
 112                         break;
 113                 case 'A':
 114                         s = va_arg(ap, char *);
 115                         n = str_ascii_charnum(s);
 116                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
 117                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
 118                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
 119                         push_string(NULL, blob->data+data_ofs,
 120                                         s, n, STR_ASCII|STR_NOALIGN);
 121                         data_ofs += n;
 122                         break;
 123                 case 'a':
 124                         n = va_arg(ap, int);
 125                         SSVAL(blob->data, data_ofs, n); data_ofs += 2;
 126                         s = va_arg(ap, char *);
 127                         n = str_charnum(s);
 128                         SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
 129                         if (0 < n) {
 130                                 push_string(NULL, blob->data+data_ofs, s, n*2,
 131                                             STR_UNICODE|STR_NOALIGN);
 132                         }
 133                         data_ofs += n*2;
 134                         break;
 135 
 136                 case 'B':
 137                         b = va_arg(ap, uint8 *);
 138                         n = va_arg(ap, int);
 139                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
 140                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
 141                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
 142                         if (n && b) /* don't follow null pointers... */
 143                                 memcpy(blob->data+data_ofs, b, n);
 144                         data_ofs += n;
 145                         break;
 146                 case 'd':
 147                         n = va_arg(ap, int);
 148                         SIVAL(blob->data, head_ofs, n); head_ofs += 4;
 149                         break;
 150                 case 'b':
 151                         b = va_arg(ap, uint8 *);
 152                         n = va_arg(ap, int);
 153                         memcpy(blob->data + head_ofs, b, n);
 154                         head_ofs += n;
 155                         break;
 156                 case 'C':
 157                         s = va_arg(ap, char *);
 158                         n = str_charnum(s) + 1;
 159                         head_ofs += push_string(NULL, blob->data+head_ofs, s, n,
 160                                                 STR_ASCII|STR_TERMINATE);
 161                         break;
 162                 }
 163         }
 164         va_end(ap);
 165 
 166         return true;
 167 }
 168 
 169 
 170 /* a helpful macro to avoid running over the end of our blob */
 171 #define NEED_DATA(amount) \
 172 if ((head_ofs + amount) > blob->length) { \
 173         va_end(ap); \
 174         return False; \
 175 }
 176 
 177 /*
 178   this is a tiny msrpc packet parser. This the the partner of msrpc_gen
 179 
 180   format specifiers are:
 181 
 182   U = unicode string (output is unix string)
 183   A = ascii string
 184   B = data blob
 185   b = data blob in header
 186   d = word (4 bytes)
 187   C = constant ascii string
 188  */
 189 
 190 bool msrpc_parse(const DATA_BLOB *blob,
     /* [<][>][^][v][top][bottom][index][help] */
 191                  const char *format, ...)
 192 {
 193         int i;
 194         va_list ap;
 195         char **ps, *s;
 196         DATA_BLOB *b;
 197         size_t head_ofs = 0;
 198         uint16 len1, len2;
 199         uint32 ptr;
 200         uint32 *v;
 201 
 202         va_start(ap, format);
 203         for (i=0; format[i]; i++) {
 204                 switch (format[i]) {
 205                 case 'U':
 206                         NEED_DATA(8);
 207                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
 208                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
 209                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 210 
 211                         ps = va_arg(ap, char **);
 212                         if (len1 == 0 && len2 == 0) {
 213                                 *ps = smb_xstrdup("");
 214                         } else {
 215                                 /* make sure its in the right format
 216                                  * be strict */
 217                                 if ((len1 != len2) || (ptr + len1 < ptr) ||
 218                                                 (ptr + len1 < len1) ||
 219                                                 (ptr + len1 > blob->length)) {
 220                                         va_end(ap);
 221                                         return false;
 222                                 }
 223                                 if (len1 & 1) {
 224                                         /* if odd length and unicode */
 225                                         va_end(ap);
 226                                         return false;
 227                                 }
 228                                 if (blob->data + ptr <
 229                                                 (uint8 *)(unsigned long)ptr ||
 230                                     blob->data + ptr < blob->data) {
 231                                         va_end(ap);
 232                                         return false;
 233                                 }
 234 
 235                                 if (0 < len1) {
 236                                         char *p = NULL;
 237                                         pull_string_talloc(talloc_tos(),
 238                                                 NULL,
 239                                                 0,
 240                                                 &p,
 241                                                 blob->data + ptr,
 242                                                 len1,
 243                                                 STR_UNICODE|STR_NOALIGN);
 244                                         if (p) {
 245                                                 (*ps) = smb_xstrdup(p);
 246                                                 TALLOC_FREE(p);
 247                                         } else {
 248                                                 (*ps) = smb_xstrdup("");
 249                                         }
 250                                 } else {
 251                                         (*ps) = smb_xstrdup("");
 252                                 }
 253                         }
 254                         break;
 255                 case 'A':
 256                         NEED_DATA(8);
 257                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
 258                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
 259                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 260 
 261                         ps = va_arg(ap, char **);
 262                         /* make sure its in the right format - be strict */
 263                         if (len1 == 0 && len2 == 0) {
 264                                 *ps = smb_xstrdup("");
 265                         } else {
 266                                 if ((len1 != len2) || (ptr + len1 < ptr) ||
 267                                                 (ptr + len1 < len1) ||
 268                                                 (ptr + len1 > blob->length)) {
 269                                         va_end(ap);
 270                                         return false;
 271                                 }
 272 
 273                                 if (blob->data + ptr <
 274                                                 (uint8 *)(unsigned long)ptr ||
 275                                     blob->data + ptr < blob->data) {
 276                                         va_end(ap);
 277                                         return false;
 278                                 }
 279 
 280                                 if (0 < len1) {
 281                                         char *p = NULL;
 282                                         pull_string_talloc(talloc_tos(),
 283                                                 NULL,
 284                                                 0,
 285                                                 &p,
 286                                                 blob->data + ptr,
 287                                                 len1,
 288                                                 STR_ASCII|STR_NOALIGN);
 289                                         if (p) {
 290                                                 (*ps) = smb_xstrdup(p);
 291                                                 TALLOC_FREE(p);
 292                                         } else {
 293                                                 (*ps) = smb_xstrdup("");
 294                                         }
 295                                 } else {
 296                                         (*ps) = smb_xstrdup("");
 297                                 }
 298                         }
 299                         break;
 300                 case 'B':
 301                         NEED_DATA(8);
 302                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
 303                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
 304                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 305 
 306                         b = (DATA_BLOB *)va_arg(ap, void *);
 307                         if (len1 == 0 && len2 == 0) {
 308                                 *b = data_blob_null;
 309                         } else {
 310                                 /* make sure its in the right format
 311                                  * be strict */
 312                                 if ((len1 != len2) || (ptr + len1 < ptr) ||
 313                                                 (ptr + len1 < len1) ||
 314                                                 (ptr + len1 > blob->length)) {
 315                                         va_end(ap);
 316                                         return false;
 317                                 }
 318 
 319                                 if (blob->data + ptr <
 320                                                 (uint8 *)(unsigned long)ptr ||
 321                                     blob->data + ptr < blob->data) {
 322                                         va_end(ap);
 323                                         return false;
 324                                 }
 325 
 326                                 *b = data_blob(blob->data + ptr, len1);
 327                         }
 328                         break;
 329                 case 'b':
 330                         b = (DATA_BLOB *)va_arg(ap, void *);
 331                         len1 = va_arg(ap, unsigned);
 332                         /* make sure its in the right format - be strict */
 333                         NEED_DATA(len1);
 334                         if (blob->data + head_ofs < (uint8 *)head_ofs ||
 335                                         blob->data + head_ofs < blob->data) {
 336                                 va_end(ap);
 337                                 return false;
 338                         }
 339 
 340                         *b = data_blob(blob->data + head_ofs, len1);
 341                         head_ofs += len1;
 342                         break;
 343                 case 'd':
 344                         v = va_arg(ap, uint32 *);
 345                         NEED_DATA(4);
 346                         *v = IVAL(blob->data, head_ofs); head_ofs += 4;
 347                         break;
 348                 case 'C':
 349                         s = va_arg(ap, char *);
 350 
 351                         if (blob->data + head_ofs < (uint8 *)head_ofs ||
 352                             blob->data + head_ofs < blob->data) {
 353                                 va_end(ap);
 354                                 return false;
 355                         }
 356 
 357                         {
 358                                 char *p = NULL;
 359                                 size_t ret = pull_string_talloc(talloc_tos(),
 360                                                 NULL,
 361                                                 0,
 362                                                 &p,
 363                                                 blob->data+head_ofs,
 364                                                 blob->length - head_ofs,
 365                                                 STR_ASCII|STR_TERMINATE);
 366                                 if (ret == (size_t)-1 || p == NULL) {
 367                                         va_end(ap);
 368                                         return false;
 369                                 }
 370                                 head_ofs += ret;
 371                                 if (strcmp(s, p) != 0) {
 372                                         TALLOC_FREE(p);
 373                                         va_end(ap);
 374                                         return false;
 375                                 }
 376                                 TALLOC_FREE(p);
 377                         }
 378                         break;
 379                 }
 380         }
 381         va_end(ap);
 382 
 383         return True;
 384 }

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