r6112: try to decompress all chunks and put them together
[samba.git] / source / libcli / auth / 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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "pstring.h"
25
26 /*
27   this is a tiny msrpc packet generator. I am only using this to
28   avoid tying this code to a particular varient of our rpc code. This
29   generator is not general enough for all our rpc needs, its just
30   enough for the spnego/ntlmssp code
31
32   format specifiers are:
33
34   U = unicode string (input is unix string)
35   a = address (input is char *unix_string)
36       (1 byte type, 1 byte length, unicode/ASCII string, all inline)
37   A = ASCII string (input is unix string)
38   B = data blob (pointer + length)
39   b = data blob in header (pointer + length)
40   D
41   d = word (4 bytes)
42   C = constant ascii string
43  */
44 BOOL msrpc_gen(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
45                const char *format, ...)
46 {
47         int i;
48         ssize_t n;
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
56         DATA_BLOB *pointers;
57
58         pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format));
59         intargs = talloc_array(pointers, int, strlen(format));
60
61         /* first scan the format to work out the header and body size */
62         va_start(ap, format);
63         for (i=0; format[i]; i++) {
64                 switch (format[i]) {
65                 case 'U':
66                         s = va_arg(ap, char *);
67                         head_size += 8;
68                         n = push_ucs2_talloc(pointers, (void **)&pointers[i].data, s);
69                         if (n == -1) {
70                                 return False;
71                         }
72                         pointers[i].length = n;
73                         pointers[i].length -= 2;
74                         data_size += pointers[i].length;
75                         break;
76                 case 'A':
77                         s = va_arg(ap, char *);
78                         head_size += 8;
79                         n = push_ascii_talloc(pointers, (char **)&pointers[i].data, s);
80                         if (n == -1) {
81                                 return False;
82                         }
83                         pointers[i].length = n;
84                         pointers[i].length -= 1;
85                         data_size += pointers[i].length;
86                         break;
87                 case 'a':
88                         n = va_arg(ap, int);
89                         intargs[i] = n;
90                         s = va_arg(ap, char *);
91                         n = push_ucs2_talloc(pointers, (void **)&pointers[i].data, s);
92                         if (n == -1) {
93                                 return False;
94                         }
95                         pointers[i].length = n;
96                         pointers[i].length -= 2;
97                         data_size += pointers[i].length + 4;
98                         break;
99                 case 'B':
100                         b = va_arg(ap, uint8_t *);
101                         head_size += 8;
102                         pointers[i].data = b;
103                         pointers[i].length = va_arg(ap, int);
104                         data_size += pointers[i].length;
105                         break;
106                 case 'b':
107                         b = va_arg(ap, uint8_t *);
108                         pointers[i].data = b;
109                         pointers[i].length = va_arg(ap, int);
110                         head_size += pointers[i].length;
111                         break;
112                 case 'd':
113                         n = va_arg(ap, int);
114                         intargs[i] = n;
115                         head_size += 4;
116                         break;
117                 case 'C':
118                         s = va_arg(ap, char *);
119                         pointers[i].data = (uint8_t *)s;
120                         pointers[i].length = strlen(s)+1;
121                         head_size += pointers[i].length;
122                         break;
123                 }
124         }
125         va_end(ap);
126
127         /* allocate the space, then scan the format again to fill in the values */
128         *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
129
130         head_ofs = 0;
131         data_ofs = head_size;
132
133         va_start(ap, format);
134         for (i=0; format[i]; i++) {
135                 switch (format[i]) {
136                 case 'U':
137                 case 'A':
138                 case 'B':
139                         n = pointers[i].length;
140                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
141                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
142                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
143                         if (pointers[i].data && n) /* don't follow null pointers... */
144                                 memcpy(blob->data+data_ofs, pointers[i].data, n);
145                         data_ofs += n;
146                         break;
147                 case 'a':
148                         n = intargs[i];
149                         SSVAL(blob->data, data_ofs, n); data_ofs += 2;
150
151                         n = pointers[i].length;
152                         SSVAL(blob->data, data_ofs, n); data_ofs += 2;
153                         if (n >= 0) {
154                                 memcpy(blob->data+data_ofs, pointers[i].data, n);
155                         }
156                         data_ofs += n;
157                         break;
158                 case 'd':
159                         n = intargs[i];
160                         SIVAL(blob->data, head_ofs, n); 
161                         head_ofs += 4;
162                         break;
163                 case 'b':
164                         n = pointers[i].length;
165                         memcpy(blob->data + head_ofs, pointers[i].data, n);
166                         head_ofs += n;
167                         break;
168                 case 'C':
169                         n = pointers[i].length;
170                         memcpy(blob->data + head_ofs, pointers[i].data, n);
171                         head_ofs += n;
172                         break;
173                 }
174         }
175         va_end(ap);
176         
177         talloc_free(pointers);
178
179         return True;
180 }
181
182
183 /* a helpful macro to avoid running over the end of our blob */
184 #define NEED_DATA(amount) \
185 if ((head_ofs + amount) > blob->length) { \
186         return False; \
187 }
188
189 /*
190   this is a tiny msrpc packet parser. This the the partner of msrpc_gen
191
192   format specifiers are:
193
194   U = unicode string (output is unix string)
195   A = ascii string
196   B = data blob
197   b = data blob in header
198   d = word (4 bytes)
199   C = constant ascii string
200  */
201
202 BOOL msrpc_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob,
203                  const char *format, ...)
204 {
205         int i;
206         va_list ap;
207         const char **ps, *s;
208         DATA_BLOB *b;
209         size_t head_ofs = 0;
210         uint16_t len1, len2;
211         uint32_t ptr;
212         uint32_t *v;
213         pstring p;
214
215         va_start(ap, format);
216         for (i=0; format[i]; i++) {
217                 switch (format[i]) {
218                 case 'U':
219                         NEED_DATA(8);
220                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
221                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
222                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
223
224                         ps = (const char **)va_arg(ap, char **);
225                         if (len1 == 0 && len2 == 0) {
226                                 *ps = "";
227                         } else {
228                                 /* make sure its in the right format - be strict */
229                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
230                                         return False;
231                                 }
232                                 if (len1 & 1) {
233                                         /* if odd length and unicode */
234                                         return False;
235                                 }
236                                 if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data)
237                                         return False;
238
239                                 if (0 < len1) {
240                                         pull_string(p, blob->data + ptr, sizeof(p), 
241                                                     len1, 
242                                                     STR_UNICODE|STR_NOALIGN);
243                                         (*ps) = talloc_strdup(mem_ctx, p);
244                                         if (!(*ps)) {
245                                                 return False;
246                                         }
247                                 } else {
248                                         (*ps) = "";
249                                 }
250                         }
251                         break;
252                 case 'A':
253                         NEED_DATA(8);
254                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
255                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
256                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
257
258                         ps = (const char **)va_arg(ap, char **);
259                         /* make sure its in the right format - be strict */
260                         if (len1 == 0 && len2 == 0) {
261                                 *ps = "";
262                         } else {
263                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
264                                         return False;
265                                 }
266
267                                 if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data)
268                                         return False;   
269
270                                 if (0 < len1) {
271                                         pull_string(p, blob->data + ptr, sizeof(p), 
272                                                     len1, 
273                                                     STR_ASCII|STR_NOALIGN);
274                                         (*ps) = talloc_strdup(mem_ctx, p);
275                                         if (!(*ps)) {
276                                                 return False;
277                                         }
278                                 } else {
279                                         (*ps) = "";
280                                 }
281                         }
282                         break;
283                 case 'B':
284                         NEED_DATA(8);
285                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
286                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
287                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
288
289                         b = (DATA_BLOB *)va_arg(ap, void *);
290                         if (len1 == 0 && len2 == 0) {
291                                 *b = data_blob_talloc(mem_ctx, NULL, 0);
292                         } else {
293                                 /* make sure its in the right format - be strict */
294                                 if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
295                                         return False;
296                                 }
297
298                                 if (blob->data + ptr < (uint8_t *)ptr || blob->data + ptr < blob->data)
299                                         return False;   
300                         
301                                 *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
302                         }
303                         break;
304                 case 'b':
305                         b = (DATA_BLOB *)va_arg(ap, void *);
306                         len1 = va_arg(ap, uint_t);
307                         /* make sure its in the right format - be strict */
308                         NEED_DATA(len1);
309                         if (blob->data + head_ofs < (uint8_t *)head_ofs || blob->data + head_ofs < blob->data)
310                                 return False;   
311                         
312                         *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
313                         head_ofs += len1;
314                         break;
315                 case 'd':
316                         v = va_arg(ap, uint32_t *);
317                         NEED_DATA(4);
318                         *v = IVAL(blob->data, head_ofs); head_ofs += 4;
319                         break;
320                 case 'C':
321                         s = va_arg(ap, char *);
322
323                         if (blob->data + head_ofs < (uint8_t *)head_ofs || blob->data + head_ofs < blob->data)
324                                 return False;   
325         
326                         head_ofs += pull_string(p, blob->data+head_ofs, sizeof(p), 
327                                                 blob->length - head_ofs, 
328                                                 STR_ASCII|STR_TERMINATE);
329                         if (strcmp(s, p) != 0) {
330                                 return False;
331                         }
332                         break;
333                 }
334         }
335         va_end(ap);
336
337         return True;
338 }