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