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