root/source3/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 "includes.h"
  35 #include "ldb/include/includes.h"
  36 
  37 #include "ldb/ldb_tdb/ldb_tdb.h"
  38 
  39 /* change this if the data format ever changes */
  40 #define LTDB_PACKING_FORMAT 0x26011967
  41 
  42 /* old packing formats */
  43 #define LTDB_PACKING_FORMAT_NODN 0x26011966
  44 
  45 /* use a portable integer format */
  46 static void put_uint32(uint8_t *p, int ofs, unsigned int val)
     /* [<][>][^][v][top][bottom][index][help] */
  47 {
  48         p += ofs;
  49         p[0] = val&0xFF;
  50         p[1] = (val>>8)  & 0xFF;
  51         p[2] = (val>>16) & 0xFF;
  52         p[3] = (val>>24) & 0xFF;
  53 }
  54 
  55 static unsigned int pull_uint32(uint8_t *p, int ofs)
     /* [<][>][^][v][top][bottom][index][help] */
  56 {
  57         p += ofs;
  58         return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
  59 }
  60 
  61 static int attribute_storable_values(const struct ldb_message_element *el)
     /* [<][>][^][v][top][bottom][index][help] */
  62 {
  63         if (el->num_values == 0) return 0;
  64 
  65         if (ldb_attr_cmp(el->name, "dn") == 0) return 0;
  66 
  67         if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
  68 
  69         return el->num_values;
  70 }
  71 
  72 /*
  73   pack a ldb message into a linear buffer in a TDB_DATA
  74 
  75   note that this routine avoids saving elements with zero values,
  76   as these are equivalent to having no element
  77 
  78   caller frees the data buffer after use
  79 */
  80 int ltdb_pack_data(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
  81                    const struct ldb_message *message,
  82                    struct TDB_DATA *data)
  83 {
  84         struct ldb_context *ldb = module->ldb;
  85         unsigned int i, j, real_elements=0;
  86         size_t size;
  87         char *dn;
  88         uint8_t *p;
  89         size_t len;
  90 
  91         dn = ldb_dn_linearize(ldb, message->dn);
  92         if (dn == NULL) {
  93                 errno = ENOMEM;
  94                 return -1;
  95         }
  96 
  97         /* work out how big it needs to be */
  98         size = 8;
  99 
 100         size += 1 + strlen(dn);
 101 
 102         for (i=0;i<message->num_elements;i++) {
 103                 if (attribute_storable_values(&message->elements[i]) == 0) {
 104                         continue;
 105                 }
 106 
 107                 real_elements++;
 108 
 109                 size += 1 + strlen(message->elements[i].name) + 4;
 110                 for (j=0;j<message->elements[i].num_values;j++) {
 111                         size += 4 + message->elements[i].values[j].length + 1;
 112                 }
 113         }
 114 
 115         /* allocate it */
 116         data->dptr = talloc_array(ldb, uint8_t, size);
 117         if (!data->dptr) {
 118                 talloc_free(dn);
 119                 errno = ENOMEM;
 120                 return -1;
 121         }
 122         data->dsize = size;
 123 
 124         p = (uint8_t *)data->dptr;
 125         put_uint32(p, 0, LTDB_PACKING_FORMAT); 
 126         put_uint32(p, 4, real_elements); 
 127         p += 8;
 128 
 129         /* the dn needs to be packed so we can be case preserving
 130            while hashing on a case folded dn */
 131         len = strlen(dn);
 132         memcpy(p, dn, len+1);
 133         p += len + 1;
 134         
 135         for (i=0;i<message->num_elements;i++) {
 136                 if (attribute_storable_values(&message->elements[i]) == 0) {
 137                         continue;
 138                 }
 139                 len = strlen(message->elements[i].name);
 140                 memcpy(p, message->elements[i].name, len+1);
 141                 p += len + 1;
 142                 put_uint32(p, 0, message->elements[i].num_values);
 143                 p += 4;
 144                 for (j=0;j<message->elements[i].num_values;j++) {
 145                         put_uint32(p, 0, message->elements[i].values[j].length);
 146                         memcpy(p+4, message->elements[i].values[j].data, 
 147                                message->elements[i].values[j].length);
 148                         p[4+message->elements[i].values[j].length] = 0;
 149                         p += 4 + message->elements[i].values[j].length + 1;
 150                 }
 151         }
 152 
 153         talloc_free(dn);
 154         return 0;
 155 }
 156 
 157 /*
 158   unpack a ldb message from a linear buffer in TDB_DATA
 159 
 160   Free with ltdb_unpack_data_free()
 161 */
 162 int ltdb_unpack_data(struct ldb_module *module,
     /* [<][>][^][v][top][bottom][index][help] */
 163                      const struct TDB_DATA *data,
 164                      struct ldb_message *message)
 165 {
 166         struct ldb_context *ldb = module->ldb;
 167         uint8_t *p;
 168         unsigned int remaining;
 169         unsigned int i, j;
 170         unsigned format;
 171         size_t len;
 172 
 173         message->elements = NULL;
 174 
 175         p = (uint8_t *)data->dptr;
 176         if (data->dsize < 8) {
 177                 errno = EIO;
 178                 goto failed;
 179         }
 180 
 181         format = pull_uint32(p, 0);
 182         message->num_elements = pull_uint32(p, 4);
 183         p += 8;
 184 
 185         remaining = data->dsize - 8;
 186 
 187         switch (format) {
 188         case LTDB_PACKING_FORMAT_NODN:
 189                 message->dn = NULL;
 190                 break;
 191 
 192         case LTDB_PACKING_FORMAT:
 193                 len = strnlen((char *)p, remaining);
 194                 if (len == remaining) {
 195                         errno = EIO;
 196                         goto failed;
 197                 }
 198                 message->dn = ldb_dn_explode(message, (char *)p);
 199                 if (message->dn == NULL) {
 200                         errno = ENOMEM;
 201                         goto failed;
 202                 }
 203                 remaining -= len + 1;
 204                 p += len + 1;
 205                 break;
 206 
 207         default:
 208                 errno = EIO;
 209                 goto failed;
 210         }
 211 
 212         if (message->num_elements == 0) {
 213                 message->elements = NULL;
 214                 return 0;
 215         }
 216         
 217         if (message->num_elements > remaining / 6) {
 218                 errno = EIO;
 219                 goto failed;
 220         }
 221 
 222         message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
 223         if (!message->elements) {
 224                 errno = ENOMEM;
 225                 goto failed;
 226         }
 227 
 228         memset(message->elements, 0, 
 229                message->num_elements * sizeof(struct ldb_message_element));
 230 
 231         for (i=0;i<message->num_elements;i++) {
 232                 if (remaining < 10) {
 233                         errno = EIO;
 234                         goto failed;
 235                 }
 236                 len = strnlen((char *)p, remaining-6);
 237                 if (len == remaining-6) {
 238                         errno = EIO;
 239                         goto failed;
 240                 }
 241                 message->elements[i].flags = 0;
 242                 message->elements[i].name = talloc_strndup(message->elements, (char *)p, len);
 243                 if (message->elements[i].name == NULL) {
 244                         errno = ENOMEM;
 245                         goto failed;
 246                 }
 247                 remaining -= len + 1;
 248                 p += len + 1;
 249                 message->elements[i].num_values = pull_uint32(p, 0);
 250                 message->elements[i].values = NULL;
 251                 if (message->elements[i].num_values != 0) {
 252                         message->elements[i].values = talloc_array(message->elements,
 253                                                                      struct ldb_val, 
 254                                                                      message->elements[i].num_values);
 255                         if (!message->elements[i].values) {
 256                                 errno = ENOMEM;
 257                                 goto failed;
 258                         }
 259                 }
 260                 p += 4;
 261                 remaining -= 4;
 262                 for (j=0;j<message->elements[i].num_values;j++) {
 263                         len = pull_uint32(p, 0);
 264                         if (len > remaining-5) {
 265                                 errno = EIO;
 266                                 goto failed;
 267                         }
 268 
 269                         message->elements[i].values[j].length = len;
 270                         message->elements[i].values[j].data = (uint8_t *)talloc_size(message->elements[i].values, len+1);
 271                         if (message->elements[i].values[j].data == NULL) {
 272                                 errno = ENOMEM;
 273                                 goto failed;
 274                         }
 275                         memcpy(message->elements[i].values[j].data, p+4, len);
 276                         message->elements[i].values[j].data[len] = 0;
 277         
 278                         remaining -= len+4+1;
 279                         p += len+4+1;
 280                 }
 281         }
 282 
 283         if (remaining != 0) {
 284                 ldb_debug(ldb, LDB_DEBUG_ERROR, 
 285                           "Error: %d bytes unread in ltdb_unpack_data\n", remaining);
 286         }
 287 
 288         return 0;
 289 
 290 failed:
 291         talloc_free(message->elements);
 292         return -1;
 293 }

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