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