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