root/source4/lib/ldb/ldb_tdb/ldb_pack.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. put_uint32
  2. pull_uint32
  3. attribute_storable_values
  4. ltdb_pack_data
  5. ltdb_unpack_data

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Andrew Tridgell  2004
   5 
   6      ** NOTE! The following LGPL license applies to the ldb
   7      ** library. This does NOT imply that all of Samba is released
   8      ** under the LGPL
   9    
  10    This library is free software; you can redistribute it and/or
  11    modify it under the terms of the GNU Lesser General Public
  12    License as published by the Free Software Foundation; either
  13    version 3 of the License, or (at your option) any later version.
  14 
  15    This library is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18    Lesser General Public License for more details.
  19 
  20    You should have received a copy of the GNU Lesser General Public
  21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 /*
  25  *  Name: ldb
  26  *
  27  *  Component: ldb pack/unpack
  28  *
  29  *  Description: pack/unpack routines for ldb messages as key/value blobs
  30  *
  31  *  Author: Andrew Tridgell
  32  */
  33 
  34 #include "ldb_tdb.h"
  35 
  36 /* change this if the data format ever changes */
  37 #define LTDB_PACKING_FORMAT 0x26011967
  38 
  39 /* old packing formats */
  40 #define LTDB_PACKING_FORMAT_NODN 0x26011966
  41 
  42 /* use a portable integer format */
  43 static void put_uint32(uint8_t *p, int ofs, unsigned int val)
     /* [<][>][^][v][top][bottom][index][help] */
  44 {
  45         p += ofs;
  46         p[0] = val&0xFF;
  47         p[1] = (val>>8)  & 0xFF;
  48         p[2] = (val>>16) & 0xFF;
  49         p[3] = (val>>24) & 0xFF;
  50 }
  51 
  52 static unsigned int pull_uint32(uint8_t *p, int ofs)
     /* [<][>][^][v][top][bottom][index][help] */
  53 {
  54         p += ofs;
  55         return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
  56 }
  57 
  58 static int attribute_storable_values(const struct ldb_message_element *el)
     /* [<][>][^][v][top][bottom][index][help] */
  59 {
  60         if (el->num_values == 0) return 0;
  61 
  62         if (ldb_attr_cmp(el->name, "dn") == 0) return 0;
  63 
  64         if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
  65 
  66         return el->num_values;
  67 }
  68 
  69 /*
  70   pack a ldb message into a linear buffer in a TDB_DATA
  71 
  72   note that this routine avoids saving elements with zero values,
  73   as these are equivalent to having no element
  74 
  75   caller frees the data buffer after use
  76 */
  77 int ltdb_pack_data(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
  78                    const struct ldb_message *message,
  79                    struct TDB_DATA *data)
  80 {
  81         struct ldb_context *ldb;
  82         unsigned int i, j, real_elements=0;
  83         size_t size;
  84         const char *dn;
  85         uint8_t *p;
  86         size_t len;
  87 
  88         ldb = ldb_module_get_ctx(module);
  89 
  90         dn = ldb_dn_get_linearized(message->dn);
  91         if (dn == NULL) {
  92                 errno = ENOMEM;
  93                 return -1;
  94         }
  95 
  96         /* work out how big it needs to be */
  97         size = 8;
  98 
  99         size += 1 + strlen(dn);
 100 
 101         for (i=0;i<message->num_elements;i++) {
 102                 if (attribute_storable_values(&message->elements[i]) == 0) {
 103                         continue;
 104                 }
 105 
 106                 real_elements++;
 107 
 108                 size += 1 + strlen(message->elements[i].name) + 4;
 109                 for (j=0;j<message->elements[i].num_values;j++) {
 110                         size += 4 + message->elements[i].values[j].length + 1;
 111                 }
 112         }
 113 
 114         /* allocate it */
 115         data->dptr = talloc_array(ldb, uint8_t, size);
 116         if (!data->dptr) {
 117                 errno = ENOMEM;
 118                 return -1;
 119         }
 120         data->dsize = size;
 121 
 122         p = data->dptr;
 123         put_uint32(p, 0, LTDB_PACKING_FORMAT); 
 124         put_uint32(p, 4, real_elements); 
 125         p += 8;
 126 
 127         /* the dn needs to be packed so we can be case preserving
 128            while hashing on a case folded dn */
 129         len = strlen(dn);
 130         memcpy(p, dn, len+1);
 131         p += len + 1;
 132         
 133         for (i=0;i<message->num_elements;i++) {
 134                 if (attribute_storable_values(&message->elements[i]) == 0) {
 135                         continue;
 136                 }
 137                 len = strlen(message->elements[i].name);
 138                 memcpy(p, message->elements[i].name, len+1);
 139                 p += len + 1;
 140                 put_uint32(p, 0, message->elements[i].num_values);
 141                 p += 4;
 142                 for (j=0;j<message->elements[i].num_values;j++) {
 143                         put_uint32(p, 0, message->elements[i].values[j].length);
 144                         memcpy(p+4, message->elements[i].values[j].data, 
 145                                message->elements[i].values[j].length);
 146                         p[4+message->elements[i].values[j].length] = 0;
 147                         p += 4 + message->elements[i].values[j].length + 1;
 148                 }
 149         }
 150 
 151         return 0;
 152 }
 153 
 154 /*
 155   unpack a ldb message from a linear buffer in TDB_DATA
 156 
 157   Free with ltdb_unpack_data_free()
 158 */
 159 int ltdb_unpack_data(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
 160                      const struct TDB_DATA *data,
 161                      struct ldb_message *message)
 162 {
 163         struct ldb_context *ldb;
 164         uint8_t *p;
 165         unsigned int remaining;
 166         unsigned int i, j;
 167         unsigned format;
 168         size_t len;
 169 
 170         ldb = ldb_module_get_ctx(module);
 171         message->elements = NULL;
 172 
 173         p = data->dptr;
 174         if (data->dsize < 8) {
 175                 errno = EIO;
 176                 goto failed;
 177         }
 178 
 179         format = pull_uint32(p, 0);
 180         message->num_elements = pull_uint32(p, 4);
 181         p += 8;
 182 
 183         remaining = data->dsize - 8;
 184 
 185         switch (format) {
 186         case LTDB_PACKING_FORMAT_NODN:
 187                 message->dn = NULL;
 188                 break;
 189 
 190         case LTDB_PACKING_FORMAT:
 191                 len = strnlen((char *)p, remaining);
 192                 if (len == remaining) {
 193                         errno = EIO;
 194                         goto failed;
 195                 }
 196                 message->dn = ldb_dn_new(message, ldb, (char *)p);
 197                 if (message->dn == NULL) {
 198                         errno = ENOMEM;
 199                         goto failed;
 200                 }
 201                 remaining -= len + 1;
 202                 p += len + 1;
 203                 break;
 204 
 205         default:
 206                 errno = EIO;
 207                 goto failed;
 208         }
 209 
 210         if (message->num_elements == 0) {
 211                 message->elements = NULL;
 212                 return 0;
 213         }
 214         
 215         if (message->num_elements > remaining / 6) {
 216                 errno = EIO;
 217                 goto failed;
 218         }
 219 
 220         message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
 221         if (!message->elements) {
 222                 errno = ENOMEM;
 223                 goto failed;
 224         }
 225 
 226         memset(message->elements, 0, 
 227                message->num_elements * sizeof(struct ldb_message_element));
 228 
 229         for (i=0;i<message->num_elements;i++) {
 230                 if (remaining < 10) {
 231                         errno = EIO;
 232                         goto failed;
 233                 }
 234                 len = strnlen((char *)p, remaining-6);
 235                 if (len == remaining-6) {
 236                         errno = EIO;
 237                         goto failed;
 238                 }
 239                 message->elements[i].flags = 0;
 240                 message->elements[i].name = talloc_strndup(message->elements, (char *)p, len);
 241                 if (message->elements[i].name == NULL) {
 242                         errno = ENOMEM;
 243                         goto failed;
 244                 }
 245                 remaining -= len + 1;
 246                 p += len + 1;
 247                 message->elements[i].num_values = pull_uint32(p, 0);
 248                 message->elements[i].values = NULL;
 249                 if (message->elements[i].num_values != 0) {
 250                         message->elements[i].values = talloc_array(message->elements,
 251                                                                      struct ldb_val, 
 252                                                                      message->elements[i].num_values);
 253                         if (!message->elements[i].values) {
 254                                 errno = ENOMEM;
 255                                 goto failed;
 256                         }
 257                 }
 258                 p += 4;
 259                 remaining -= 4;
 260                 for (j=0;j<message->elements[i].num_values;j++) {
 261                         len = pull_uint32(p, 0);
 262                         if (len > remaining-5) {
 263                                 errno = EIO;
 264                                 goto failed;
 265                         }
 266 
 267                         message->elements[i].values[j].length = len;
 268                         message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1);
 269                         if (message->elements[i].values[j].data == NULL) {
 270                                 errno = ENOMEM;
 271                                 goto failed;
 272                         }
 273                         memcpy(message->elements[i].values[j].data, p+4, len);
 274                         message->elements[i].values[j].data[len] = 0;
 275         
 276                         remaining -= len+4+1;
 277                         p += len+4+1;
 278                 }
 279         }
 280 
 281         if (remaining != 0) {
 282                 ldb_debug(ldb, LDB_DEBUG_ERROR, 
 283                           "Error: %d bytes unread in ltdb_unpack_data\n", remaining);
 284         }
 285 
 286         return 0;
 287 
 288 failed:
 289         talloc_free(message->elements);
 290         return -1;
 291 }

/* [<][>][^][v][top][bottom][index][help] */