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 variant 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 167816 : NTSTATUS msrpc_gen(TALLOC_CTX *mem_ctx,
44 : DATA_BLOB *blob,
45 : const char *format, ...)
46 : {
47 1462 : int i, j;
48 1462 : bool ret;
49 1462 : va_list ap;
50 1462 : char *s;
51 1462 : uint8_t *b;
52 167816 : int head_size=0, data_size=0;
53 1462 : int head_ofs, data_ofs;
54 1462 : int *intargs;
55 1462 : size_t n;
56 :
57 1462 : DATA_BLOB *pointers;
58 :
59 167816 : pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format));
60 167816 : if (!pointers) {
61 0 : return NT_STATUS_NO_MEMORY;
62 : }
63 167816 : intargs = talloc_array(pointers, int, strlen(format));
64 167816 : 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 167816 : va_start(ap, format);
70 1456308 : for (i=0; format[i]; i++) {
71 1288492 : switch (format[i]) {
72 153157 : case 'U':
73 153157 : s = va_arg(ap, char *);
74 153157 : head_size += 8;
75 153817 : ret = push_ucs2_talloc(
76 : pointers,
77 153157 : (smb_ucs2_t **)(void *)&pointers[i].data,
78 : s, &n);
79 153157 : if (!ret) {
80 0 : va_end(ap);
81 0 : return map_nt_error_from_unix_common(errno);
82 : }
83 153157 : pointers[i].length = n;
84 153157 : pointers[i].length -= 2;
85 153157 : data_size += pointers[i].length;
86 1280027 : break;
87 78782 : case 'A':
88 78782 : s = va_arg(ap, char *);
89 78782 : head_size += 8;
90 79408 : ret = push_ascii_talloc(
91 78782 : pointers, (char **)(void *)&pointers[i].data,
92 : s, &n);
93 78782 : if (!ret) {
94 0 : va_end(ap);
95 0 : return map_nt_error_from_unix_common(errno);
96 : }
97 78782 : pointers[i].length = n;
98 78782 : pointers[i].length -= 1;
99 78782 : data_size += pointers[i].length;
100 78782 : break;
101 17909 : case 'a':
102 17909 : j = va_arg(ap, int);
103 17909 : intargs[i] = j;
104 17909 : s = va_arg(ap, char *);
105 18850 : ret = push_ucs2_talloc(
106 : pointers,
107 17909 : (smb_ucs2_t **)(void *)&pointers[i].data,
108 : s, &n);
109 17909 : if (!ret) {
110 0 : va_end(ap);
111 0 : return map_nt_error_from_unix_common(errno);
112 : }
113 17909 : pointers[i].length = n;
114 17909 : pointers[i].length -= 2;
115 17909 : data_size += pointers[i].length + 4;
116 17909 : break;
117 153157 : case 'B':
118 153157 : b = va_arg(ap, uint8_t *);
119 153157 : head_size += 8;
120 153157 : pointers[i].data = b;
121 153157 : pointers[i].length = va_arg(ap, int);
122 153157 : data_size += pointers[i].length;
123 153157 : break;
124 320331 : case 'b':
125 320331 : b = va_arg(ap, uint8_t *);
126 320331 : pointers[i].data = b;
127 320331 : pointers[i].length = va_arg(ap, int);
128 320331 : head_size += pointers[i].length;
129 320331 : break;
130 449264 : case 'd':
131 449264 : j = va_arg(ap, int);
132 449264 : intargs[i] = j;
133 449264 : head_size += 4;
134 449264 : break;
135 115892 : case 'C':
136 115892 : s = va_arg(ap, char *);
137 115892 : pointers[i].data = (uint8_t *)s;
138 115892 : pointers[i].length = strlen(s)+1;
139 115892 : head_size += pointers[i].length;
140 115892 : break;
141 0 : default:
142 0 : va_end(ap);
143 0 : return NT_STATUS_INVALID_PARAMETER;
144 : }
145 : }
146 167816 : va_end(ap);
147 :
148 167816 : 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 167816 : *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
154 167816 : if (!blob->data) {
155 0 : return NT_STATUS_NO_MEMORY;
156 : }
157 167816 : head_ofs = 0;
158 167816 : data_ofs = head_size;
159 :
160 167816 : va_start(ap, format);
161 1456308 : for (i=0; format[i]; i++) {
162 1288492 : switch (format[i]) {
163 385096 : case 'U':
164 : case 'A':
165 : case 'B':
166 385096 : n = pointers[i].length;
167 385096 : SSVAL(blob->data, head_ofs, n); head_ofs += 2;
168 385096 : SSVAL(blob->data, head_ofs, n); head_ofs += 2;
169 385096 : SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
170 385096 : if (pointers[i].data && n) /* don't follow null pointers... */
171 300551 : memcpy(blob->data+data_ofs, pointers[i].data, n);
172 385096 : data_ofs += n;
173 1281313 : break;
174 17909 : case 'a':
175 17909 : j = intargs[i];
176 17909 : SSVAL(blob->data, data_ofs, j); data_ofs += 2;
177 :
178 17909 : n = pointers[i].length;
179 17909 : SSVAL(blob->data, data_ofs, n); data_ofs += 2;
180 17909 : memcpy(blob->data+data_ofs, pointers[i].data, n);
181 17909 : data_ofs += n;
182 17909 : break;
183 449264 : case 'd':
184 449264 : j = intargs[i];
185 449264 : SIVAL(blob->data, head_ofs, j);
186 449264 : head_ofs += 4;
187 449264 : break;
188 320331 : case 'b':
189 320331 : n = pointers[i].length;
190 320331 : if (pointers[i].data && n) {
191 : /* don't follow null pointers... */
192 320331 : memcpy(blob->data + head_ofs, pointers[i].data, n);
193 : }
194 320331 : head_ofs += n;
195 320331 : break;
196 115892 : case 'C':
197 115892 : n = pointers[i].length;
198 115892 : memcpy(blob->data + head_ofs, pointers[i].data, n);
199 115892 : head_ofs += n;
200 115892 : break;
201 0 : default:
202 0 : va_end(ap);
203 0 : return NT_STATUS_INVALID_PARAMETER;
204 : }
205 : }
206 167816 : va_end(ap);
207 :
208 167816 : talloc_free(pointers);
209 :
210 167816 : 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 267985 : bool msrpc_parse(TALLOC_CTX *mem_ctx,
235 : const DATA_BLOB *blob,
236 : const char *format, ...)
237 : {
238 1155 : int i;
239 1155 : va_list ap;
240 1155 : char **ps, *s;
241 1155 : DATA_BLOB *b;
242 267985 : size_t head_ofs = 0;
243 1155 : uint16_t len1, len2;
244 1155 : uint32_t ptr;
245 1155 : uint32_t *v;
246 267985 : bool ret = true;
247 :
248 267985 : va_start(ap, format);
249 1492453 : for (i=0; format[i]; i++) {
250 1224468 : switch (format[i]) {
251 152626 : case 'U':
252 152626 : NEED_DATA(8);
253 152626 : len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
254 152626 : len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
255 152626 : ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
256 :
257 152626 : ps = va_arg(ap, char **);
258 152626 : if (len1 == 0 && len2 == 0) {
259 3620 : *ps = talloc_strdup(mem_ctx, "");
260 3620 : 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 149006 : if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
267 0 : ret = false;
268 0 : goto cleanup;
269 : }
270 149006 : if (len1 & 1) {
271 : /* if odd length and unicode */
272 0 : ret = false;
273 0 : goto cleanup;
274 : }
275 149006 : if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
276 : blob->data + ptr < blob->data) {
277 0 : ret = false;
278 0 : goto cleanup;
279 : }
280 :
281 149006 : if (0 < len1) {
282 594 : size_t pull_len;
283 149006 : if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
284 148412 : 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 151966 : 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 : blob->data + ptr < blob->data) {
320 0 : ret = false;
321 0 : goto cleanup;
322 : }
323 :
324 0 : if (0 < len1) {
325 0 : 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 191105 : case 'B':
343 191105 : NEED_DATA(8);
344 191105 : len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
345 191105 : len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
346 191105 : ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
347 :
348 191105 : b = (DATA_BLOB *)va_arg(ap, void *);
349 191105 : if (len1 == 0 && len2 == 0) {
350 2348 : *b = data_blob_talloc(mem_ctx, NULL, 0);
351 : } else {
352 : /* make sure its in the right format - be strict */
353 188757 : if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
354 0 : ret = false;
355 0 : goto cleanup;
356 : }
357 :
358 188757 : if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
359 : blob->data + ptr < blob->data) {
360 0 : ret = false;
361 0 : goto cleanup;
362 : }
363 :
364 188757 : *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
365 : }
366 190280 : break;
367 114577 : case 'b':
368 114577 : b = (DATA_BLOB *)va_arg(ap, void *);
369 114577 : len1 = va_arg(ap, unsigned int);
370 : /* make sure its in the right format - be strict */
371 114577 : NEED_DATA(len1);
372 114577 : if (blob->data + head_ofs < (uint8_t *)head_ofs ||
373 114577 : blob->data + head_ofs < blob->data) {
374 0 : ret = false;
375 0 : goto cleanup;
376 : }
377 :
378 114577 : *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
379 114577 : head_ofs += len1;
380 114577 : break;
381 498175 : case 'd':
382 498175 : v = va_arg(ap, uint32_t *);
383 498175 : NEED_DATA(4);
384 498175 : *v = IVAL(blob->data, head_ofs); head_ofs += 4;
385 498175 : break;
386 267985 : case 'C':
387 267985 : s = va_arg(ap, char *);
388 :
389 267985 : if (blob->data + head_ofs < (uint8_t *)head_ofs ||
390 267985 : blob->data + head_ofs < blob->data ||
391 267985 : (head_ofs + (strlen(s) + 1)) > blob->length) {
392 0 : ret = false;
393 0 : goto cleanup;
394 : }
395 :
396 267985 : if (memcmp(blob->data + head_ofs, s, strlen(s)+1) != 0) {
397 0 : ret = false;
398 0 : goto cleanup;
399 : }
400 266830 : head_ofs += (strlen(s) + 1);
401 :
402 266830 : break;
403 : }
404 : }
405 :
406 267985 : cleanup:
407 267985 : va_end(ap);
408 267985 : return ret;
409 : }
|