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