librpc/ndr: Use MAX_WBITS zlib define and change memLevel in MSZIP code
[Samba.git] / librpc / ndr / ndr_compression.c
blob41328ea499cfa75541f644d991dd45d5232ff079
1 /*
2 Unix SMB/CIFS implementation.
4 libndr compression support
6 Copyright (C) Stefan Metzmacher 2005
7 Copyright (C) Matthieu Suiche 2008
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 3 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "../lib/compression/lzxpress.h"
25 #include "librpc/ndr/libndr.h"
26 #include "../librpc/ndr/ndr_compression.h"
27 #include <zlib.h>
29 struct ndr_compression_state {
30 enum ndr_compression_alg type;
31 union {
32 struct {
33 struct z_stream_s *z;
34 uint8_t *dict;
35 size_t dict_size;
36 } mszip;
40 static voidpf ndr_zlib_alloc(voidpf opaque, uInt items, uInt size)
42 return talloc_zero_size(opaque, items * size);
45 static void ndr_zlib_free(voidpf opaque, voidpf address)
47 talloc_free(address);
50 static enum ndr_err_code ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull,
51 struct ndr_push *ndrpush,
52 z_stream *z,
53 bool *last)
55 DATA_BLOB comp_chunk;
56 uint32_t comp_chunk_offset;
57 uint32_t comp_chunk_size;
58 DATA_BLOB plain_chunk;
59 uint32_t plain_chunk_offset;
60 uint32_t plain_chunk_size;
61 int z_ret;
63 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
64 if (plain_chunk_size > 0x00008000) {
65 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad MSZIP plain chunk size %08X > 0x00008000 (PULL)",
66 plain_chunk_size);
69 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
71 DEBUG(9,("MSZIP plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
72 plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
74 comp_chunk_offset = ndrpull->offset;
75 NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
76 comp_chunk.length = comp_chunk_size;
77 comp_chunk.data = ndrpull->data + comp_chunk_offset;
79 plain_chunk_offset = ndrpush->offset;
80 NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
81 plain_chunk.length = plain_chunk_size;
82 plain_chunk.data = ndrpush->data + plain_chunk_offset;
84 if (comp_chunk.length < 2) {
85 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
86 "Bad MSZIP comp chunk size %u < 2 (PULL)",
87 (unsigned int)comp_chunk.length);
89 /* CK = Chris Kirmse, official Microsoft purloiner */
90 if (comp_chunk.data[0] != 'C' ||
91 comp_chunk.data[1] != 'K') {
92 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
93 "Bad MSZIP invalid prefix [%c%c] != [CK]",
94 comp_chunk.data[0], comp_chunk.data[1]);
97 z->next_in = comp_chunk.data + 2;
98 z->avail_in = comp_chunk.length -2;
99 z->total_in = 0;
101 z->next_out = plain_chunk.data;
102 z->avail_out = plain_chunk.length;
103 z->total_out = 0;
105 if (!z->opaque) {
106 /* the first time we need to intialize completely */
107 z->zalloc = ndr_zlib_alloc;
108 z->zfree = ndr_zlib_free;
109 z->opaque = ndrpull;
111 z_ret = inflateInit2(z, -MAX_WBITS);
112 if (z_ret != Z_OK) {
113 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
114 "Bad inflateInit2 error %s(%d) (PULL)",
115 zError(z_ret), z_ret);
120 /* call inflate untill we get Z_STREAM_END or an error */
121 while (true) {
122 z_ret = inflate(z, Z_BLOCK);
123 if (z_ret != Z_OK) break;
126 if (z_ret != Z_STREAM_END) {
127 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
128 "Bad inflate(Z_BLOCK) error %s(%d) (PULL)",
129 zError(z_ret), z_ret);
132 if (z->avail_in) {
133 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
134 "MSZIP not all avail_in[%u] bytes consumed (PULL)",
135 z->avail_in);
138 if (z->avail_out) {
139 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
140 "MSZIP not all avail_out[%u] bytes consumed (PULL)",
141 z->avail_out);
144 if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
145 /* this is the last chunk */
146 *last = true;
149 z_ret = inflateReset(z);
150 if (z_ret != Z_OK) {
151 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
152 "Bad inflateReset error %s(%d) (PULL)",
153 zError(z_ret), z_ret);
156 z_ret = inflateSetDictionary(z, plain_chunk.data, plain_chunk.length);
157 if (z_ret != Z_OK) {
158 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
159 "Bad inflateSetDictionary error %s(%d) (PULL)",
160 zError(z_ret), z_ret);
163 return NDR_ERR_SUCCESS;
166 static enum ndr_err_code ndr_push_compression_mszip_chunk(struct ndr_push *ndrpush,
167 struct ndr_pull *ndrpull,
168 z_stream *z,
169 bool *last)
171 DATA_BLOB comp_chunk;
172 uint32_t comp_chunk_size;
173 uint32_t comp_chunk_size_offset;
174 DATA_BLOB plain_chunk;
175 uint32_t plain_chunk_size;
176 uint32_t plain_chunk_offset;
177 uint32_t max_plain_size = 0x00008000;
178 uint32_t max_comp_size = 0x00008000 + 2 + 12 /*TODO: what value do we really need here?*/;
179 uint32_t tmp_offset;
180 int z_ret;
182 plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
183 plain_chunk_offset = ndrpull->offset;
184 NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
186 plain_chunk.data = ndrpull->data + plain_chunk_offset;
187 plain_chunk.length = plain_chunk_size;
189 if (plain_chunk_size < max_plain_size) {
190 *last = true;
193 NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size));
194 comp_chunk_size_offset = ndrpush->offset;
195 NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE));
197 NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
199 comp_chunk.data = ndrpush->data + ndrpush->offset;
200 comp_chunk.length = max_comp_size;
202 /* CK = Chris Kirmse, official Microsoft purloiner */
203 comp_chunk.data[0] = 'C';
204 comp_chunk.data[1] = 'K';
206 z->next_in = plain_chunk.data;
207 z->avail_in = plain_chunk.length;
208 z->total_in = 0;
210 z->next_out = comp_chunk.data + 2;
211 z->avail_out = comp_chunk.length - 2;
212 z->total_out = 0;
214 if (!z->opaque) {
215 /* the first time we need to intialize completely */
216 z->zalloc = ndr_zlib_alloc;
217 z->zfree = ndr_zlib_free;
218 z->opaque = ndrpull;
220 /* TODO: find how to trigger the same parameters windows uses */
221 z_ret = deflateInit2(z,
222 Z_DEFAULT_COMPRESSION,
223 Z_DEFLATED,
224 -MAX_WBITS,
225 8, /* memLevel */
226 Z_DEFAULT_STRATEGY);
227 if (z_ret != Z_OK) {
228 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
229 "Bad deflateInit2 error %s(%d) (PUSH)",
230 zError(z_ret), z_ret);
235 /* call deflate untill we get Z_STREAM_END or an error */
236 while (true) {
237 z_ret = deflate(z, Z_FINISH);
238 if (z_ret != Z_OK) break;
240 if (z_ret != Z_STREAM_END) {
241 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
242 "Bad delate(Z_BLOCK) error %s(%d) (PUSH)",
243 zError(z_ret), z_ret);
246 if (z->avail_in) {
247 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
248 "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
249 z->avail_in);
252 comp_chunk_size = 2 + z->total_out;
254 z_ret = deflateReset(z);
255 if (z_ret != Z_OK) {
256 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
257 "Bad deflateReset error %s(%d) (PULL)",
258 zError(z_ret), z_ret);
261 z_ret = deflateSetDictionary(z, plain_chunk.data, plain_chunk.length);
262 if (z_ret != Z_OK) {
263 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
264 "Bad deflateSetDictionary error %s(%d) (PULL)",
265 zError(z_ret), z_ret);
268 tmp_offset = ndrpush->offset;
269 ndrpush->offset = comp_chunk_size_offset;
270 NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk_size));
271 ndrpush->offset = tmp_offset;
273 DEBUG(9,("MSZIP comp plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
274 (unsigned int)plain_chunk.length,
275 (unsigned int)plain_chunk.length,
276 comp_chunk_size, comp_chunk_size));
278 ndrpush->offset += comp_chunk_size;
279 return NDR_ERR_SUCCESS;
282 static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull,
283 struct ndr_push *ndrpush,
284 bool *last)
286 DATA_BLOB comp_chunk;
287 DATA_BLOB plain_chunk;
288 uint32_t comp_chunk_offset;
289 uint32_t plain_chunk_offset;
290 uint32_t comp_chunk_size;
291 uint32_t plain_chunk_size;
292 ssize_t ret;
294 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
295 if (plain_chunk_size > 0x00010000) {
296 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad XPRESS plain chunk size %08X > 0x00010000 (PULL)",
297 plain_chunk_size);
300 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
302 comp_chunk_offset = ndrpull->offset;
303 NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
304 comp_chunk.length = comp_chunk_size;
305 comp_chunk.data = ndrpull->data + comp_chunk_offset;
307 plain_chunk_offset = ndrpush->offset;
308 NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
309 plain_chunk.length = plain_chunk_size;
310 plain_chunk.data = ndrpush->data + plain_chunk_offset;
312 DEBUG(9,("XPRESS plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
313 plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
315 /* Uncompressing the buffer using LZ Xpress algorithm */
316 ret = lzxpress_decompress(comp_chunk.data,
317 comp_chunk.length,
318 plain_chunk.data,
319 plain_chunk.length);
320 if (ret < 0) {
321 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
322 "XPRESS lzxpress_decompress() returned %d\n",
323 (int)ret);
325 plain_chunk.length = ret;
327 if ((plain_chunk_size < 0x00010000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
328 /* this is the last chunk */
329 *last = true;
332 return NDR_ERR_SUCCESS;
335 static enum ndr_err_code ndr_push_compression_xpress_chunk(struct ndr_push *ndrpush,
336 struct ndr_pull *ndrpull,
337 bool *last)
339 DATA_BLOB comp_chunk;
340 uint32_t comp_chunk_size_offset;
341 DATA_BLOB plain_chunk;
342 uint32_t plain_chunk_size;
343 uint32_t plain_chunk_offset;
344 uint32_t max_plain_size = 0x00010000;
345 uint32_t max_comp_size = 0x00020000 + 2; /* TODO: use the correct value here */
346 uint32_t tmp_offset;
347 ssize_t ret;
349 plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
350 plain_chunk_offset = ndrpull->offset;
351 NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
353 plain_chunk.data = ndrpull->data + plain_chunk_offset;
354 plain_chunk.length = plain_chunk_size;
356 if (plain_chunk_size < max_plain_size) {
357 *last = true;
360 NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size));
361 comp_chunk_size_offset = ndrpush->offset;
362 NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE));
364 NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
366 comp_chunk.data = ndrpush->data + ndrpush->offset;
367 comp_chunk.length = max_comp_size;
369 /* Compressing the buffer using LZ Xpress algorithm */
370 ret = lzxpress_compress(plain_chunk.data,
371 plain_chunk.length,
372 comp_chunk.data,
373 comp_chunk.length);
374 if (ret < 0) {
375 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
376 "XPRESS lzxpress_compress() returned %d\n",
377 (int)ret);
379 comp_chunk.length = ret;
381 tmp_offset = ndrpush->offset;
382 ndrpush->offset = comp_chunk_size_offset;
383 NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk.length));
384 ndrpush->offset = tmp_offset;
386 ndrpush->offset += comp_chunk.length;
387 return NDR_ERR_SUCCESS;
391 handle compressed subcontext buffers, which in midl land are user-marshalled, but
392 we use magic in pidl to make them easier to cope with
394 enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr,
395 struct ndr_pull **_comndr,
396 enum ndr_compression_alg compression_alg,
397 ssize_t decompressed_len,
398 ssize_t compressed_len)
400 struct ndr_push *ndrpush;
401 struct ndr_pull *comndr;
402 DATA_BLOB uncompressed;
403 bool last = false;
404 z_stream z;
406 ndrpush = ndr_push_init_ctx(subndr);
407 NDR_ERR_HAVE_NO_MEMORY(ndrpush);
409 switch (compression_alg) {
410 case NDR_COMPRESSION_MSZIP:
411 ZERO_STRUCT(z);
412 while (!last) {
413 NDR_CHECK(ndr_pull_compression_mszip_chunk(subndr, ndrpush, &z, &last));
415 break;
417 case NDR_COMPRESSION_XPRESS:
418 while (!last) {
419 NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr, ndrpush, &last));
421 break;
423 default:
424 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)",
425 compression_alg);
428 uncompressed = ndr_push_blob(ndrpush);
429 if (uncompressed.length != decompressed_len) {
430 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION,
431 "Bad uncompressed_len [%u] != [%u](0x%08X) (PULL)",
432 (int)uncompressed.length,
433 (int)decompressed_len,
434 (int)decompressed_len);
437 comndr = talloc_zero(subndr, struct ndr_pull);
438 NDR_ERR_HAVE_NO_MEMORY(comndr);
439 comndr->flags = subndr->flags;
440 comndr->current_mem_ctx = subndr->current_mem_ctx;
442 comndr->data = uncompressed.data;
443 comndr->data_size = uncompressed.length;
444 comndr->offset = 0;
446 *_comndr = comndr;
447 return NDR_ERR_SUCCESS;
450 enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr,
451 struct ndr_pull *comndr,
452 enum ndr_compression_alg compression_alg,
453 ssize_t decompressed_len)
455 return NDR_ERR_SUCCESS;
459 push a compressed subcontext
461 enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr,
462 struct ndr_push **_uncomndr,
463 enum ndr_compression_alg compression_alg,
464 ssize_t decompressed_len)
466 struct ndr_push *uncomndr;
468 switch (compression_alg) {
469 case NDR_COMPRESSION_MSZIP:
470 case NDR_COMPRESSION_XPRESS:
471 break;
472 default:
473 return ndr_push_error(subndr, NDR_ERR_COMPRESSION,
474 "Bad compression algorithm %d (PUSH)",
475 compression_alg);
478 uncomndr = ndr_push_init_ctx(subndr);
479 NDR_ERR_HAVE_NO_MEMORY(uncomndr);
480 uncomndr->flags = subndr->flags;
482 *_uncomndr = uncomndr;
483 return NDR_ERR_SUCCESS;
487 push a compressed subcontext
489 enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr,
490 struct ndr_push *uncomndr,
491 enum ndr_compression_alg compression_alg,
492 ssize_t decompressed_len)
494 struct ndr_pull *ndrpull;
495 bool last = false;
496 z_stream z;
498 ndrpull = talloc_zero(uncomndr, struct ndr_pull);
499 NDR_ERR_HAVE_NO_MEMORY(ndrpull);
500 ndrpull->flags = uncomndr->flags;
501 ndrpull->data = uncomndr->data;
502 ndrpull->data_size = uncomndr->offset;
503 ndrpull->offset = 0;
505 switch (compression_alg) {
506 case NDR_COMPRESSION_MSZIP:
507 ZERO_STRUCT(z);
508 while (!last) {
509 NDR_CHECK(ndr_push_compression_mszip_chunk(subndr, ndrpull, &z, &last));
511 break;
513 case NDR_COMPRESSION_XPRESS:
514 while (!last) {
515 NDR_CHECK(ndr_push_compression_xpress_chunk(subndr, ndrpull, &last));
517 break;
519 default:
520 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)",
521 compression_alg);
524 talloc_free(uncomndr);
525 return NDR_ERR_SUCCESS;
528 static enum ndr_err_code generic_mszip_init(TALLOC_CTX *mem_ctx,
529 struct ndr_compression_state *state)
531 z_stream *z = talloc_zero(mem_ctx, z_stream);
532 NDR_ERR_HAVE_NO_MEMORY(z);
534 z->zalloc = ndr_zlib_alloc;
535 z->zfree = ndr_zlib_free;
536 z->opaque = mem_ctx;
538 state->mszip.z = z;
539 state->mszip.dict_size = 0;
540 /* pre-alloc dictionnary */
541 state->mszip.dict = talloc_array(mem_ctx, uint8_t, 0x8000);
542 NDR_ERR_HAVE_NO_MEMORY(state->mszip.dict);
544 return NDR_ERR_SUCCESS;
547 static void generic_mszip_free(struct ndr_compression_state *state)
549 if (state == NULL) {
550 return;
553 TALLOC_FREE(state->mszip.z);
554 TALLOC_FREE(state->mszip.dict);
558 enum ndr_err_code ndr_pull_compression_state_init(struct ndr_pull *ndr,
559 enum ndr_compression_alg compression_alg,
560 struct ndr_compression_state **state)
562 struct ndr_compression_state *s;
563 int z_ret;
565 s = talloc_zero(ndr, struct ndr_compression_state);
566 NDR_ERR_HAVE_NO_MEMORY(s);
567 s->type = compression_alg;
569 switch (compression_alg) {
570 case NDR_COMPRESSION_MSZIP:
571 case NDR_COMPRESSION_XPRESS:
572 break;
573 case NDR_COMPRESSION_MSZIP_CAB:
574 NDR_CHECK(generic_mszip_init(ndr, s));
575 z_ret = inflateInit2(s->mszip.z, -MAX_WBITS);
576 if (z_ret != Z_OK) {
577 return ndr_pull_error(ndr, NDR_ERR_COMPRESSION,
578 "zlib inflateinit2 error %s (%d) %s (PULL)",
579 zError(z_ret), z_ret, s->mszip.z->msg);
581 break;
582 default:
583 return ndr_pull_error(ndr, NDR_ERR_COMPRESSION,
584 "Bad compression algorithm %d (PULL)",
585 compression_alg);
586 break;
589 *state = s;
591 return NDR_ERR_SUCCESS;
594 void ndr_pull_compression_state_free(struct ndr_compression_state *state)
596 if (state == NULL) {
597 return;
600 switch (state->type) {
601 case NDR_COMPRESSION_MSZIP:
602 case NDR_COMPRESSION_XPRESS:
603 break;
604 case NDR_COMPRESSION_MSZIP_CAB:
605 generic_mszip_free(state);
606 break;
607 default:
608 break;
610 TALLOC_FREE(state);
613 enum ndr_err_code ndr_push_compression_state_init(struct ndr_push *ndr,
614 enum ndr_compression_alg compression_alg,
615 struct ndr_compression_state **state)
617 struct ndr_compression_state *s;
618 int z_ret;
620 s = talloc_zero(ndr, struct ndr_compression_state);
621 NDR_ERR_HAVE_NO_MEMORY(s);
622 s->type = compression_alg;
624 switch (compression_alg) {
625 case NDR_COMPRESSION_XPRESS:
626 case NDR_COMPRESSION_MSZIP:
627 break;
628 case NDR_COMPRESSION_MSZIP_CAB:
629 NDR_CHECK(generic_mszip_init(ndr, s));
630 z_ret = deflateInit2(s->mszip.z,
631 Z_DEFAULT_COMPRESSION,
632 Z_DEFLATED,
633 -MAX_WBITS,
634 8, /* memLevel */
635 Z_DEFAULT_STRATEGY);
636 if (z_ret != Z_OK) {
637 return ndr_push_error(ndr, NDR_ERR_COMPRESSION,
638 "zlib inflateinit2 error %s (%d) %s (PUSH)",
639 zError(z_ret), z_ret, s->mszip.z->msg);
641 break;
642 default:
643 return ndr_push_error(ndr, NDR_ERR_COMPRESSION,
644 "Bad compression algorithm %d (PUSH)",
645 compression_alg);
646 break;
649 *state = s;
651 return NDR_ERR_SUCCESS;
654 void ndr_push_compression_state_free(struct ndr_compression_state *state)
656 if (state == NULL) {
657 return;
660 switch (state->type) {
661 case NDR_COMPRESSION_MSZIP:
662 case NDR_COMPRESSION_XPRESS:
663 break;
664 case NDR_COMPRESSION_MSZIP_CAB:
665 generic_mszip_free(state);
666 break;
667 default:
668 break;
670 TALLOC_FREE(state);