librpc: Add autogenerated checksum calculation for Cabinet files
authorGünther Deschner <gd@samba.org>
Thu, 15 Sep 2016 22:15:30 +0000 (00:15 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Thu, 24 Nov 2016 19:24:26 +0000 (20:24 +0100)
Guenther

Signed-off-by: Guenther Deschner <gd@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
librpc/idl/cab.idl
librpc/ndr/ndr_cab.c
librpc/ndr/ndr_cab.h

index af8dad2440493e43fb403e047e9f7b06a407136b..2174bce73343a11cefaafa109c053719b9c6b569 100644 (file)
@@ -111,7 +111,7 @@ import "misc.idl";
        } CFFILE;
 
        typedef [public,flag(NDR_PAHEX|NDR_LITTLE_ENDIAN|NDR_NOALIGN)] struct {
-               uint32 csum;            /* checksum of this CFDATA entry */
+               [value(ndr_cab_generate_checksum(r))] uint32 csum;              /* checksum of this CFDATA entry */
                uint16 cbData;          /* number of compressed bytes in this block */
                uint16 cbUncomp;        /* number of uncompressed bytes in this block */
 #if 0
index 87c103a4901944d7b43dac5a3feb44ee942cb2da..611e378cb34ac3fa99fc7f7579e0cdb50933a5ae 100644 (file)
@@ -63,6 +63,55 @@ uint32_t ndr_count_cfdata(const struct cab_file *r)
        return count;
 }
 
+static uint32_t ndr_cab_compute_checksum(uint8_t *data, uint32_t length, uint32_t seed)
+{
+       int num_ulong;
+       uint32_t checksum;
+       uint8_t *pb;
+       uint32_t ul;
+
+       num_ulong = length / 4;
+       checksum = seed;
+       pb = data;
+
+       while (num_ulong-- > 0) {
+               ul = *pb++;
+               ul |= (((uint32_t)(*pb++)) <<  8);
+               ul |= (((uint32_t)(*pb++)) << 16);
+               ul |= (((uint32_t)(*pb++)) << 24);
+
+               checksum ^= ul;
+       }
+
+       ul = 0;
+
+       switch (length % 4) {
+       case 3:
+               ul |= (((uint32_t)(*pb++)) << 16);
+       case 2:
+               ul |= (((uint32_t)(*pb++)) <<  8);
+       case 1:
+               ul |= *pb++;
+       default:
+               break;
+       }
+
+       checksum ^= ul;
+
+       return checksum;
+}
+
+uint32_t ndr_cab_generate_checksum(const struct CFDATA *r)
+{
+       uint32_t csumPartial;
+
+       csumPartial = ndr_cab_compute_checksum(&r->ab[0], r->cbData, 0);
+
+       return ndr_cab_compute_checksum((uint8_t *)discard_const(&r->cbData),
+                                       sizeof(r->cbData) + sizeof(r->cbUncomp),
+                                       csumPartial);
+}
+
 _PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, int ndr_flags, const struct cab_file *r)
 {
        uint32_t cntr_cffolders_0;
index 39b6bc9b4835dbb507f47c09d0644fd3172e6d2b..59dbc9914421ec168dd7b40f049d8f3a225ce703 100644 (file)
@@ -20,3 +20,4 @@
 */
 
 uint32_t ndr_count_cfdata(const struct cab_file *r);
+uint32_t ndr_cab_generate_checksum(const struct CFDATA *r);