wbclient: Fix use of wb_int_trans_send, queue parameter must not be NULL
[ira/wip.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
93          * again to fill in the values */
94
95         *blob = data_blob(NULL, head_size + data_size);
96
97         head_ofs = 0;
98         data_ofs = head_size;
99
100         va_start(ap, format);
101         for (i=0; format[i]; i++) {
102                 switch (format[i]) {
103                 case 'U':
104                         s = va_arg(ap, char *);
105                         n = str_charnum(s);
106                         SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
107                         SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
108                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
109                         push_string(NULL, blob->data+data_ofs,
110                                         s, n*2, STR_UNICODE|STR_NOALIGN);
111                         data_ofs += n*2;
112                         break;
113                 case 'A':
114                         s = va_arg(ap, char *);
115                         n = str_ascii_charnum(s);
116                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
117                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
118                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
119                         push_string(NULL, blob->data+data_ofs,
120                                         s, n, STR_ASCII|STR_NOALIGN);
121                         data_ofs += n;
122                         break;
123                 case 'a':
124                         n = va_arg(ap, int);
125                         SSVAL(blob->data, data_ofs, n); data_ofs += 2;
126                         s = va_arg(ap, char *);
127                         n = str_charnum(s);
128                         SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
129                         if (0 < n) {
130                                 push_string(NULL, blob->data+data_ofs, s, n*2,
131                                             STR_UNICODE|STR_NOALIGN);
132                         }
133                         data_ofs += n*2;
134                         break;
135
136                 case 'B':
137                         b = va_arg(ap, uint8 *);
138                         n = va_arg(ap, int);
139                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
140                         SSVAL(blob->data, head_ofs, n); head_ofs += 2;
141                         SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
142                         if (n && b) /* don't follow null pointers... */
143                                 memcpy(blob->data+data_ofs, b, n);
144                         data_ofs += n;
145                         break;
146                 case 'd':
147                         n = va_arg(ap, int);
148                         SIVAL(blob->data, head_ofs, n); head_ofs += 4;
149                         break;
150                 case 'b':
151                         b = va_arg(ap, uint8 *);
152                         n = va_arg(ap, int);
153                         memcpy(blob->data + head_ofs, b, n);
154                         head_ofs += n;
155                         break;
156                 case 'C':
157                         s = va_arg(ap, char *);
158                         n = str_charnum(s) + 1;
159                         head_ofs += push_string(NULL, blob->data+head_ofs, s, n,
160                                                 STR_ASCII|STR_TERMINATE);
161                         break;
162                 }
163         }
164         va_end(ap);
165
166         return true;
167 }
168
169
170 /* a helpful macro to avoid running over the end of our blob */
171 #define NEED_DATA(amount) \
172 if ((head_ofs + amount) > blob->length) { \
173         va_end(ap); \
174         return False; \
175 }
176
177 /*
178   this is a tiny msrpc packet parser. This the the partner of msrpc_gen
179
180   format specifiers are:
181
182   U = unicode string (output is unix string)
183   A = ascii string
184   B = data blob
185   b = data blob in header
186   d = word (4 bytes)
187   C = constant ascii string
188  */
189
190 bool msrpc_parse(const DATA_BLOB *blob,
191                  const char *format, ...)
192 {
193         int i;
194         va_list ap;
195         char **ps, *s;
196         DATA_BLOB *b;
197         size_t head_ofs = 0;
198         uint16 len1, len2;
199         uint32 ptr;
200         uint32 *v;
201
202         va_start(ap, format);
203         for (i=0; format[i]; i++) {
204                 switch (format[i]) {
205                 case 'U':
206                         NEED_DATA(8);
207                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
208                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
209                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
210
211                         ps = va_arg(ap, char **);
212                         if (len1 == 0 && len2 == 0) {
213                                 *ps = smb_xstrdup("");
214                         } else {
215                                 /* make sure its in the right format
216                                  * be strict */
217                                 if ((len1 != len2) || (ptr + len1 < ptr) ||
218                                                 (ptr + len1 < len1) ||
219                                                 (ptr + len1 > blob->length)) {
220                                         va_end(ap);
221                                         return false;
222                                 }
223                                 if (len1 & 1) {
224                                         /* if odd length and unicode */
225                                         va_end(ap);
226                                         return false;
227                                 }
228                                 if (blob->data + ptr <
229                                                 (uint8 *)(unsigned long)ptr ||
230                                     blob->data + ptr < blob->data) {
231                                         va_end(ap);
232                                         return false;
233                                 }
234
235                                 if (0 < len1) {
236                                         char *p = NULL;
237                                         pull_string_talloc(talloc_tos(),
238                                                 NULL,
239                                                 0,
240                                                 &p,
241                                                 blob->data + ptr,
242                                                 len1,
243                                                 STR_UNICODE|STR_NOALIGN);
244                                         if (p) {
245                                                 (*ps) = smb_xstrdup(p);
246                                                 TALLOC_FREE(p);
247                                         } else {
248                                                 (*ps) = smb_xstrdup("");
249                                         }
250                                 } else {
251                                         (*ps) = smb_xstrdup("");
252                                 }
253                         }
254                         break;
255                 case 'A':
256                         NEED_DATA(8);
257                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
258                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
259                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
260
261                         ps = va_arg(ap, char **);
262                         /* make sure its in the right format - be strict */
263                         if (len1 == 0 && len2 == 0) {
264                                 *ps = smb_xstrdup("");
265                         } else {
266                                 if ((len1 != len2) || (ptr + len1 < ptr) ||
267                                                 (ptr + len1 < len1) ||
268                                                 (ptr + len1 > blob->length)) {
269                                         va_end(ap);
270                                         return false;
271                                 }
272
273                                 if (blob->data + ptr <
274                                                 (uint8 *)(unsigned long)ptr ||
275                                     blob->data + ptr < blob->data) {
276                                         va_end(ap);
277                                         return false;
278                                 }
279
280                                 if (0 < len1) {
281                                         char *p = NULL;
282                                         pull_string_talloc(talloc_tos(),
283                                                 NULL,
284                                                 0,
285                                                 &p,
286                                                 blob->data + ptr,
287                                                 len1,
288                                                 STR_ASCII|STR_NOALIGN);
289                                         if (p) {
290                                                 (*ps) = smb_xstrdup(p);
291                                                 TALLOC_FREE(p);
292                                         } else {
293                                                 (*ps) = smb_xstrdup("");
294                                         }
295                                 } else {
296                                         (*ps) = smb_xstrdup("");
297                                 }
298                         }
299                         break;
300                 case 'B':
301                         NEED_DATA(8);
302                         len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
303                         len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
304                         ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
305
306                         b = (DATA_BLOB *)va_arg(ap, void *);
307                         if (len1 == 0 && len2 == 0) {
308                                 *b = data_blob_null;
309                         } else {
310                                 /* make sure its in the right format
311                                  * be strict */
312                                 if ((len1 != len2) || (ptr + len1 < ptr) ||
313                                                 (ptr + len1 < len1) ||
314                                                 (ptr + len1 > blob->length)) {
315                                         va_end(ap);
316                                         return false;
317                                 }
318
319                                 if (blob->data + ptr <
320                                                 (uint8 *)(unsigned long)ptr ||
321                                     blob->data + ptr < blob->data) {
322                                         va_end(ap);
323                                         return false;
324                                 }
325
326                                 *b = data_blob(blob->data + ptr, len1);
327                         }
328                         break;
329                 case 'b':
330                         b = (DATA_BLOB *)va_arg(ap, void *);
331                         len1 = va_arg(ap, unsigned);
332                         /* make sure its in the right format - be strict */
333                         NEED_DATA(len1);
334                         if (blob->data + head_ofs < (uint8 *)head_ofs ||
335                                         blob->data + head_ofs < blob->data) {
336                                 va_end(ap);
337                                 return false;
338                         }
339
340                         *b = data_blob(blob->data + head_ofs, len1);
341                         head_ofs += len1;
342                         break;
343                 case 'd':
344                         v = va_arg(ap, uint32 *);
345                         NEED_DATA(4);
346                         *v = IVAL(blob->data, head_ofs); head_ofs += 4;
347                         break;
348                 case 'C':
349                         s = va_arg(ap, char *);
350
351                         if (blob->data + head_ofs < (uint8 *)head_ofs ||
352                             blob->data + head_ofs < blob->data) {
353                                 va_end(ap);
354                                 return false;
355                         }
356
357                         {
358                                 char *p = NULL;
359                                 size_t ret = pull_string_talloc(talloc_tos(),
360                                                 NULL,
361                                                 0,
362                                                 &p,
363                                                 blob->data+head_ofs,
364                                                 blob->length - head_ofs,
365                                                 STR_ASCII|STR_TERMINATE);
366                                 if (ret == (size_t)-1 || p == NULL) {
367                                         va_end(ap);
368                                         return false;
369                                 }
370                                 head_ofs += ret;
371                                 if (strcmp(s, p) != 0) {
372                                         TALLOC_FREE(p);
373                                         va_end(ap);
374                                         return false;
375                                 }
376                                 TALLOC_FREE(p);
377                         }
378                         break;
379                 }
380         }
381         va_end(ap);
382
383         return True;
384 }