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