~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/lib/ldb/ldb_tdb/ldb_pack.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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)
 
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)
 
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)
 
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,
 
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,
 
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
}