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