/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- msrpc_gen
- 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 }