e1e54622acaece74d4ba67671959af85a1538a8c
[bbaumbach/samba-autobuild/.git] / source4 / lib / tdr / tdr.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    TDR (Trivial Data Representation) helper functions
5      Based loosely on ndr.c by Andrew Tridgell.
6
7    Copyright (C) Jelmer Vernooij 2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "system/network.h"
26
27 #define TDR_BASE_MARSHALL_SIZE 1024
28
29 #define TDR_PUSH_NEED_BYTES(tdr, n) TDR_CHECK(tdr_push_expand(tdr, tdr->offset+(n)))
30
31 #define TDR_PULL_NEED_BYTES(tdr, n) do { \
32         if ((n) > tdr->data.length || tdr->offset + (n) > tdr->data.length) { \
33                 return NT_STATUS_BUFFER_TOO_SMALL; \
34         } \
35 } while(0)
36
37 #define TDR_BE(tdr) ((tdr)->flags & TDR_BIG_ENDIAN)
38
39 #define TDR_CVAL(tdr, ofs) CVAL(tdr->data.data,ofs)
40 #define TDR_SVAL(tdr, ofs) (TDR_BE(tdr)?RSVAL(tdr->data.data,ofs):SVAL(tdr->data.data,ofs))
41 #define TDR_IVAL(tdr, ofs) (TDR_BE(tdr)?RIVAL(tdr->data.data,ofs):IVAL(tdr->data.data,ofs))
42 #define TDR_IVALS(tdr, ofs) (TDR_BE(tdr)?RIVALS(tdr->data.data,ofs):IVALS(tdr->data.data,ofs))
43 #define TDR_SCVAL(tdr, ofs, v) SCVAL(tdr->data.data,ofs,v)
44 #define TDR_SSVAL(tdr, ofs, v) do { if (TDR_BE(tdr))  { RSSVAL(tdr->data.data,ofs,v); } else SSVAL(tdr->data.data,ofs,v); } while (0)
45 #define TDR_SIVAL(tdr, ofs, v) do { if (TDR_BE(tdr))  { RSIVAL(tdr->data.data,ofs,v); } else SIVAL(tdr->data.data,ofs,v); } while (0)
46 #define TDR_SIVALS(tdr, ofs, v) do { if (TDR_BE(tdr))  { RSIVALS(tdr->data.data,ofs,v); } else SIVALS(tdr->data.data,ofs,v); } while (0)
47
48 /*
49   expand the available space in the buffer to 'size'
50 */
51 NTSTATUS tdr_push_expand(struct tdr_push *tdr, uint32_t size)
52 {
53         if (talloc_get_size(tdr->data.data) >= size) {
54                 return NT_STATUS_OK;
55         }
56
57         tdr->data.data = talloc_realloc(tdr, tdr->data.data, uint8_t, tdr->data.length + TDR_BASE_MARSHALL_SIZE);
58
59         if (tdr->data.data == NULL)
60                 return NT_STATUS_NO_MEMORY;
61
62         return NT_STATUS_OK;
63 }
64
65
66 NTSTATUS tdr_pull_uint8(struct tdr_pull *tdr, uint8_t *v)
67 {
68         TDR_PULL_NEED_BYTES(tdr, 1);
69         *v = TDR_CVAL(tdr, tdr->offset);
70         tdr->offset += 1;
71         return NT_STATUS_OK;
72 }
73
74 NTSTATUS tdr_push_uint8(struct tdr_push *tdr, const uint8_t *v)
75 {
76         TDR_PUSH_NEED_BYTES(tdr, 1);
77         TDR_SCVAL(tdr, tdr->offset, *v);
78         tdr->offset += 1;
79         return NT_STATUS_OK;
80 }
81
82 NTSTATUS tdr_print_uint8(struct tdr_print *tdr, const char *name, uint8_t *v)
83 {
84         tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
85         return NT_STATUS_OK;
86 }
87
88 NTSTATUS tdr_pull_uint16(struct tdr_pull *tdr, uint16_t *v)
89 {
90         TDR_PULL_NEED_BYTES(tdr, 2);
91         *v = TDR_SVAL(tdr, tdr->offset);
92         tdr->offset += 2;
93         return NT_STATUS_OK;
94 }
95
96 NTSTATUS tdr_push_uint16(struct tdr_push *tdr, const uint16_t *v)
97 {
98         TDR_PUSH_NEED_BYTES(tdr, 2);
99         TDR_SSVAL(tdr, tdr->offset, *v);
100         tdr->offset += 2;
101         return NT_STATUS_OK;
102 }
103
104 NTSTATUS tdr_print_uint16(struct tdr_print *tdr, const char *name, uint16_t *v)
105 {
106         tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
107         return NT_STATUS_OK;
108 }
109
110 NTSTATUS tdr_pull_uint32(struct tdr_pull *tdr, uint32_t *v)
111 {
112         TDR_PULL_NEED_BYTES(tdr, 4);
113         *v = TDR_IVAL(tdr, tdr->offset);
114         tdr->offset += 4;
115         return NT_STATUS_OK;
116 }
117
118 NTSTATUS tdr_push_uint32(struct tdr_push *tdr, const uint32_t *v)
119 {
120         TDR_PUSH_NEED_BYTES(tdr, 4);
121         TDR_SIVAL(tdr, tdr->offset, *v);
122         tdr->offset += 4;
123         return NT_STATUS_OK;
124 }
125
126 NTSTATUS tdr_print_uint32(struct tdr_print *tdr, const char *name, uint32_t *v)
127 {
128         tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
129         return NT_STATUS_OK;
130 }
131
132 NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, const char **v, uint32_t length, uint32_t el_size, int chset)
133 {
134         int ret;
135
136         if (length == -1) {
137                 switch (chset) {
138                         case CH_DOS:
139                                 length = ascii_len_n((const char*)tdr->data.data+tdr->offset, tdr->data.length-tdr->offset);
140                                 break;
141                         case CH_UTF16:
142                                 length = utf16_len_n(tdr->data.data+tdr->offset, tdr->data.length-tdr->offset);
143                                 break;
144
145                         default:
146                                 return NT_STATUS_INVALID_PARAMETER;
147                 }
148         }
149
150         if (length == 0) {
151                 *v = talloc_strdup(tdr, "");
152                 return NT_STATUS_OK;
153         }
154
155         TDR_PULL_NEED_BYTES(tdr, el_size*length);
156         
157         ret = convert_string_talloc(tdr, chset, CH_UNIX, tdr->data.data+tdr->offset, el_size*length, discard_const_p(void *, v));
158
159         if (ret == -1) {
160                 return NT_STATUS_INVALID_PARAMETER;
161         }
162
163         tdr->offset += length * el_size;
164
165         return NT_STATUS_OK;
166 }
167
168 NTSTATUS tdr_push_charset(struct tdr_push *tdr, const char **v, uint32_t length, uint32_t el_size, int chset)
169 {
170         ssize_t ret, required;
171
172         required = el_size * length;
173         TDR_PUSH_NEED_BYTES(tdr, required);
174
175         ret = convert_string(CH_UNIX, chset, *v, strlen(*v), tdr->data.data+tdr->offset, required);
176
177         if (ret == -1) {
178                 return NT_STATUS_INVALID_PARAMETER;
179         }
180
181         /* Make sure the remaining part of the string is filled with zeroes */
182         if (ret < required) {
183                 memset(tdr->data.data+tdr->offset+ret, 0, required-ret);
184         }
185         
186         tdr->offset += required;
187                                                  
188         return NT_STATUS_OK;
189 }
190
191 NTSTATUS tdr_print_charset(struct tdr_print *tdr, const char *name, const char **v, uint32_t length, uint32_t el_size, int chset)
192 {
193         tdr->print(tdr, "%-25s: %s", name, *v);
194         return NT_STATUS_OK;
195 }
196
197 /*
198   pull a ipv4address
199 */
200 NTSTATUS tdr_pull_ipv4address(struct tdr_pull *tdr, const char **address)
201 {
202         struct ipv4_addr in;
203         TDR_CHECK(tdr_pull_uint32(tdr, &in.addr));
204         in.addr = htonl(in.addr);
205         *address = talloc_strdup(tdr, sys_inet_ntoa(in));
206         NT_STATUS_HAVE_NO_MEMORY(*address);
207         return NT_STATUS_OK;
208 }
209
210 /*
211   push a ipv4address
212 */
213 NTSTATUS tdr_push_ipv4address(struct tdr_push *tdr, const char **address)
214 {
215         uint32_t addr = htonl(interpret_addr(*address));
216         TDR_CHECK(tdr_push_uint32(tdr, &addr));
217         return NT_STATUS_OK;
218 }
219
220 /*
221   print a ipv4address
222 */
223 NTSTATUS tdr_print_ipv4address(struct tdr_print *tdr, const char *name, 
224                            const char **address)
225 {
226         tdr->print(tdr, "%-25s: %s", name, *address);
227         return NT_STATUS_OK;
228 }
229
230 /*
231   parse a hyper
232 */
233 NTSTATUS tdr_pull_hyper(struct tdr_pull *tdr, uint64_t *v)
234 {
235         TDR_PULL_NEED_BYTES(tdr, 8);
236         *v = TDR_IVAL(tdr, tdr->offset);
237         *v |= (uint64_t)(TDR_IVAL(tdr, tdr->offset+4)) << 32;
238         tdr->offset += 8;
239         return NT_STATUS_OK;
240 }
241
242 /*
243   push a hyper
244 */
245 NTSTATUS tdr_push_hyper(struct tdr_push *tdr, uint64_t *v)
246 {
247         TDR_PUSH_NEED_BYTES(tdr, 8);
248         TDR_SIVAL(tdr, tdr->offset, ((*v) & 0xFFFFFFFF));
249         TDR_SIVAL(tdr, tdr->offset+4, ((*v)>>32));
250         tdr->offset += 8;
251         return NT_STATUS_OK;
252 }
253
254
255
256 /*
257   push a NTTIME
258 */
259 NTSTATUS tdr_push_NTTIME(struct tdr_push *tdr, NTTIME *t)
260 {
261         TDR_CHECK(tdr_push_hyper(tdr, t));
262         return NT_STATUS_OK;
263 }
264
265 /*
266   pull a NTTIME
267 */
268 NTSTATUS tdr_pull_NTTIME(struct tdr_pull *tdr, NTTIME *t)
269 {
270         TDR_CHECK(tdr_pull_hyper(tdr, t));
271         return NT_STATUS_OK;
272 }
273
274 /*
275   push a time_t
276 */
277 NTSTATUS tdr_push_time_t(struct tdr_push *tdr, time_t *t)
278 {
279         return tdr_push_uint32(tdr, (uint32_t *)t);
280 }
281
282 /*
283   pull a time_t
284 */
285 NTSTATUS tdr_pull_time_t(struct tdr_pull *tdr, time_t *t)
286 {
287         uint32_t tt;
288         TDR_CHECK(tdr_pull_uint32(tdr, &tt));
289         *t = tt;
290         return NT_STATUS_OK;
291 }
292
293 NTSTATUS tdr_print_time_t(struct tdr_print *tdr, const char *name, time_t *t)
294 {
295         if (*t == (time_t)-1 || *t == 0) {
296                 tdr->print(tdr, "%-25s: (time_t)%d", name, (int)*t);
297         } else {
298                 tdr->print(tdr, "%-25s: %s", name, timestring(tdr, *t));
299         }
300
301         return NT_STATUS_OK;
302 }
303
304 NTSTATUS tdr_print_NTTIME(struct tdr_print *tdr, const char *name, NTTIME *t)
305 {
306         tdr->print(tdr, "%-25s: %s", name, nt_time_string(tdr, *t));
307
308         return NT_STATUS_OK;
309 }
310
311 NTSTATUS tdr_print_DATA_BLOB(struct tdr_print *tdr, const char *name, DATA_BLOB *r)
312 {
313         tdr->print(tdr, "%-25s: DATA_BLOB length=%u", name, r->length);
314         if (r->length) {
315                 dump_data(10, r->data, r->length);
316         }
317
318         return NT_STATUS_OK;
319 }
320
321 #define TDR_ALIGN(tdr,n) (((tdr)->offset & ((n)-1)) == 0?0:((n)-((tdr)->offset&((n)-1))))
322
323 /*
324   push a DATA_BLOB onto the wire. 
325 */
326 NTSTATUS tdr_push_DATA_BLOB(struct tdr_push *tdr, DATA_BLOB *blob)
327 {
328         if (tdr->flags & TDR_ALIGN2) {
329                 blob->length = TDR_ALIGN(tdr, 2);
330         } else if (tdr->flags & TDR_ALIGN4) {
331                 blob->length = TDR_ALIGN(tdr, 4);
332         } else if (tdr->flags & TDR_ALIGN8) {
333                 blob->length = TDR_ALIGN(tdr, 8);
334         }
335
336         TDR_PUSH_NEED_BYTES(tdr, blob->length);
337         
338         memcpy(tdr->data.data+tdr->offset, blob->data, blob->length);
339         return NT_STATUS_OK;
340 }
341
342 /*
343   pull a DATA_BLOB from the wire. 
344 */
345 NTSTATUS tdr_pull_DATA_BLOB(struct tdr_pull *tdr, DATA_BLOB *blob)
346 {
347         uint32_t length;
348
349         if (tdr->flags & TDR_ALIGN2) {
350                 length = TDR_ALIGN(tdr, 2);
351         } else if (tdr->flags & TDR_ALIGN4) {
352                 length = TDR_ALIGN(tdr, 4);
353         } else if (tdr->flags & TDR_ALIGN8) {
354                 length = TDR_ALIGN(tdr, 8);
355         } else if (tdr->flags & TDR_REMAINING) {
356                 length = tdr->data.length - tdr->offset;
357         } else {
358                 return NT_STATUS_INVALID_PARAMETER;
359         }
360
361         if (tdr->data.length - tdr->offset < length) {
362                 length = tdr->data.length - tdr->offset;
363         }
364
365         TDR_PULL_NEED_BYTES(tdr, length);
366
367         *blob = data_blob_talloc(tdr, tdr->data.data+tdr->offset, length);
368         tdr->offset += length;
369         return NT_STATUS_OK;
370 }