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