ndr: Use resizing array instead of linked lists (breaking ABI)
[samba.git] / librpc / ndr / ndr_cab.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    routines for marshalling/unmarshalling cab structures
5
6    Copyright (C) Guenther Deschner 2016
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 "librpc/gen_ndr/ndr_cab.h"
24
25 _PUBLIC_ void ndr_print_cf_time(struct ndr_print *ndr, const char *name, const struct cf_time *r)
26 {
27         uint8_t hour = 0, minute = 0, seconds = 0;
28         char *s;
29         if (r == NULL) { ndr_print_null(ndr); return; }
30         hour = r->time >> 11;
31         minute = (r->time >> 5) & 0x3f;
32         seconds = (r->time << 1) & 0x3e;
33         s = talloc_asprintf(ndr, "%02d:%02d:%02d", hour, minute, seconds);
34         if (s == NULL) { return; }
35         ndr_print_string(ndr, "time", s);
36         talloc_free(s);
37 }
38
39 _PUBLIC_ void ndr_print_cf_date(struct ndr_print *ndr, const char *name, const struct cf_date *r)
40 {
41         uint16_t year = 0;
42         uint8_t month = 0, day = 0;
43         char *s;
44         if (r == NULL) { ndr_print_null(ndr); return; }
45         year = (r->date >> 9);
46         year += 1980;
47         month = (r->date >> 5 & 0xf);
48         day = (r->date & 0x1f);
49         s = talloc_asprintf(ndr, "%02d/%02d/%04d", day, month, year);
50         if (s == NULL) { return; }
51         ndr_print_string(ndr, "date", s);
52         talloc_free(s);
53 }
54
55 uint32_t ndr_count_cfdata(const struct cab_file *r)
56 {
57         uint32_t count = 0, i;
58
59         for (i = 0; i < r->cfheader.cFolders; i++) {
60                 if (count + r->cffolders[i].cCFData < count) {
61                         /* Integer wrap. */
62                         return 0;
63                 }
64                 count += r->cffolders[i].cCFData;
65         }
66
67         return count;
68 }
69
70 static uint32_t ndr_cab_compute_checksum(uint8_t *data, uint32_t length, uint32_t seed)
71 {
72         int num_ulong;
73         uint32_t checksum;
74         uint8_t *pb;
75         uint32_t ul;
76
77         num_ulong = length / 4;
78         checksum = seed;
79         pb = data;
80
81         while (num_ulong-- > 0) {
82                 ul = *pb++;
83                 ul |= (((uint32_t)(*pb++)) <<  8);
84                 ul |= (((uint32_t)(*pb++)) << 16);
85                 ul |= (((uint32_t)(*pb++)) << 24);
86
87                 checksum ^= ul;
88         }
89
90         ul = 0;
91
92         switch (length % 4) {
93         case 3:
94                 ul |= (((uint32_t)(*pb++)) << 16);
95         case 2:
96                 ul |= (((uint32_t)(*pb++)) <<  8);
97         case 1:
98                 ul |= *pb++;
99         default:
100                 break;
101         }
102
103         checksum ^= ul;
104
105         return checksum;
106 }
107
108 uint32_t ndr_cab_generate_checksum(const struct CFDATA *r)
109 {
110         uint32_t csumPartial;
111
112         csumPartial = ndr_cab_compute_checksum(&r->ab[0], r->cbData, 0);
113
114         return ndr_cab_compute_checksum((uint8_t *)discard_const(&r->cbData),
115                                         sizeof(r->cbData) + sizeof(r->cbUncomp),
116                                         csumPartial);
117 }
118
119 static bool ndr_size_cab_file(const struct cab_file *r, uint32_t *psize)
120 {
121         uint32_t size = 0;
122         int i;
123
124         /* header */
125         size += 36;
126
127         /* folder */
128         for (i = 0; i < r->cfheader.cFolders; i++) {
129                 if (size + 8 < size) {
130                         /* Integer wrap. */
131                         return false;
132                 }
133                 size += 8;
134         }
135
136         /* files */
137         for (i = 0; i < r->cfheader.cFiles; i++) {
138                 uint32_t cfsize = ndr_size_CFFILE(&r->cffiles[i], 0);
139                 if (size + cfsize < size) {
140                         /* Integer wrap. */
141                         return false;
142                 }
143                 size += cfsize;
144         }
145
146         /* data */
147         for (i = 0; i < ndr_count_cfdata(r); i++) {
148                 if (size + 8 < size) {
149                         /* Integer wrap. */
150                         return false;
151                 }
152                 size += 8;
153                 if (size + r->cfdata[i].cbData < size) {
154                         /* Integer wrap. */
155                         return false;
156                 }
157                 size += r->cfdata[i].cbData;
158         }
159
160         *psize = size;
161         return true;
162 }
163
164 enum cf_compress_type ndr_cab_get_compression(const struct cab_file *r)
165 {
166         if (r->cfheader.cFolders == 0) {
167                 return CF_COMPRESS_NONE;
168         }
169
170         return r->cffolders[0].typeCompress;
171 }
172
173 _PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, int ndr_flags, const struct cab_file *r)
174 {
175         uint32_t cntr_cffolders_0;
176         uint32_t cntr_cffiles_0;
177         uint32_t cntr_cfdata_0;
178         uint32_t cab_size = 0;
179         {
180                 uint32_t _flags_save_STRUCT = ndr->flags;
181                 ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
182                 NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
183                 if (ndr_flags & NDR_SCALARS) {
184                         uint32_t next_offset = 0;
185                         NDR_CHECK(ndr_push_align(ndr, 4));
186                         NDR_CHECK(ndr_push_CFHEADER(ndr, NDR_SCALARS, &r->cfheader));
187                         for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (r->cfheader.cFolders); cntr_cffolders_0++) {
188                                 NDR_CHECK(ndr_push_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0]));
189                         }
190                         for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (r->cfheader.cFiles); cntr_cffiles_0++) {
191                                 uint32_t offset = ndr->offset + 4;
192                                 NDR_CHECK(ndr_push_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0]));
193                                 if (cntr_cffiles_0 > 0) {
194                                         next_offset += r->cffiles[cntr_cffiles_0 - 1].cbFile;
195                                 }
196                                 SIVAL(ndr->data, offset, next_offset);
197                         }
198 #if 0
199                         NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_count_cfdata(r)));
200 #endif
201                         for (cntr_cfdata_0 = 0; cntr_cfdata_0 < (ndr_count_cfdata(r)); cntr_cfdata_0++) {
202                                 NDR_CHECK(ndr_push_CFDATA(ndr, NDR_SCALARS, &r->cfdata[cntr_cfdata_0]));
203                         }
204                         NDR_CHECK(ndr_push_trailer_align(ndr, 4));
205                 }
206                 if (ndr_flags & NDR_BUFFERS) {
207                 }
208                 ndr->flags = _flags_save_STRUCT;
209         }
210
211         if (ndr_size_cab_file(r, &cab_size) == false) {
212                 return NDR_ERR_VALIDATE;
213         }
214         SIVAL(ndr->data, 8, cab_size);
215
216         return NDR_ERR_SUCCESS;
217 }
218
219 _PUBLIC_ enum ndr_err_code ndr_pull_cab_file(struct ndr_pull *ndr, int ndr_flags, struct cab_file *r)
220 {
221         uint32_t size_cffolders_0 = 0;
222         uint32_t cntr_cffolders_0;
223         TALLOC_CTX *_mem_save_cffolders_0 = NULL;
224         uint32_t size_cffiles_0 = 0;
225         uint32_t cntr_cffiles_0;
226         TALLOC_CTX *_mem_save_cffiles_0 = NULL;
227         uint32_t size_cfdata_0 = 0;
228         uint32_t cntr_cfdata_0;
229         TALLOC_CTX *_mem_save_cfdata_0 = NULL;
230         {
231                 uint32_t _flags_save_STRUCT = ndr->flags;
232                 ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
233                 NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
234                 if (ndr_flags & NDR_SCALARS) {
235                         NDR_CHECK(ndr_pull_align(ndr, 4));
236                         NDR_CHECK(ndr_pull_CFHEADER(ndr, NDR_SCALARS, &r->cfheader));
237                         size_cffolders_0 = r->cfheader.cFolders;
238                         NDR_PULL_ALLOC_N(ndr, r->cffolders, size_cffolders_0);
239                         _mem_save_cffolders_0 = NDR_PULL_GET_MEM_CTX(ndr);
240                         NDR_PULL_SET_MEM_CTX(ndr, r->cffolders, 0);
241                         for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (size_cffolders_0); cntr_cffolders_0++) {
242                                 NDR_CHECK(ndr_pull_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0]));
243                         }
244                         NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffolders_0, 0);
245                         size_cffiles_0 = r->cfheader.cFiles;
246                         NDR_PULL_ALLOC_N(ndr, r->cffiles, size_cffiles_0);
247                         _mem_save_cffiles_0 = NDR_PULL_GET_MEM_CTX(ndr);
248                         NDR_PULL_SET_MEM_CTX(ndr, r->cffiles, 0);
249                         for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (size_cffiles_0); cntr_cffiles_0++) {
250                                 NDR_CHECK(ndr_pull_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0]));
251                         }
252                         NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffiles_0, 0);
253 #if 0
254                         NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->cfdata_count));
255 #else
256                         r->cfdata_count = ndr_count_cfdata(r);
257 #endif
258                         size_cfdata_0 = r->cfdata_count;
259                         NDR_PULL_ALLOC_N(ndr, r->cfdata, size_cfdata_0);
260                         _mem_save_cfdata_0 = NDR_PULL_GET_MEM_CTX(ndr);
261                         NDR_PULL_SET_MEM_CTX(ndr, r->cfdata, 0);
262                         for (cntr_cfdata_0 = 0; cntr_cfdata_0 < (size_cfdata_0); cntr_cfdata_0++) {
263                                 NDR_CHECK(ndr_pull_CFDATA(ndr, NDR_SCALARS, &r->cfdata[cntr_cfdata_0]));
264                         }
265                         NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cfdata_0, 0);
266                         NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
267                 }
268                 if (ndr_flags & NDR_BUFFERS) {
269                 }
270                 ndr->flags = _flags_save_STRUCT;
271         }
272         return NDR_ERR_SUCCESS;
273 }