mirror of
https://github.com/samba-team/samba.git
synced 2025-01-15 23:24:37 +03:00
a9e31b33b5
- ldb_dn_get_linearized returns a const string - ldb_dn_alloc_linearized allocs astring with the linearized dn (This used to be commit 3929c086d5d0b3f08b1c4f2f3f9602c3f4a9a4bd)
293 lines
6.8 KiB
C
293 lines
6.8 KiB
C
/*
|
|
ldb database library
|
|
|
|
Copyright (C) Andrew Tridgell 2004
|
|
|
|
** NOTE! The following LGPL license applies to the ldb
|
|
** library. This does NOT imply that all of Samba is released
|
|
** under the LGPL
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* Name: ldb
|
|
*
|
|
* Component: ldb pack/unpack
|
|
*
|
|
* Description: pack/unpack routines for ldb messages as key/value blobs
|
|
*
|
|
* Author: Andrew Tridgell
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "ldb/include/includes.h"
|
|
|
|
#include "ldb/ldb_tdb/ldb_tdb.h"
|
|
|
|
/* change this if the data format ever changes */
|
|
#define LTDB_PACKING_FORMAT 0x26011967
|
|
|
|
/* old packing formats */
|
|
#define LTDB_PACKING_FORMAT_NODN 0x26011966
|
|
|
|
/* use a portable integer format */
|
|
static void put_uint32(uint8_t *p, int ofs, unsigned int val)
|
|
{
|
|
p += ofs;
|
|
p[0] = val&0xFF;
|
|
p[1] = (val>>8) & 0xFF;
|
|
p[2] = (val>>16) & 0xFF;
|
|
p[3] = (val>>24) & 0xFF;
|
|
}
|
|
|
|
static unsigned int pull_uint32(uint8_t *p, int ofs)
|
|
{
|
|
p += ofs;
|
|
return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
|
|
}
|
|
|
|
static int attribute_storable_values(const struct ldb_message_element *el)
|
|
{
|
|
if (el->num_values == 0) return 0;
|
|
|
|
if (ldb_attr_cmp(el->name, "dn") == 0) return 0;
|
|
|
|
if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
|
|
|
|
return el->num_values;
|
|
}
|
|
|
|
/*
|
|
pack a ldb message into a linear buffer in a TDB_DATA
|
|
|
|
note that this routine avoids saving elements with zero values,
|
|
as these are equivalent to having no element
|
|
|
|
caller frees the data buffer after use
|
|
*/
|
|
int ltdb_pack_data(struct ldb_module *module,
|
|
const struct ldb_message *message,
|
|
struct TDB_DATA *data)
|
|
{
|
|
struct ldb_context *ldb = module->ldb;
|
|
unsigned int i, j, real_elements=0;
|
|
size_t size;
|
|
const char *dn;
|
|
uint8_t *p;
|
|
size_t len;
|
|
|
|
dn = ldb_dn_get_linearized(message->dn);
|
|
if (dn == NULL) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
/* work out how big it needs to be */
|
|
size = 8;
|
|
|
|
size += 1 + strlen(dn);
|
|
|
|
for (i=0;i<message->num_elements;i++) {
|
|
if (attribute_storable_values(&message->elements[i]) == 0) {
|
|
continue;
|
|
}
|
|
|
|
real_elements++;
|
|
|
|
size += 1 + strlen(message->elements[i].name) + 4;
|
|
for (j=0;j<message->elements[i].num_values;j++) {
|
|
size += 4 + message->elements[i].values[j].length + 1;
|
|
}
|
|
}
|
|
|
|
/* allocate it */
|
|
data->dptr = talloc_array(ldb, uint8_t, size);
|
|
if (!data->dptr) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
data->dsize = size;
|
|
|
|
p = data->dptr;
|
|
put_uint32(p, 0, LTDB_PACKING_FORMAT);
|
|
put_uint32(p, 4, real_elements);
|
|
p += 8;
|
|
|
|
/* the dn needs to be packed so we can be case preserving
|
|
while hashing on a case folded dn */
|
|
len = strlen(dn);
|
|
memcpy(p, dn, len+1);
|
|
p += len + 1;
|
|
|
|
for (i=0;i<message->num_elements;i++) {
|
|
if (attribute_storable_values(&message->elements[i]) == 0) {
|
|
continue;
|
|
}
|
|
len = strlen(message->elements[i].name);
|
|
memcpy(p, message->elements[i].name, len+1);
|
|
p += len + 1;
|
|
put_uint32(p, 0, message->elements[i].num_values);
|
|
p += 4;
|
|
for (j=0;j<message->elements[i].num_values;j++) {
|
|
put_uint32(p, 0, message->elements[i].values[j].length);
|
|
memcpy(p+4, message->elements[i].values[j].data,
|
|
message->elements[i].values[j].length);
|
|
p[4+message->elements[i].values[j].length] = 0;
|
|
p += 4 + message->elements[i].values[j].length + 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
unpack a ldb message from a linear buffer in TDB_DATA
|
|
|
|
Free with ltdb_unpack_data_free()
|
|
*/
|
|
int ltdb_unpack_data(struct ldb_module *module,
|
|
const struct TDB_DATA *data,
|
|
struct ldb_message *message)
|
|
{
|
|
struct ldb_context *ldb = module->ldb;
|
|
uint8_t *p;
|
|
unsigned int remaining;
|
|
unsigned int i, j;
|
|
unsigned format;
|
|
size_t len;
|
|
|
|
message->elements = NULL;
|
|
|
|
p = data->dptr;
|
|
if (data->dsize < 8) {
|
|
errno = EIO;
|
|
goto failed;
|
|
}
|
|
|
|
format = pull_uint32(p, 0);
|
|
message->num_elements = pull_uint32(p, 4);
|
|
p += 8;
|
|
|
|
remaining = data->dsize - 8;
|
|
|
|
switch (format) {
|
|
case LTDB_PACKING_FORMAT_NODN:
|
|
message->dn = NULL;
|
|
break;
|
|
|
|
case LTDB_PACKING_FORMAT:
|
|
len = strnlen((char *)p, remaining);
|
|
if (len == remaining) {
|
|
errno = EIO;
|
|
goto failed;
|
|
}
|
|
message->dn = ldb_dn_new(message, ldb, (char *)p);
|
|
if (message->dn == NULL) {
|
|
errno = ENOMEM;
|
|
goto failed;
|
|
}
|
|
remaining -= len + 1;
|
|
p += len + 1;
|
|
break;
|
|
|
|
default:
|
|
errno = EIO;
|
|
goto failed;
|
|
}
|
|
|
|
if (message->num_elements == 0) {
|
|
message->elements = NULL;
|
|
return 0;
|
|
}
|
|
|
|
if (message->num_elements > remaining / 6) {
|
|
errno = EIO;
|
|
goto failed;
|
|
}
|
|
|
|
message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
|
|
if (!message->elements) {
|
|
errno = ENOMEM;
|
|
goto failed;
|
|
}
|
|
|
|
memset(message->elements, 0,
|
|
message->num_elements * sizeof(struct ldb_message_element));
|
|
|
|
for (i=0;i<message->num_elements;i++) {
|
|
if (remaining < 10) {
|
|
errno = EIO;
|
|
goto failed;
|
|
}
|
|
len = strnlen((char *)p, remaining-6);
|
|
if (len == remaining-6) {
|
|
errno = EIO;
|
|
goto failed;
|
|
}
|
|
message->elements[i].flags = 0;
|
|
message->elements[i].name = talloc_strndup(message->elements, (char *)p, len);
|
|
if (message->elements[i].name == NULL) {
|
|
errno = ENOMEM;
|
|
goto failed;
|
|
}
|
|
remaining -= len + 1;
|
|
p += len + 1;
|
|
message->elements[i].num_values = pull_uint32(p, 0);
|
|
message->elements[i].values = NULL;
|
|
if (message->elements[i].num_values != 0) {
|
|
message->elements[i].values = talloc_array(message->elements,
|
|
struct ldb_val,
|
|
message->elements[i].num_values);
|
|
if (!message->elements[i].values) {
|
|
errno = ENOMEM;
|
|
goto failed;
|
|
}
|
|
}
|
|
p += 4;
|
|
remaining -= 4;
|
|
for (j=0;j<message->elements[i].num_values;j++) {
|
|
len = pull_uint32(p, 0);
|
|
if (len > remaining-5) {
|
|
errno = EIO;
|
|
goto failed;
|
|
}
|
|
|
|
message->elements[i].values[j].length = len;
|
|
message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1);
|
|
if (message->elements[i].values[j].data == NULL) {
|
|
errno = ENOMEM;
|
|
goto failed;
|
|
}
|
|
memcpy(message->elements[i].values[j].data, p+4, len);
|
|
message->elements[i].values[j].data[len] = 0;
|
|
|
|
remaining -= len+4+1;
|
|
p += len+4+1;
|
|
}
|
|
}
|
|
|
|
if (remaining != 0) {
|
|
ldb_debug(ldb, LDB_DEBUG_ERROR,
|
|
"Error: %d bytes unread in ltdb_unpack_data\n", remaining);
|
|
}
|
|
|
|
return 0;
|
|
|
|
failed:
|
|
talloc_free(message->elements);
|
|
return -1;
|
|
}
|