4
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
5
Copyright (C) Andrew Tridgell 2005
6
Copyright (C) Simo Sorce 2004-2008
8
** NOTE! The following LGPL license applies to the ldb
9
** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
29
* Component: ldb objectguid module
31
* Description: add a unique objectGUID onto every new record
37
#include "ldb_module.h"
38
#include "librpc/gen_ndr/ndr_misc.h"
39
#include "param/param.h"
41
static struct ldb_message_element *objectguid_find_attribute(const struct ldb_message *msg, const char *name)
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];
55
add a time element to a record
57
static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
59
struct ldb_message_element *el;
62
if (ldb_msg_find_element(msg, attr) != NULL) {
66
s = ldb_timestring(msg, t);
71
if (ldb_msg_add_string(msg, attr, s) != 0) {
75
el = ldb_msg_find_element(msg, attr);
76
/* always set as replace. This works because on add ops, the flag
78
el->flags = LDB_FLAG_MOD_REPLACE;
84
add a uint64_t element to a record
86
static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
88
struct ldb_message_element *el;
90
if (ldb_msg_find_element(msg, attr) != NULL) {
94
if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != 0) {
98
el = ldb_msg_find_element(msg, attr);
99
/* always set as replace. This works because on add ops, the flag
101
el->flags = LDB_FLAG_MOD_REPLACE;
107
struct ldb_module *module;
108
struct ldb_request *req;
111
static int og_op_callback(struct ldb_request *req, struct ldb_reply *ares)
113
struct og_context *ac;
115
ac = talloc_get_type(req->context, struct og_context);
118
return ldb_module_done(ac->req, NULL, NULL,
119
LDB_ERR_OPERATIONS_ERROR);
121
if (ares->error != LDB_SUCCESS) {
122
return ldb_module_done(ac->req, ares->controls,
123
ares->response, ares->error);
126
if (ares->type != LDB_REPLY_DONE) {
128
return ldb_module_done(ac->req, NULL, NULL,
129
LDB_ERR_OPERATIONS_ERROR);
132
return ldb_module_done(ac->req, ares->controls,
133
ares->response, ares->error);
136
/* add_record: add objectGUID attribute */
137
static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
139
struct ldb_context *ldb;
140
struct ldb_request *down_req;
141
struct ldb_message_element *attribute;
142
struct ldb_message *msg;
146
enum ndr_err_code ndr_err;
148
time_t t = time(NULL);
149
struct og_context *ac;
151
ldb = ldb_module_get_ctx(module);
153
ldb_debug(ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
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);
160
if ((attribute = objectguid_find_attribute(req->op.add.message, "objectGUID")) != NULL ) {
161
return ldb_next_request(module, req);
164
ac = talloc(req, struct og_context);
166
return LDB_ERR_OPERATIONS_ERROR;
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);
174
talloc_free(down_req);
175
return LDB_ERR_OPERATIONS_ERROR;
179
guid = GUID_random();
181
ndr_err = ndr_push_struct_blob(&v, msg,
182
lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
184
(ndr_push_flags_fn_t)ndr_push_GUID);
185
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
186
return LDB_ERR_OPERATIONS_ERROR;
189
ret = ldb_msg_add_value(msg, "objectGUID", &v, NULL);
194
if (add_time_element(msg, "whenCreated", t) != 0 ||
195
add_time_element(msg, "whenChanged", t) != 0) {
196
return LDB_ERR_OPERATIONS_ERROR;
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;
210
ret = ldb_build_add_req(&down_req, ldb, ac,
215
if (ret != LDB_SUCCESS) {
216
return LDB_ERR_OPERATIONS_ERROR;
219
/* go on with the call chain */
220
return ldb_next_request(module, down_req);
223
/* modify_record: update timestamps */
224
static int objectguid_modify(struct ldb_module *module, struct ldb_request *req)
226
struct ldb_context *ldb;
227
struct ldb_request *down_req;
228
struct ldb_message *msg;
230
time_t t = time(NULL);
232
struct og_context *ac;
234
ldb = ldb_module_get_ctx(module);
236
ldb_debug(ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
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);
243
ac = talloc(req, struct og_context);
245
return LDB_ERR_OPERATIONS_ERROR;
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);
253
return LDB_ERR_OPERATIONS_ERROR;
256
if (add_time_element(msg, "whenChanged", t) != 0) {
257
return LDB_ERR_OPERATIONS_ERROR;
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;
268
ret = ldb_build_mod_req(&down_req, ldb, ac,
273
if (ret != LDB_SUCCESS) {
274
return LDB_ERR_OPERATIONS_ERROR;
277
/* go on with the call chain */
278
return ldb_next_request(module, down_req);
281
_PUBLIC_ const struct ldb_module_ops ldb_objectguid_module_ops = {
282
.name = "objectguid",
283
.add = objectguid_add,
284
.modify = objectguid_modify,