~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/dsdb/samdb/ldb_modules/objectguid.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 Bartlett <abartlet@samba.org> 2005
 
5
   Copyright (C) Andrew Tridgell 2005
 
6
   Copyright (C) Simo Sorce  2004-2008
 
7
 
 
8
     ** NOTE! The following LGPL license applies to the ldb
 
9
     ** library. This does NOT imply that all of Samba is released
 
10
     ** under the LGPL
 
11
   
 
12
   This library is free software; you can redistribute it and/or
 
13
   modify it under the terms of the GNU Lesser General Public
 
14
   License as published by the Free Software Foundation; either
 
15
   version 3 of the License, or (at your option) any later version.
 
16
 
 
17
   This library is distributed in the hope that it will be useful,
 
18
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
20
   Lesser General Public License for more details.
 
21
 
 
22
   You should have received a copy of the GNU Lesser General Public
 
23
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
 
24
*/
 
25
 
 
26
/*
 
27
 *  Name: ldb
 
28
 *
 
29
 *  Component: ldb objectguid module
 
30
 *
 
31
 *  Description: add a unique objectGUID onto every new record
 
32
 *
 
33
 *  Author: Simo Sorce
 
34
 */
 
35
 
 
36
#include "includes.h"
 
37
#include "ldb_module.h"
 
38
#include "librpc/gen_ndr/ndr_misc.h"
 
39
#include "param/param.h"
 
40
 
 
41
static struct ldb_message_element *objectguid_find_attribute(const struct ldb_message *msg, const char *name)
 
42
{
 
43
        int i;
 
44
 
 
45
        for (i = 0; i < msg->num_elements; i++) {
 
46
                if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
 
47
                        return &msg->elements[i];
 
48
                }
 
49
        }
 
50
 
 
51
        return NULL;
 
52
}
 
53
 
 
54
/*
 
55
  add a time element to a record
 
56
*/
 
57
static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
 
58
{
 
59
        struct ldb_message_element *el;
 
60
        char *s;
 
61
 
 
62
        if (ldb_msg_find_element(msg, attr) != NULL) {
 
63
                return 0;
 
64
        }
 
65
 
 
66
        s = ldb_timestring(msg, t);
 
67
        if (s == NULL) {
 
68
                return -1;
 
69
        }
 
70
 
 
71
        if (ldb_msg_add_string(msg, attr, s) != 0) {
 
72
                return -1;
 
73
        }
 
74
 
 
75
        el = ldb_msg_find_element(msg, attr);
 
76
        /* always set as replace. This works because on add ops, the flag
 
77
           is ignored */
 
78
        el->flags = LDB_FLAG_MOD_REPLACE;
 
79
 
 
80
        return 0;
 
81
}
 
82
 
 
83
/*
 
84
  add a uint64_t element to a record
 
85
*/
 
86
static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
 
87
{
 
88
        struct ldb_message_element *el;
 
89
 
 
90
        if (ldb_msg_find_element(msg, attr) != NULL) {
 
91
                return 0;
 
92
        }
 
93
 
 
94
        if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != 0) {
 
95
                return -1;
 
96
        }
 
97
 
 
98
        el = ldb_msg_find_element(msg, attr);
 
99
        /* always set as replace. This works because on add ops, the flag
 
100
           is ignored */
 
101
        el->flags = LDB_FLAG_MOD_REPLACE;
 
102
 
 
103
        return 0;
 
104
}
 
105
 
 
106
struct og_context {
 
107
        struct ldb_module *module;
 
108
        struct ldb_request *req;
 
109
};
 
110
 
 
111
static int og_op_callback(struct ldb_request *req, struct ldb_reply *ares)
 
112
{
 
113
        struct og_context *ac;
 
114
 
 
115
        ac = talloc_get_type(req->context, struct og_context);
 
116
 
 
117
        if (!ares) {
 
118
                return ldb_module_done(ac->req, NULL, NULL,
 
119
                                        LDB_ERR_OPERATIONS_ERROR);
 
120
        }
 
121
        if (ares->error != LDB_SUCCESS) {
 
122
                return ldb_module_done(ac->req, ares->controls,
 
123
                                        ares->response, ares->error);
 
124
        }
 
125
 
 
126
        if (ares->type != LDB_REPLY_DONE) {
 
127
                talloc_free(ares);
 
128
                return ldb_module_done(ac->req, NULL, NULL,
 
129
                                        LDB_ERR_OPERATIONS_ERROR);
 
130
        }
 
131
 
 
132
        return ldb_module_done(ac->req, ares->controls,
 
133
                                ares->response, ares->error);
 
134
}
 
135
 
 
136
/* add_record: add objectGUID attribute */
 
137
static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
 
