LCOV - code coverage report
Current view: top level - librpc/ndr - ndr_cab.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 183 220 83.2 %
Date: 2024-02-28 12:06:22 Functions: 8 8 100.0 %

          Line data    Source code
       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             : #include "librpc/ndr/ndr_compression.h"
      25             : 
      26             : #define OFFSET_OF_FOLDER_COFFCABSTART(folder) (36 /* cfheader size */ + (size_t)(folder)*8)
      27             : 
      28           8 : _PUBLIC_ void ndr_print_cf_time(struct ndr_print *ndr, const char *name, const struct cf_time *r)
      29             : {
      30           8 :         uint8_t hour = 0, minute = 0, seconds = 0;
      31           8 :         char *s;
      32           8 :         if (r == NULL) { ndr_print_null(ndr); return; }
      33           8 :         hour = r->time >> 11;
      34           8 :         minute = (r->time >> 5) & 0x3f;
      35           8 :         seconds = (r->time << 1) & 0x3e;
      36           8 :         s = talloc_asprintf(ndr, "%02d:%02d:%02d", hour, minute, seconds);
      37           8 :         if (s == NULL) { return; }
      38           8 :         ndr_print_string(ndr, "time", s);
      39           8 :         talloc_free(s);
      40             : }
      41             : 
      42           8 : _PUBLIC_ void ndr_print_cf_date(struct ndr_print *ndr, const char *name, const struct cf_date *r)
      43             : {
      44           8 :         uint16_t year = 0;
      45           8 :         uint8_t month = 0, day = 0;
      46           8 :         char *s;
      47           8 :         if (r == NULL) { ndr_print_null(ndr); return; }
      48           8 :         year = (r->date >> 9);
      49           8 :         year += 1980;
      50           8 :         month = (r->date >> 5 & 0xf);
      51           8 :         day = (r->date & 0x1f);
      52           8 :         s = talloc_asprintf(ndr, "%02"PRIu8"/%02"PRIu8"/%04"PRIu16, day, month, year);
      53           8 :         if (s == NULL) { return; }
      54           8 :         ndr_print_string(ndr, "date", s);
      55           8 :         talloc_free(s);
      56             : }
      57             : 
      58           8 : uint32_t ndr_count_cfdata(const struct cab_file *r)
      59             : {
      60           8 :         uint32_t count = 0, i;
      61             : 
      62          16 :         for (i = 0; i < r->cfheader.cFolders; i++) {
      63           8 :                 if (count + r->cffolders[i].cCFData < count) {
      64             :                         /* Integer wrap. */
      65           0 :                         return 0;
      66             :                 }
      67           8 :                 count += r->cffolders[i].cCFData;
      68             :         }
      69             : 
      70           0 :         return count;
      71             : }
      72             : 
      73           4 : static uint32_t ndr_cab_compute_checksum(uint8_t *data, uint32_t length, uint32_t seed)
      74             : {
      75           4 :         int num_ulong;
      76           4 :         uint32_t checksum;
      77           4 :         uint8_t *pb;
      78           4 :         uint32_t ul;
      79             : 
      80           4 :         num_ulong = length / 4;
      81           4 :         checksum = seed;
      82           4 :         pb = data;
      83             : 
      84       16390 :         while (num_ulong-- > 0) {
      85       16386 :                 ul = (uint32_t)(*pb++);
      86       16386 :                 ul |= (((uint32_t)(*pb++)) <<  8);
      87       16386 :                 ul |= (((uint32_t)(*pb++)) << 16);
      88       16386 :                 ul |= (((uint32_t)(*pb++)) << 24);
      89             : 
      90       16386 :                 checksum ^= ul;
      91             :         }
      92             : 
      93           4 :         ul = 0;
      94             : 
      95           4 :         switch (length % 4) {
      96           0 :         case 3:
      97           0 :                 ul |= (((uint32_t)(*pb++)) << 16);
      98           0 :                 FALL_THROUGH;
      99           0 :         case 2:
     100           0 :                 ul |= (((uint32_t)(*pb++)) <<  8);
     101           0 :                 FALL_THROUGH;
     102           0 :         case 1:
     103           0 :                 ul |= (uint32_t)(*pb++);
     104           4 :                 FALL_THROUGH;
     105           0 :         default:
     106           4 :                 break;
     107             :         }
     108             : 
     109           4 :         checksum ^= ul;
     110             : 
     111           4 :         return checksum;
     112             : }
     113             : 
     114             : /* Push all CFDATA of a folder.
     115             :  *
     116             :  * This works on a folder level because compression type is set per
     117             :  * folder, and a compression state can be shared between CFDATA of the
     118             :  * same folder.
     119             :  *
     120             :  * This is not a regular NDR func as we pass the compression type and
     121             :  * the number of CFDATA as extra arguments
     122             :  */
     123           2 : static enum ndr_err_code ndr_push_folder_cfdata(struct ndr_push *ndr,
     124             :                                                 const struct CFDATA *r,
     125             :                                                 enum cf_compress_type cab_ctype,
     126             :                                                 size_t num_cfdata)
     127             : {
     128           2 :         size_t i;
     129           2 :         enum ndr_compression_alg ndr_ctype = 0;
     130             : 
     131           2 :         ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
     132             : 
     133           2 :         if (cab_ctype == CF_COMPRESS_MSZIP) {
     134           0 :                 ndr_ctype = NDR_COMPRESSION_MSZIP_CAB;
     135           0 :                 NDR_CHECK(ndr_push_compression_state_init(ndr, ndr_ctype));
     136             :         }
     137             : 
     138           4 :         for (i = 0; i < num_cfdata; i++, r++) {
     139           2 :                 uint32_t compressed_length = 0;
     140           2 :                 uint32_t csum, csumPartial;
     141           2 :                 size_t compressed_offset, csum_offset, data_offset;
     142             : 
     143           2 :                 if (!r->ab.data) {
     144           0 :                         return ndr_push_error(ndr, NDR_ERR_LENGTH,
     145             :                                               "NULL uncompressed data blob");
     146             :                 }
     147           2 :                 if (r->ab.length != r->cbUncomp) {
     148           0 :                         return ndr_push_error(ndr, NDR_ERR_LENGTH,
     149             :                                               "Uncompressed data blob size != uncompressed data size field");
     150             :                 }
     151             : 
     152             :                 /*
     153             :                  * checksum is a function of the size fields
     154             :                  * and the potentially compressed data bytes,
     155             :                  * which haven't been compressed yet so
     156             :                  * remember offset, write zeroes, fill out
     157             :                  * later
     158             :                  */
     159           2 :                 csum_offset = ndr->offset;
     160           2 :                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
     161             : 
     162             :                 /*
     163             :                  * similarly, we don't know the compressed
     164             :                  * size yet, remember offset, write zeros,
     165             :                  * fill out later
     166             :                  */
     167           2 :                 compressed_offset = ndr->offset;
     168           2 :                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
     169           2 :                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->cbUncomp));
     170             : 
     171           2 :                 data_offset = ndr->offset;
     172             : 
     173           2 :                 switch (cab_ctype) {
     174           2 :                 case CF_COMPRESS_NONE:
     175             :                         /* just copy the data */
     176           2 :                         NDR_PUSH_NEED_BYTES(ndr, r->ab.length);
     177           2 :                         NDR_CHECK(ndr_push_bytes(ndr, r->ab.data, r->ab.length));
     178           2 :                         compressed_length = r->ab.length;
     179           2 :                         break;
     180           0 :                 case CF_COMPRESS_LZX:
     181             :                         /*
     182             :                          * we have not yet worked out the details of LZX
     183             :                          * compression
     184             :                          */
     185           0 :                         return NDR_ERR_COMPRESSION;
     186             : 
     187           0 :                 case CF_COMPRESS_MSZIP: {
     188           0 :                         struct ndr_push *push_sub, *push_compress;
     189             : 
     190             :                         /* compress via subcontext */
     191           0 :                         NDR_CHECK(ndr_push_subcontext_start(ndr, &push_sub, 0, -1));
     192             : 
     193             :                         /*
     194             :                          * This assignment replaces a call to
     195             :                          * ndr_push_compression_state_init(push_sub, ndr_ctype))
     196             :                          * here.  This is instead done outside the loop.
     197             :                          */
     198           0 :                         push_sub->cstate = ndr->cstate;
     199             : 
     200           0 :                         NDR_CHECK(ndr_push_compression_start(push_sub, &push_compress));
     201           0 :                         ndr_set_flags(&push_compress->flags, LIBNDR_FLAG_REMAINING);
     202           0 :                         NDR_CHECK(ndr_push_DATA_BLOB(push_compress, NDR_SCALARS, r->ab));
     203           0 :                         NDR_CHECK(ndr_push_compression_end(push_sub, push_compress));
     204           0 :                         NDR_CHECK(ndr_push_subcontext_end(ndr, push_sub, 0, -1));
     205           0 :                         compressed_length = push_sub->offset;
     206             : 
     207           0 :                         break;
     208             :                         }
     209           0 :                 default:
     210           0 :                         return NDR_ERR_BAD_SWITCH;
     211             :                 }
     212             : 
     213             :                 /* we can now write the compressed size and the checksum */
     214           2 :                 SSVAL(ndr->data, compressed_offset, compressed_length);
     215             : 
     216             :                 /*
     217             :                  * Create checksum over compressed data.
     218             :                  *
     219             :                  * The 8 bytes are the header size.
     220             :                  *
     221             :                  * We have already have written the checksum and set it to zero,
     222             :                  * earlier. So we know that after the checksum end the value
     223             :                  * for the compressed length comes the blob data.
     224             :                  *
     225             :                  * NDR already did all the checks for integer wraps.
     226             :                  */
     227           2 :                 csumPartial = ndr_cab_compute_checksum(&ndr->data[data_offset],
     228             :                                                        compressed_length, 0);
     229             : 
     230             :                 /*
     231             :                  * Checksum over header (compressed and uncompressed length).
     232             :                  *
     233             :                  * The first 4 bytes are the checksum size.
     234             :                  * The second 4 bytes are the size of the compressed and
     235             :                  * uncompressed length fields.
     236             :                  *
     237             :                  * NDR already did all the checks for integer wraps.
     238             :                  */
     239           2 :                 csum = ndr_cab_compute_checksum(&ndr->data[compressed_offset],
     240             :                                                 data_offset - compressed_offset,
     241             :                                                 csumPartial);
     242             : 
     243           2 :                 SIVAL(ndr->data, csum_offset, csum);
     244             :         }
     245             : 
     246           2 :         TALLOC_FREE(ndr->cstate);
     247             : 
     248           0 :         return NDR_ERR_SUCCESS;
     249             : }
     250             : 
     251           2 : _PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct cab_file *r)
     252             : {
     253           2 :         uint32_t cntr_cffolders_0;
     254           2 :         uint32_t cntr_cffiles_0;
     255           2 :         size_t processed_cfdata = 0;
     256             :         {
     257           2 :                 libndr_flags _flags_save_STRUCT = ndr->flags;
     258           2 :                 ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
     259           2 :                 NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
     260             : 
     261           2 :                 if (ndr_flags & NDR_SCALARS) {
     262           2 :                         uint32_t i;
     263           2 :                         NDR_CHECK(ndr_push_align(ndr, 4));
     264           2 :                         NDR_CHECK(ndr_push_CFHEADER(ndr, NDR_SCALARS, &r->cfheader));
     265           4 :                         for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (r->cfheader.cFolders); cntr_cffolders_0++) {
     266           2 :                                 NDR_CHECK(ndr_push_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0]));
     267             :                         }
     268           4 :                         for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (r->cfheader.cFiles); cntr_cffiles_0++) {
     269           2 :                                 NDR_CHECK(ndr_push_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0]));
     270             :                         }
     271             : #if 0
     272             :                         NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_count_cfdata(r)));
     273             : #endif
     274             : 
     275             :                         /* write in the folder header the offset of its first data block */
     276           4 :                         for (i = 0; i < r->cfheader.cFolders; i++) {
     277           2 :                                 size_t off = OFFSET_OF_FOLDER_COFFCABSTART(i);
     278             :                                 /* check that the offset we want to
     279             :                                  * write to is always inside our
     280             :                                  * current push buffer
     281             :                                  */
     282           2 :                                 if (off >= ndr->offset) {
     283           0 :                                         return ndr_push_error(ndr, NDR_ERR_OFFSET,
     284             :                                                               "trying to write past current push buffer size");
     285             :                                 }
     286           2 :                                 SIVAL(ndr->data, off, ndr->offset);
     287           2 :                                 NDR_CHECK(ndr_push_folder_cfdata(ndr, r->cfdata + processed_cfdata, r->cffolders[i].typeCompress, r->cffolders[i].cCFData));
     288           2 :                                 processed_cfdata += r->cffolders[i].cCFData;
     289             :                         }
     290           2 :                         NDR_CHECK(ndr_push_trailer_align(ndr, 4));
     291             :                 }
     292           2 :                 if (ndr_flags & NDR_BUFFERS) {
     293           2 :                 }
     294           2 :                 ndr->flags = _flags_save_STRUCT;
     295             :         }
     296             : 
     297             : 
     298             :         /* write total file size in header */
     299           2 :         SIVAL(ndr->data, 8, ndr->offset);
     300             : 
     301           2 :         return NDR_ERR_SUCCESS;
     302             : }
     303             : 
     304             : 
     305             : /* Pull all CFDATA of a folder.
     306             :  *
     307             :  * This works on a folder level because compression type is set per
     308             :  * folder, and a compression state can be shared between CFDATA of the
     309             :  * same folder.
     310             :  *
     311             :  * This is not a regular NDR func as we pass the compression type and
     312             :  * the number of CFDATA as extra arguments
     313             :  */
     314           8 : static enum ndr_err_code ndr_pull_folder_cfdata(struct ndr_pull *ndr,
     315             :                                                 struct CFDATA *r,
     316             :                                                 enum cf_compress_type cab_ctype,
     317             :                                                 size_t num_cfdata)
     318             : {
     319           8 :         size_t i;
     320           8 :         enum ndr_compression_alg ndr_ctype = 0;
     321             : 
     322           8 :         if (cab_ctype == CF_COMPRESS_MSZIP) {
     323           2 :                 ndr_ctype = NDR_COMPRESSION_MSZIP_CAB;
     324           2 :                 NDR_CHECK(ndr_pull_compression_state_init(ndr, NDR_COMPRESSION_MSZIP_CAB, &ndr->cstate));
     325             :         }
     326             : 
     327          16 :         for (i = 0; i < num_cfdata; i++, r++) {
     328           8 :                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->csum));
     329           8 :                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->cbData));
     330           8 :                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->cbUncomp));
     331             : 
     332           8 :                 switch (cab_ctype) {
     333           4 :                 case CF_COMPRESS_NONE:
     334             :                         /* just copy the data */
     335           4 :                         NDR_PULL_NEED_BYTES(ndr, r->cbUncomp);
     336           4 :                         r->ab = data_blob_talloc(ndr->current_mem_ctx,
     337             :                                                  ndr->data+ndr->offset,
     338             :                                                  r->cbUncomp);
     339           4 :                         if (r->ab.data == NULL) {
     340           0 :                                 return ndr_pull_error(ndr, NDR_ERR_ALLOC,
     341             :                                                       "failed to allocate buffer for uncompressed CFDATA block");
     342             :                         }
     343           4 :                         ndr->offset += r->cbUncomp;
     344           4 :                         break;
     345             : 
     346           2 :                 case CF_COMPRESS_LZX:
     347             :                         /* just copy the data (LZX decompression not implemented yet) */
     348           2 :                         NDR_PULL_NEED_BYTES(ndr, r->cbData);
     349           2 :                         r->ab = data_blob_talloc(ndr->current_mem_ctx,
     350             :                                                  ndr->data+ndr->offset,
     351             :                                                  r->cbData);
     352           2 :                         if (r->ab.data == NULL) {
     353           0 :                                 return ndr_pull_error(ndr, NDR_ERR_ALLOC,
     354             :                                                       "failed to allocate buffer for LZX-compressed CFDATA block");
     355             :                         }
     356           2 :                         ndr->offset += r->cbData;
     357           2 :                         break;
     358             : 
     359           2 :                 case CF_COMPRESS_MSZIP: {
     360           2 :                         struct ndr_pull *pull_sub, *pull_compress;
     361           2 :                         NDR_PULL_NEED_BYTES(ndr, r->cbData);
     362             :                         /* decompress via subcontext */
     363           2 :                         NDR_CHECK(ndr_pull_subcontext_start(ndr, &pull_sub, 0, r->cbData));
     364           2 :                         pull_sub->cstate = ndr->cstate;
     365           2 :                         NDR_CHECK(ndr_pull_compression_start(pull_sub, &pull_compress,
     366             :                                                              ndr_ctype, r->cbUncomp, r->cbData));
     367           2 :                         ndr_set_flags(&pull_compress->flags, LIBNDR_FLAG_REMAINING);
     368           2 :                         NDR_CHECK(ndr_pull_DATA_BLOB(pull_compress, NDR_SCALARS, &r->ab));
     369           2 :                         NDR_CHECK(ndr_pull_compression_end(pull_sub, pull_compress, ndr_ctype, r->cbUncomp));
     370           2 :                         NDR_CHECK(ndr_pull_subcontext_end(ndr, pull_sub, 0, r->cbData));
     371             : 
     372           2 :                         break;
     373             :                 }
     374           0 :                 default:
     375           0 :                         return NDR_ERR_BAD_SWITCH;
     376             :                 }
     377             :         }
     378             : 
     379           8 :         TALLOC_FREE(ndr->cstate);
     380             : 
     381           0 :         return NDR_ERR_SUCCESS;
     382             : }
     383             : 
     384           8 : _PUBLIC_ enum ndr_err_code ndr_pull_cab_file(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct cab_file *r)
     385             : {
     386           8 :         uint32_t size_cffolders_0 = 0;
     387           8 :         uint32_t cntr_cffolders_0;
     388           8 :         TALLOC_CTX *_mem_save_cffolders_0 = NULL;
     389           8 :         uint32_t size_cffiles_0 = 0;
     390           8 :         uint32_t cntr_cffiles_0;
     391           8 :         TALLOC_CTX *_mem_save_cffiles_0 = NULL;
     392           8 :         uint32_t size_cfdata_0 = 0;
     393           8 :         size_t processed_cfdata = 0;
     394           8 :         TALLOC_CTX *_mem_save_cfdata_0 = NULL;
     395             :         {
     396           8 :                 libndr_flags _flags_save_STRUCT = ndr->flags;
     397           8 :                 ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
     398           8 :                 NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
     399           8 :                 if (ndr_flags & NDR_SCALARS) {
     400           8 :                         NDR_CHECK(ndr_pull_align(ndr, 4));
     401           8 :                         NDR_CHECK(ndr_pull_CFHEADER(ndr, NDR_SCALARS, &r->cfheader));
     402           8 :                         size_cffolders_0 = r->cfheader.cFolders;
     403           8 :                         NDR_PULL_ALLOC_N(ndr, r->cffolders, size_cffolders_0);
     404           8 :                         _mem_save_cffolders_0 = NDR_PULL_GET_MEM_CTX(ndr);
     405           8 :                         NDR_PULL_SET_MEM_CTX(ndr, r->cffolders, 0);
     406          16 :                         for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (size_cffolders_0); cntr_cffolders_0++) {
     407           8 :                                 NDR_CHECK(ndr_pull_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0]));
     408             :                         }
     409           8 :                         NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffolders_0, 0);
     410           8 :                         size_cffiles_0 = r->cfheader.cFiles;
     411           8 :                         NDR_PULL_ALLOC_N(ndr, r->cffiles, size_cffiles_0);
     412           8 :                         _mem_save_cffiles_0 = NDR_PULL_GET_MEM_CTX(ndr);
     413           8 :                         NDR_PULL_SET_MEM_CTX(ndr, r->cffiles, 0);
     414          16 :                         for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (size_cffiles_0); cntr_cffiles_0++) {
     415           8 :                                 NDR_CHECK(ndr_pull_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0]));
     416             :                         }
     417           8 :                         NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffiles_0, 0);
     418             : #if 0
     419             :                         NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->cfdata_count));
     420             : #else
     421           8 :                         r->cfdata_count = ndr_count_cfdata(r);
     422             : #endif
     423           8 :                         size_cfdata_0 = r->cfdata_count;
     424           8 :                         NDR_PULL_ALLOC_N(ndr, r->cfdata, size_cfdata_0);
     425           8 :                         _mem_save_cfdata_0 = NDR_PULL_GET_MEM_CTX(ndr);
     426           8 :                         NDR_PULL_SET_MEM_CTX(ndr, r->cfdata, 0);
     427          16 :                         for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (size_cffolders_0); cntr_cffolders_0++) {
     428           8 :                                 NDR_CHECK(ndr_pull_folder_cfdata(ndr,
     429             :                                                                  r->cfdata + processed_cfdata,
     430             :                                                                  r->cffolders[cntr_cffolders_0].typeCompress,
     431             :                                                                  r->cffolders[cntr_cffolders_0].cCFData));
     432           8 :                                 processed_cfdata += r->cffolders[cntr_cffolders_0].cCFData;
     433             :                         }
     434           8 :                         NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cfdata_0, 0);
     435           8 :                         NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
     436             :                 }
     437           8 :                 if (ndr_flags & NDR_BUFFERS) {
     438           8 :                 }
     439           8 :                 ndr->flags = _flags_save_STRUCT;
     440             :         }
     441           8 :         return NDR_ERR_SUCCESS;
     442             : }

Generated by: LCOV version 1.14