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 164975 : NTSTATUS msrpc_gen(TALLOC_CTX *mem_ctx,
44 : DATA_BLOB *blob,
45 : const char *format, ...)
46 : {
47 1404 : int i, j;
48 1404 : bool ret;
49 1404 : va_list ap;
50 1404 : char *s;
51 1404 : uint8_t *b;
52 164975 : int head_size=0, data_size=0;
53 1404 : int head_ofs, data_ofs;
54 1404 : int *intargs;
55 1404 : size_t n;
56 :
57 1404 : DATA_BLOB *pointers;
58 :
59 164975 : pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format));
60 164975 : if (!pointers) {
61 0 : return NT_STATUS_NO_MEMORY;
62 : }
63 164975 : intargs = talloc_array(pointers, int, strlen(format));
64 164975 : 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 164975 : va_start(ap, format);
70 1430367 : for (i=0; format[i]; i++) {
71 1265392 : switch (format[i]) {
72 150151 : case 'U':
73 150151 : s = va_arg(ap, char *);
74 150151 : head_size += 8;
75 150743 : ret = push_ucs2_talloc(
76 : pointers,
77 150151 : (smb_ucs2_t **)(void *)&pointers[i].data,
78 : s, &n);
79 150151 : if (!ret) {
80 0 : va_end(ap);
81 0 : return map_nt_error_from_unix_common(errno);
82 : }
83 150151 : pointers[i].length = n;
84 150151 : pointers[i].length -= 2;
85 150151 : data_size += pointers[i].length;
86 1257343 : break;
87 77306 : case 'A':
88 77306 : s = va_arg(ap, char *);
89 77306 : head_size += 8;
90 77898 : ret = push_ascii_talloc(
91 77306 : pointers, (char **)(void *)&pointers[i].data,
92 : s, &n);
93 77306 : if (!ret) {
94 0 : va_end(ap);
95 0 : return map_nt_error_from_unix_common(errno);
96 : }
97 77306 : pointers[i].length = n;
98 77306 : pointers[i].length -= 1;
99 77306 : data_size += pointers[i].length;
100 77306 : 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 150151 : case 'B':
118 150151 : b = va_arg(ap, uint8_t *);
119 150151 : head_size += 8;
120 150151 : pointers[i].data = b;
121 150151 : pointers[i].length = va_arg(ap, int);
122 150151 : data_size += pointers[i].length;
123 150151 : break;
124 314808 : case 'b':
125 314808 : b = va_arg(ap, uint8_t *);
126 314808 : pointers[i].data = b;
127 314808 : pointers[i].length = va_arg(ap, int);
128 314808 : head_size += pointers[i].length;
129 314808 : break;
130 441437 : case 'd':
131 441437 : j = va_arg(ap, int);
132 441437 : intargs[i] = j;
133 441437 : head_size += 4;
134 441437 : break;
135 113630 : case 'C':
136 113630 : s = va_arg(ap, char *);
137 113630 : pointers[i].data = (uint8_t *)s;
138 113630 : pointers[i].length = strlen(s)+1;
139 113630 : head_size += pointers[i].length;
140 113630 : break;
141 0 : default:
142 0 : va_end(ap);
143 0 : return NT_STATUS_INVALID_PARAMETER;
144 : }
145 : }
146 164975 : va_end(ap);
147 :
148 164975 : 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 164975 : *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
154 164975 : if (!blob->data) {
155 0 : return NT_STATUS_NO_MEMORY;
156 : }
157 164975 : head_ofs = 0;
158 164975 : data_ofs = head_size;
159 :
160 164975 : va_start(ap, format);
161 1430367 : for (i=0; format[i]; i++) {
162 1265392 : switch (format[i]) {
163 377608 : case 'U':
164 : case 'A':
165 : case 'B':
166 377608 : n = pointers[i].length;
167 377608 : SSVAL(blob->data, head_ofs, n); head_ofs += 2;
168 377608 : SSVAL(blob->data, head_ofs, n); head_ofs += 2;
169 377608 : SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
170 377608 : if (pointers[i].data && n) /* don't follow null pointers... */
171 295357 : memcpy(blob->data+data_ofs, pointers[i].data, n);
172 377608 : data_ofs += n;
173 1258527 : 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 441437 : case 'd':
184 441437 : j = intargs[i];
185 441437 : SIVAL(blob->data, head_ofs, j);
186 441437 : head_ofs += 4;
187 441437 : break;
188 314808 : case 'b':
189 314808 : n = pointers[i].length;
190 314808 : if (pointers[i].data && n) {
191 : /* don't follow null pointers... */
192 314808 : memcpy(blob->data + head_ofs, pointers[i].data, n);
193 : }
194 314808 : head_ofs += n;
195 314808 : break;
196 113630 : case 'C':
197 113630 : n = pointers[i].length;
198 113630 : memcpy(blob->data + head_ofs, pointers[i].data, n);
199 113630 : head_ofs += n;
200 113630 : break;
201 0 : default:
202 0 : va_end(ap);
203 0 : return NT_STATUS_INVALID_PARAMETER;
204 : }
205 : }
206 164975 : va_end(ap);
207 :
208 164975 : talloc_free(pointers);
209 :
210 164975 : 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 262633 : bool msrpc_parse(TALLOC_CTX *mem_ctx,
235 : const DATA_BLOB *blob,
236 : const char *format, ...)
237 : {
238 1036 : int i;
239 1036 : va_list ap;
240 1036 : char **ps, *s;
241 1036 : DATA_BLOB *b;
242 262633 : size_t head_ofs = 0;
243 1036 : uint16_t len1, len2;
244 1036 : uint32_t ptr;
245 1036 : uint32_t *v;
246 262633 : bool ret = true;
247 :
248 262633 : va_start(ap, format);
249 1462636 : for (i=0; format[i]; i++) {
250 1200003 : switch (format[i]) {
251 149530 : case 'U':
252 149530 : NEED_DATA(8);
253 149530 : len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
254 149530 : len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
255 149530 : ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
256 :
257 149530 : ps = va_arg(ap, char **);
258 149530 : if (len1 == 0 && len2 == 0) {
259 3115 : *ps = talloc_strdup(mem_ctx, "");
260 3115 : 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 146415 : if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
267 0 : ret = false;
268 0 : goto cleanup;
269 : }
270 146415 : if (len1 & 1) {
271 : /* if odd length and unicode */
272 0 : ret = false;
273 0 : goto cleanup;
274 : }
275 146415 : 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 146415 : if (0 < len1) {
282 556 : size_t pull_len;
283 146415 : if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
284 145859 : 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 148938 : 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 187271 : case 'B':
343 187271 : NEED_DATA(8);
344 187271 : len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
345 187271 : len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
346 187271 : ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
347 :
348 187271 : b = (DATA_BLOB *)va_arg(ap, void *);
349 187271 : if (len1 == 0 && len2 == 0) {
350 2016 : *b = data_blob_talloc(mem_ctx, NULL, 0);
351 : } else {
352 : /* make sure its in the right format - be strict */
353 185255 : if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
354 0 : ret = false;
355 0 : goto cleanup;
356 : }
357 :
358 185255 : 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 185255 : *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
365 : }
366 186531 : break;
367 112267 : case 'b':
368 112267 : b = (DATA_BLOB *)va_arg(ap, void *);
369 112267 : len1 = va_arg(ap, unsigned int);
370 : /* make sure its in the right format - be strict */
371 112267 : NEED_DATA(len1);
372 112267 : if (blob->data + head_ofs < (uint8_t *)head_ofs ||
373 112267 : blob->data + head_ofs < blob->data) {
374 0 : ret = false;
375 0 : goto cleanup;
376 : }
377 :
378 112267 : *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
379 112267 : head_ofs += len1;
380 112267 : break;
381 488302 : case 'd':
382 488302 : v = va_arg(ap, uint32_t *);
383 488302 : NEED_DATA(4);
384 488302 : *v = IVAL(blob->data, head_ofs); head_ofs += 4;
385 488302 : break;
386 262633 : case 'C':
387 262633 : s = va_arg(ap, char *);
388 :
389 262633 : if (blob->data + head_ofs < (uint8_t *)head_ofs ||
390 262633 : blob->data + head_ofs < blob->data ||
391 262633 : (head_ofs + (strlen(s) + 1)) > blob->length) {
392 0 : ret = false;
393 0 : goto cleanup;
394 : }
395 :
396 262633 : if (memcmp(blob->data + head_ofs, s, strlen(s)+1) != 0) {
397 0 : ret = false;
398 0 : goto cleanup;
399 : }
400 261597 : head_ofs += (strlen(s) + 1);
401 :
402 261597 : break;
403 : }
404 : }
405 :
406 262633 : cleanup:
407 262633 : va_end(ap);
408 262633 : return ret;
409 : }
|