138
{
 
139
        struct ldb_context *ldb;
 
140
        struct ldb_request *down_req;
 
141
        struct ldb_message_element *attribute;
 
142
        struct ldb_message *msg;
 
143
        struct ldb_val v;
 
144
        struct GUID guid;
 
145
        uint64_t seq_num;
 
146
        enum ndr_err_code ndr_err;
 
147
        int ret;
 
148
        time_t t = time(NULL);
 
149
        struct og_context *ac;
 
150
 
 
151
        ldb = ldb_module_get_ctx(module);
 
152
 
 
153
        ldb_debug(ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
 
154
 
 
155
        /* do not manipulate our control entries */
 
156
        if (ldb_dn_is_special(req->op.add.message->dn)) {
 
157
                return ldb_next_request(module, req);
 
158
        }
 
159
 
 
160
        if ((attribute = objectguid_find_attribute(req->op.add.message, "objectGUID")) != NULL ) {
 
161
                return ldb_next_request(module, req);
 
162
        }
 
163
 
 
164
        ac = talloc(req, struct og_context);
 
165
        if (ac == NULL) {
 
166
                return LDB_ERR_OPERATIONS_ERROR;
 
167
        }
 
168
        ac->module = module;
 
169
        ac->req = req;
 
170
 
 
171
        /* we have to copy the message as the caller might have it as a const */
 
172
        msg = ldb_msg_copy_shallow(ac, req->op.add.message);
 
173
        if (msg == NULL) {
 
174
                talloc_free(down_req);
 
175
                return LDB_ERR_OPERATIONS_ERROR;
 
176
        }
 
177
 
 
178
        /* a new GUID */
 
179
        guid = GUID_random();
 
180
 
 
181
        ndr_err = ndr_push_struct_blob(&v, msg, 
 
182
                                       lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
 
183
                                       &guid,
 
184
                                       (ndr_push_flags_fn_t)ndr_push_GUID);
 
185
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
186
                return LDB_ERR_OPERATIONS_ERROR;
 
187
        }
 
188
 
 
189
        ret = ldb_msg_add_value(msg, "objectGUID", &v, NULL);
 
190
        if (ret) {
 
191
                return ret;
 
192
        }
 
193
        
 
194
        if (add_time_element(msg, "whenCreated", t) != 0 ||
 
195
            add_time_element(msg, "whenChanged", t) != 0) {
 
196
                return LDB_ERR_OPERATIONS_ERROR;
 
197
        }
 
198
 
 
199
        /* Get a sequence number from the backend */
 
200
        /* FIXME: ldb_sequence_number is a semi-async call,
 
201
         * make sure this function is split and a callback is used */
 
202
        ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
 
203
        if (ret == LDB_SUCCESS) {
 
204
                if (add_uint64_element(msg, "uSNCreated", seq_num) != 0 ||
 
205
                    add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
 
206
                        return LDB_ERR_OPERATIONS_ERROR;
 
207
                }
 
208
        }
 
209
 
 
210
        ret = ldb_build_add_req(&down_req, ldb, ac,
 
211
                                msg,
 
212
                                req->controls,
 
213
                                ac, og_op_callback,
 
214
                                req);
 
215
        if (ret != LDB_SUCCESS) {
 
216
                return LDB_ERR_OPERATIONS_ERROR;
 
217
        }
 
218
 
 
219
        /* go on with the call chain */
 
220
        return ldb_next_request(module, down_req);
 
221
}
 
222
 
 
223
/* modify_record: update timestamps */
 
224
static int objectguid_modify(struct ldb_module *module, struct ldb_request *req)
 
225
{
 
226
        struct ldb_context *ldb;
 
227
        struct ldb_request *down_req;
 
228
        struct ldb_message *msg;
 
229
        int ret;
 
230
        time_t t = time(NULL);
 
231
        uint64_t seq_num;
 
232
        struct og_context *ac;
 
233
 
 
234
        ldb = ldb_module_get_ctx(module);
 
235
 
 
236
        ldb_debug(ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
 
237
 
 
238
        /* do not manipulate our control entries */
 
239
        if (ldb_dn_is_special(req->op.add.message->dn)) {
 
240
                return ldb_next_request(module, req);
 
241
        }
 
242
 
 
243
        ac = talloc(req, struct og_context);
 
244
        if (ac == NULL) {
 
245
                return LDB_ERR_OPERATIONS_ERROR;
 
246
        }
 
247
        ac->module = module;
 
248
        ac->req = req;
 
249
 
 
250
        /* we have to copy the message as the caller might have it as a const */
 
251
        msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
 
252
        if (msg == NULL) {
 
253
                return LDB_ERR_OPERATIONS_ERROR;
 
254
        }
 
255
 
 
256
        if (add_time_element(msg, "whenChanged", t) != 0) {
 
257
                return LDB_ERR_OPERATIONS_ERROR;
 
258
        }
 
259
 
 
260
        /* Get a sequence number from the backend */
 
261
        ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
 
262
        if (ret == LDB_SUCCESS) {
 
263
                if (add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
 
264
                        return LDB_ERR_OPERATIONS_ERROR;
 
265
                }
 
266
        }
 
267
 
 
268
        ret = ldb_build_mod_req(&down_req, ldb, ac,
 
269
                                msg,
 
270
                                req->controls,
 
271
                                ac, og_op_callback,
 
272
                                req);
 
273
        if (ret != LDB_SUCCESS) {
 
274
                return LDB_ERR_OPERATIONS_ERROR;
 
275
        }
 
276
 
 
277
        /* go on with the call chain */
 
278
        return ldb_next_request(module, down_req);
 
279
}
 
280
 
 
281
_PUBLIC_ const struct ldb_module_ops ldb_objectguid_module_ops = {
 
282
        .name          = "objectguid",
 
283
        .add           = objectguid_add,
 
284
        .modify        = objectguid_modify,
 
285
};