r23792: convert Samba4 to GPLv3
[ira/wip.git] / source / librpc / ndr / ndr_compression.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    libndr compression support
5
6    Copyright (C) Stefan Metzmacher 2005
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 "lib/compression/mszip.h"
24 #include "librpc/ndr/libndr.h"
25
26 static NTSTATUS ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull,
27                                                  struct ndr_push *ndrpush,
28                                                  struct decomp_state *decomp_state)
29 {
30         DATA_BLOB comp_chunk;
31         uint32_t comp_chunk_offset;
32         uint32_t comp_chunk_size;
33         DATA_BLOB plain_chunk;
34         uint32_t plain_chunk_offset;
35         uint32_t plain_chunk_size;
36         int ret;
37
38         NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
39         if (plain_chunk_size > 0x00008000) {
40                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad MSZIP plain chunk size %08X > 0x00008000 (PULL)", 
41                                       plain_chunk_size);
42         }
43
44         NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
45
46         DEBUG(10,("MSZIP plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
47                   plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
48
49         comp_chunk_offset = ndrpull->offset;
50         NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
51         comp_chunk.length = comp_chunk_size;
52         comp_chunk.data = ndrpull->data + comp_chunk_offset;
53
54         plain_chunk_offset = ndrpush->offset;
55         NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
56         plain_chunk.length = plain_chunk_size;
57         plain_chunk.data = ndrpush->data + plain_chunk_offset;
58
59         ret = ZIPdecompress(decomp_state, &comp_chunk, &plain_chunk);
60         if (ret != DECR_OK) {
61                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad ZIPdecompress() error %d (PULL)",
62                                       ret);
63         }
64
65         if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
66                 /* this is the last chunk */
67                 return NT_STATUS_OK;
68         }
69
70         return NT_STATUS_MORE_PROCESSING_REQUIRED;
71 }
72
73 static NTSTATUS ndr_pull_compression_mszip(struct ndr_pull *subndr,
74                                            struct ndr_pull **_comndr,
75                                            ssize_t decompressed_len)
76 {
77         NTSTATUS status = NT_STATUS_MORE_PROCESSING_REQUIRED;
78         struct ndr_push *ndrpush;
79         struct ndr_pull *comndr;
80         DATA_BLOB uncompressed;
81         uint32_t payload_header[4];
82         uint32_t payload_size;
83         uint32_t payload_offset;
84         uint8_t *payload;
85         struct decomp_state *decomp_state;
86
87         ndrpush = ndr_push_init_ctx(subndr);
88         NT_STATUS_HAVE_NO_MEMORY(ndrpush);
89
90         decomp_state = ZIPdecomp_state(subndr);
91         NT_STATUS_HAVE_NO_MEMORY(decomp_state);
92
93         while (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) {
94                 status = ndr_pull_compression_mszip_chunk(subndr, ndrpush, decomp_state);
95         }
96         NT_STATUS_NOT_OK_RETURN(status);
97
98         uncompressed = ndr_push_blob(ndrpush);
99
100         if (uncompressed.length != decompressed_len) {
101                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP uncompressed_len [%u] != [%d] (PULL)",
102                                       (int)uncompressed.length, (int)decompressed_len);
103         }
104
105         comndr = talloc_zero(subndr, struct ndr_pull);
106         NT_STATUS_HAVE_NO_MEMORY(comndr);
107         comndr->flags           = subndr->flags;
108         comndr->current_mem_ctx = subndr->current_mem_ctx;
109
110         comndr->data            = uncompressed.data;
111         comndr->data_size       = uncompressed.length;
112         comndr->offset          = 0;
113
114         NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[0]));
115         NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[1]));
116         NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[2]));
117         NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[3]));
118
119         if (payload_header[0] != 0x00081001) {
120                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[0] [0x%08X] != [0x00081001] (PULL)",
121                                       payload_header[0]);
122         }
123         if (payload_header[1] != 0xCCCCCCCC) {
124                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[1] [0x%08X] != [0xCCCCCCCC] (PULL)",
125                                       payload_header[1]);
126         }
127
128         payload_size = payload_header[2];
129
130         if (payload_header[3] != 0x00000000) {
131                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[3] [0x%08X] != [0x00000000] (PULL)",
132                                       payload_header[3]);
133         }
134
135         payload_offset = comndr->offset;
136         NDR_CHECK(ndr_pull_advance(comndr, payload_size));
137         payload = comndr->data + payload_offset;
138
139         comndr->data            = payload;
140         comndr->data_size       = payload_size;
141         comndr->offset          = 0;
142
143         *_comndr = comndr;
144         return NT_STATUS_OK;
145 }
146
147 static NTSTATUS ndr_push_compression_mszip(struct ndr_push *subndr,
148                                            struct ndr_push *comndr)
149 {
150         return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Sorry MSZIP compression is not supported yet (PUSH)");
151 }
152
153 static NTSTATUS ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull,
154                                                   struct ndr_push *ndrpush)
155 {
156         DATA_BLOB comp_chunk;
157         uint32_t comp_chunk_offset;
158         uint32_t comp_chunk_size;
159         uint32_t plain_chunk_size;
160
161         comp_chunk_offset = ndrpull->offset;
162
163         NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
164         if (plain_chunk_size > 0x00010000) {
165                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad XPRESS plain chunk size %08X > 0x00010000 (PULL)", 
166                                       plain_chunk_size);
167         }
168
169         NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
170
171         NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
172         comp_chunk.length = comp_chunk_size + 8;
173         comp_chunk.data = ndrpull->data + comp_chunk_offset;
174
175         DEBUG(10,("XPRESS plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
176                   plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
177
178         /* For now, we just copy over the compressed blob */
179         NDR_CHECK(ndr_push_bytes(ndrpush, comp_chunk.data, comp_chunk.length));
180
181         if ((plain_chunk_size < 0x00010000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
182                 /* this is the last chunk */
183                 return NT_STATUS_OK;
184         }
185
186         return NT_STATUS_MORE_PROCESSING_REQUIRED;
187 }
188
189 static NTSTATUS ndr_pull_compression_xpress(struct ndr_pull *subndr,
190                                             struct ndr_pull **_comndr,
191                                             ssize_t decompressed_len)
192 {
193         NTSTATUS status = NT_STATUS_MORE_PROCESSING_REQUIRED;
194         struct ndr_push *ndrpush;
195         struct ndr_pull *comndr;
196         DATA_BLOB uncompressed;
197
198         ndrpush = ndr_push_init_ctx(subndr);
199         NT_STATUS_HAVE_NO_MEMORY(ndrpush);
200
201         while (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) {
202                 status = ndr_pull_compression_xpress_chunk(subndr, ndrpush);
203         }
204         NT_STATUS_NOT_OK_RETURN(status);
205
206         uncompressed = ndr_push_blob(ndrpush);
207
208         comndr = talloc_zero(subndr, struct ndr_pull);
209         NT_STATUS_HAVE_NO_MEMORY(comndr);
210         comndr->flags           = subndr->flags;
211         comndr->current_mem_ctx = subndr->current_mem_ctx;
212
213         comndr->data            = uncompressed.data;
214         comndr->data_size       = uncompressed.length;
215         comndr->offset          = 0;
216
217         *_comndr = comndr;
218         return NT_STATUS_OK;
219 }
220
221 static NTSTATUS ndr_push_compression_xpress(struct ndr_push *subndr,
222                                             struct ndr_push *comndr)
223 {
224         return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "XPRESS compression is not supported yet (PUSH)");
225 }
226
227 /*
228   handle compressed subcontext buffers, which in midl land are user-marshalled, but
229   we use magic in pidl to make them easier to cope with
230 */
231 NTSTATUS ndr_pull_compression_start(struct ndr_pull *subndr,
232                                     struct ndr_pull **_comndr,
233                                     enum ndr_compression_alg compression_alg,
234                                     ssize_t decompressed_len)
235 {
236         switch (compression_alg) {
237         case NDR_COMPRESSION_MSZIP:
238                 return ndr_pull_compression_mszip(subndr, _comndr, decompressed_len);
239         case NDR_COMPRESSION_XPRESS:
240                 return ndr_pull_compression_xpress(subndr, _comndr, decompressed_len);
241         default:
242                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)", 
243                                       compression_alg);
244         }
245         return NT_STATUS_OK;
246 }
247
248 NTSTATUS ndr_pull_compression_end(struct ndr_pull *subndr,
249                                   struct ndr_pull *comndr,
250                                   enum ndr_compression_alg compression_alg,
251                                   ssize_t decompressed_len)
252 {
253         return NT_STATUS_OK;
254 }
255
256 /*
257   push a compressed subcontext
258 */
259 NTSTATUS ndr_push_compression_start(struct ndr_push *subndr,
260                                     struct ndr_push **_comndr,
261                                     enum ndr_compression_alg compression_alg,
262                                     ssize_t decompressed_len)
263 {
264         struct ndr_push *comndr;
265
266         comndr = ndr_push_init_ctx(subndr);
267         NT_STATUS_HAVE_NO_MEMORY(comndr);
268         comndr->flags   = subndr->flags;
269
270         *_comndr = comndr;
271         return NT_STATUS_OK;
272 }
273
274 /*
275   push a compressed subcontext
276 */
277 NTSTATUS ndr_push_compression_end(struct ndr_push *subndr,
278                                   struct ndr_push *comndr,
279                                   enum ndr_compression_alg compression_alg,
280                                   ssize_t decompressed_len)
281 {
282         switch (compression_alg) {
283         case NDR_COMPRESSION_MSZIP:
284                 return ndr_push_compression_mszip(subndr, comndr);
285         case NDR_COMPRESSION_XPRESS:
286                 return ndr_push_compression_xpress(subndr, comndr);
287         default:
288                 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)", 
289                                       compression_alg);
290         }
291         return NT_STATUS_OK;
292 }