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 2 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, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23#include "includes.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 */ 43BOOL msrpc_gen(DATA_BLOB *blob, 44 const char *format, ...) 45{ 46 int i, n; 47 va_list ap; 48 char *s; 49 uint8 *b; 50 int head_size=0, data_size=0; 51 int head_ofs, data_ofs; 52 53 /* first scan the format to work out the header and body size */ 54 va_start(ap, format); 55 for (i=0; format[i]; i++) { 56 switch (format[i]) { 57 case 'U': 58 s = va_arg(ap, char *); 59 head_size += 8; 60 data_size += str_charnum(s) * 2; 61 break; 62 case 'A': 63 s = va_arg(ap, char *); 64 head_size += 8; 65 data_size += str_ascii_charnum(s); 66 break; 67 case 'a': 68 n = va_arg(ap, int); 69 s = va_arg(ap, char *); 70 data_size += (str_charnum(s) * 2) + 4; 71 break; 72 case 'B': 73 b = va_arg(ap, uint8 *); 74 head_size += 8; 75 data_size += va_arg(ap, int); 76 break; 77 case 'b': 78 b = va_arg(ap, uint8 *); 79 head_size += va_arg(ap, int); 80 break; 81 case 'd': 82 n = va_arg(ap, int); 83 head_size += 4; 84 break; 85 case 'C': 86 s = va_arg(ap, char *); 87 head_size += str_charnum(s) + 1; 88 break; 89 } 90 } 91 va_end(ap); 92 93 /* allocate the space, then scan the format again to fill in the values */ 94 *blob = data_blob(NULL, head_size + data_size); 95 96 head_ofs = 0; 97 data_ofs = head_size; 98 99 va_start(ap, format); 100 for (i=0; format[i]; i++) { 101 switch (format[i]) { 102 case 'U': 103 s = va_arg(ap, char *); 104 n = str_charnum(s); 105 SSVAL(blob->data, head_ofs, n*2); head_ofs += 2; 106 SSVAL(blob->data, head_ofs, n*2); head_ofs += 2; 107 SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4; 108 push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN); 109 data_ofs += n*2; 110 break; 111 case 'A': 112 s = va_arg(ap, char *); 113 n = str_ascii_charnum(s); 114 SSVAL(blob->data, head_ofs, n); head_ofs += 2; 115 SSVAL(blob->data, head_ofs, n); head_ofs += 2; 116 SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4; 117 push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN); 118 data_ofs += n; 119 break; 120 case 'a': 121 n = va_arg(ap, int); 122 SSVAL(blob->data, data_ofs, n); data_ofs += 2; 123 s = va_arg(ap, char *); 124 n = str_charnum(s); 125 SSVAL(blob->data, data_ofs, n*2); data_ofs += 2; 126 if (0 < n) { 127 push_string(NULL, blob->data+data_ofs, s, n*2, 128 STR_UNICODE|STR_NOALIGN); 129 } 130 data_ofs += n*2; 131 break; 132 133 case 'B': 134 b = va_arg(ap, uint8 *); 135 n = va_arg(ap, int); 136 SSVAL(blob->data, head_ofs, n); head_ofs += 2; 137 SSVAL(blob->data, head_ofs, n); head_ofs += 2; 138 SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4; 139 if (n && b) /* don't follow null pointers... */ 140 memcpy(blob->data+data_ofs, b, n); 141 data_ofs += n; 142 break; 143 case 'd': 144 n = va_arg(ap, int); 145 SIVAL(blob->data, head_ofs, n); head_ofs += 4; 146 break; 147 case 'b': 148 b = va_arg(ap, uint8 *); 149 n = va_arg(ap, int); 150 memcpy(blob->data + head_ofs, b, n); 151 head_ofs += n; 152 break; 153 case 'C': 154 s = va_arg(ap, char *); 155 head_ofs += push_string(NULL, blob->data+head_ofs, s, -1, 156 STR_ASCII|STR_TERMINATE); 157 break; 158 } 159 } 160 va_end(ap); 161 162 return True; 163} 164 165 166/* a helpful macro to avoid running over the end of our blob */ 167#define NEED_DATA(amount) \ 168if ((head_ofs + amount) > blob->length) { \ 169 return False; \ 170} 171 172/* 173 this is a tiny msrpc packet parser. This the the partner of msrpc_gen 174 175 format specifiers are: 176 177 U = unicode string (output is unix string) 178 A = ascii string 179 B = data blob 180 b = data blob in header 181 d = word (4 bytes) 182 C = constant ascii string 183 */ 184 185BOOL msrpc_parse(const DATA_BLOB *blob, 186 const char *format, ...) 187{ 188 int i; 189 va_list ap; 190 char **ps, *s; 191 DATA_BLOB *b; 192 size_t head_ofs = 0; 193 uint16 len1, len2; 194 uint32 ptr; 195 uint32 *v; 196 pstring p; 197 198 va_start(ap, format); 199 for (i=0; format[i]; i++) { 200 switch (format[i]) { 201 case 'U': 202 NEED_DATA(8); 203 len1 = SVAL(blob->data, head_ofs); head_ofs += 2; 204 len2 = SVAL(blob->data, head_ofs); head_ofs += 2; 205 ptr = IVAL(blob->data, head_ofs); head_ofs += 4; 206 207 ps = va_arg(ap, char **); 208 if (len1 == 0 && len2 == 0) { 209 *ps = smb_xstrdup(""); 210 } else { 211 /* make sure its in the right format - be strict */ 212 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { 213 return False; 214 } 215 if (len1 & 1) { 216 /* if odd length and unicode */ 217 return False; 218 } 219 if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data) 220 return False; 221 222 if (0 < len1) { 223 pull_string(NULL, p, blob->data + ptr, sizeof(p), 224 len1, 225 STR_UNICODE|STR_NOALIGN); 226 (*ps) = smb_xstrdup(p); 227 } else { 228 (*ps) = smb_xstrdup(""); 229 } 230 } 231 break; 232 case 'A': 233 NEED_DATA(8); 234 len1 = SVAL(blob->data, head_ofs); head_ofs += 2; 235 len2 = SVAL(blob->data, head_ofs); head_ofs += 2; 236 ptr = IVAL(blob->data, head_ofs); head_ofs += 4; 237 238 ps = va_arg(ap, char **); 239 /* make sure its in the right format - be strict */ 240 if (len1 == 0 && len2 == 0) { 241 *ps = smb_xstrdup(""); 242 } else { 243 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { 244 return False; 245 } 246 247 if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data) 248 return False; 249 250 if (0 < len1) { 251 pull_string(NULL, p, blob->data + ptr, sizeof(p), 252 len1, 253 STR_ASCII|STR_NOALIGN); 254 (*ps) = smb_xstrdup(p); 255 } else { 256 (*ps) = smb_xstrdup(""); 257 } 258 } 259 break; 260 case 'B': 261 NEED_DATA(8); 262 len1 = SVAL(blob->data, head_ofs); head_ofs += 2; 263 len2 = SVAL(blob->data, head_ofs); head_ofs += 2; 264 ptr = IVAL(blob->data, head_ofs); head_ofs += 4; 265 266 b = (DATA_BLOB *)va_arg(ap, void *); 267 if (len1 == 0 && len2 == 0) { 268 *b = data_blob(NULL, 0); 269 } else { 270 /* make sure its in the right format - be strict */ 271 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { 272 return False; 273 } 274 275 if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data) 276 return False; 277 278 *b = data_blob(blob->data + ptr, len1); 279 } 280 break; 281 case 'b': 282 b = (DATA_BLOB *)va_arg(ap, void *); 283 len1 = va_arg(ap, unsigned); 284 /* make sure its in the right format - be strict */ 285 NEED_DATA(len1); 286 if (blob->data + head_ofs < (uint8 *)head_ofs || blob->data + head_ofs < blob->data) 287 return False; 288 289 *b = data_blob(blob->data + head_ofs, len1); 290 head_ofs += len1; 291 break; 292 case 'd': 293 v = va_arg(ap, uint32 *); 294 NEED_DATA(4); 295 *v = IVAL(blob->data, head_ofs); head_ofs += 4; 296 break; 297 case 'C': 298 s = va_arg(ap, char *); 299 300 if (blob->data + head_ofs < (uint8 *)head_ofs || blob->data + head_ofs < blob->data) 301 return False; 302 303 head_ofs += pull_string(NULL, p, blob->data+head_ofs, sizeof(p), 304 blob->length - head_ofs, 305 STR_ASCII|STR_TERMINATE); 306 if (strcmp(s, p) != 0) { 307 return False; 308 } 309 break; 310 } 311 } 312 va_end(ap); 313 314 return True; 315} 316