libcli/auth: add netlogon_creds_step_crypt() and netlogon_creds_first_step()
[kai/samba.git] / libcli / auth / msrpc_parse.c
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 bool 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         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(
70                                 pointers,
71                                 (smb_ucs2_t **)(void *)&pointers[i].data,
72                                 s, &n);
73                         if (!ret) {
74                                 va_end(ap);
75                                 return false;
76                         }
77                         pointers[i].length = n;
78                         pointers[i].length -= 2;
79                         data_size += pointers[i].length;
80                         break;
81                 case 'A':
82                         s = va_arg(ap, char *);
83                         head_size += 8;
84                         ret = push_ascii_talloc(
85                                 pointers, (char **)(void *)&pointers[i].data,
86                                 s, &n);
87                         if (!ret) {
88                                 va_end(ap);
89                                 return false;
90                         }
91                         pointers[i].length = n;
92                         pointers[i].length -= 1;
93                         data_size += pointers[i].length;
94                         break;
95                 case 'a':
96                         j = va_arg(ap, int);
97                         intargs[i] = j;
98                         s = va_arg(ap, char *);
99                         ret = push_ucs2_talloc(
100                                 pointers,
101                                 (smb_ucs2_t **)(void *)&pointers[i].data,
102                                 s, &n);
103                         if (!ret) {
104                                 va_end(ap);
105                                 return false;
106                         }
107                         pointers[i].length = n;
108                         pointers[i].length -= 2;
109                         data_size += pointers[i].length + 4;
110                         break;
111                 case 'B':
112                         b = va_arg(ap, uint8_t *);
113                         head_size += 8;
114                         pointers[i].data = b;
115                         pointers[i].length = va_arg(ap, int);
116                         data_size += pointers[i].length;
117                         break;
118                 case 'b':
119                         b = va_arg(ap, uint8_t *);
120                         pointers[i].data = b;
121                         pointers[i].length = va_arg(ap, int);
122                         head_size += pointers[i].length;
123                         break;
124                 case 'd':
125                         j = va_arg(ap, int);
126                         intargs[i] = j;
127                         head_size += 4;
128                         break;
129                 case 'C':
130                         s = va_arg(ap, char *);
131                         pointers[i].data = (uint8_t *)s;
132                         pointers[i].length = strlen(s)+1;
133                         head_size += pointers[i].length;
134                         break;
135                 }
136         }
137         va_end(ap);
138
139         /* allocate the space, then scan the format again to fill in the values */
140         *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
141
142         head_ofs = 0;
143         data_ofs = head_size;
144
145         va_start(ap, format);
146         for (i=0; format[i]; i++) {
147                 switch (format[i]) {
148                 case 'U':
149                 case 'A':
150                 case 'B':
151                         n = pointers[i].length;
152                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
153                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
154                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
155                         if (pointers[i].data && n) /* don't follow null pointers... */
156                                 memcpy(blob->data+data_ofs, pointers[i].data, n);
157                         data_ofs += n;
158                         break;
159                 case 'a':
160                         j = intargs[i];
161                         SSVAL(blob->data, data_ofs, j); data_ofs += 2;
162
163                         n = pointers[i].length;
164                         SSVAL(blob->data, data_ofs, n); data_ofs += 2;
165                         if (n >= 0) {
166                                 memcpy(blob->data+data_ofs, pointers[i].data, n);
167                         }
168                         data_ofs += n;
169                         break;
170                 case 'd':
171                         j = intargs[i];
172                         SIVAL(blob->data, head_ofs, j); 
173                         head_ofs += 4;
174                         break;
175                 case 'b':
176                         n = pointers[i].length;
177                         memcpy(blob->data + head_ofs, pointers[i].data, n);
178                         head_ofs += n;
179                         break;
180                 case 'C':
181                         n = pointers[i].length;
182                         memcpy(blob->data + head_ofs, pointers[i].data, n);
183                         head_ofs += n;
184                         break;
185                 }
186         }
187         va_end(ap);
188         
189         talloc_free(pointers);
190
191         return true;
192 }
193
194
195 /* a helpful macro to avoid running over the end of our blob */
196 #define NEED_DATA(amount) \
197 if ((head_ofs + amount) > blob->length) { \
198         va_end(ap); \
199         return false; \
200 }
201
202 /**
203   this is a tiny msrpc packet parser. This the the partner of msrpc_gen
204
205   format specifiers are:
206
207   U = unicode string (output is unix string)
208   A = ascii string
209   B = data blob
210   b = data blob in header
211   d = word (4 bytes)
212   C = constant ascii string
213  */
214
215 bool msrpc_parse(TALLOC_CTX *mem_ctx, 
216                  const DATA_BLOB *blob,
217                  const char *format, ...)
218 {
219         int i;
220         va_list ap;
221         char **ps, *s;
222         DATA_BLOB *b;
223         size_t head_ofs = 0;
224         uint16_t len1, len2;
225         uint32_t ptr;
226         uint32_t *v;
227         size_t p_len = 1024;
228         char *p = talloc_array(mem_ctx, char, p_len);
229         bool ret = true;
230
231         va_start(ap, format);
232         for (i=0; format[i]; i++) {
233                 switch (format[i]) {
234                 case 'U':
235                         NEED_DATA(8);
236                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
237                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
238                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
239
240                         ps = va_arg(ap, char **);
241                         if (len1 == 0 && len2 == 0) {
242                                 *ps = (char *)discard_const("");
243                         } else {
244                                 /* make sure its in the right format - be strict */
245                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
246                                         ret = false;
247                                         goto cleanup;
248                                 }
249                                 if (len1 & 1) {
250                                         /* if odd length and unicode */
251                                         ret = false;
252                                         goto cleanup;
253                                 }
254                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
255                                                 blob->data + ptr < blob->data) {
256                                         ret = false;
257                                         goto cleanup;
258                                 }
259
260                                 if (0 < len1) {
261                                         size_t pull_len;
262                                         if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
263                                                                    blob->data + ptr, len1, 
264                                                                    ps, &pull_len, false)) {
265                                                 ret = false;
266                                                 goto cleanup;
267                                         }
268                                 } else {
269                                         (*ps) = (char *)discard_const("");
270                                 }
271                         }
272                         break;
273                 case 'A':
274                         NEED_DATA(8);
275                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
276                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
277                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
278
279                         ps = (char **)va_arg(ap, char **);
280                         /* make sure its in the right format - be strict */
281                         if (len1 == 0 && len2 == 0) {
282                                 *ps = (char *)discard_const("");
283                         } else {
284                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
285                                         ret = false;
286                                         goto cleanup;
287                                 }
288
289                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
290                                                 blob->data + ptr < blob->data) {
291                                         ret = false;
292                                         goto cleanup;
293                                 }
294
295                                 if (0 < len1) {
296                                         size_t pull_len;
297
298                                         if (!convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, 
299                                                                    blob->data + ptr, len1, 
300                                                                    ps, &pull_len, false)) {
301                                                 ret = false;
302                                                 goto cleanup;
303                                         }
304                                 } else {
305                                         (*ps) = (char *)discard_const("");
306                                 }
307                         }
308                         break;
309                 case 'B':
310                         NEED_DATA(8);
311                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
312                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
313                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
314
315                         b = (DATA_BLOB *)va_arg(ap, void *);
316                         if (len1 == 0 && len2 == 0) {
317                                 *b = data_blob_talloc(mem_ctx, NULL, 0);
318                         } else {
319                                 /* make sure its in the right format - be strict */
320                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
321                                         ret = false;
322                                         goto cleanup;
323                                 }
324
325                                 if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
326                                                 blob->data + ptr < blob->data) {
327                                         ret = false;
328                                         goto cleanup;
329                                 }
330
331                                 *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
332                         }
333                         break;
334                 case 'b':
335                         b = (DATA_BLOB *)va_arg(ap, void *);
336                         len1 = va_arg(ap, uint_t);
337                         /* make sure its in the right format - be strict */
338                         NEED_DATA(len1);
339                         if (blob->data + head_ofs < (uint8_t *)head_ofs ||
340                                         blob->data + head_ofs < blob->data) {
341                                 ret = false;
342                                 goto cleanup;
343                         }
344
345                         *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
346                         head_ofs += len1;
347                         break;
348                 case 'd':
349                         v = va_arg(ap, uint32_t *);
350                         NEED_DATA(4);
351                         *v = IVAL(blob->data, head_ofs); head_ofs += 4;
352                         break;
353                 case 'C':
354                         s = va_arg(ap, char *);
355
356                         if (blob->data + head_ofs < (uint8_t *)head_ofs ||
357                                         blob->data + head_ofs < blob->data ||
358                             (head_ofs + (strlen(s) + 1)) > blob->length) {
359                                 ret = false;
360                                 goto cleanup;
361                         }
362
363                         if (memcmp(blob->data + head_ofs, s, strlen(s)+1) != 0) {
364                                 ret = false;
365                                 goto cleanup;
366                         }
367                         head_ofs += (strlen(s) + 1);
368
369                         break;
370                 }
371         }
372
373 cleanup:
374         va_end(ap);
375         talloc_free(p);
376         return ret;
377 }