4 Copyright (C) Simo Sorce 2004-2006
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6 Copyright (C) Andrew Tridgell 2005
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 2 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, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 * Component: ldb objectguid module
32 * Description: add a unique objectGUID onto every new record
38 #include "ldb/include/ldb_includes.h"
39 #include "librpc/gen_ndr/ndr_misc.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;
106 /* add_record: add objectGUID attribute */
107 static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
109 struct ldb_request *down_req;
110 struct ldb_message_element *attribute;
111 struct ldb_message *msg;
117 time_t t = time(NULL);
119 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
121 /* do not manipulate our control entries */
122 if (ldb_dn_is_special(req->op.add.message->dn)) {
123 return ldb_next_request(module, req);
126 if ((attribute = objectguid_find_attribute(req->op.add.message, "objectGUID")) != NULL ) {
127 return ldb_next_request(module, req);
130 down_req = talloc(req, struct ldb_request);
131 if (down_req == NULL) {
132 return LDB_ERR_OPERATIONS_ERROR;
137 /* we have to copy the message as the caller might have it as a const */
138 down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
140 talloc_free(down_req);
141 return LDB_ERR_OPERATIONS_ERROR;
145 guid = GUID_random();
147 nt_status = ndr_push_struct_blob(&v, msg, &guid,
148 (ndr_push_flags_fn_t)ndr_push_GUID);
149 if (!NT_STATUS_IS_OK(nt_status)) {
150 talloc_free(down_req);
151 return LDB_ERR_OPERATIONS_ERROR;
154 ret = ldb_msg_add_value(msg, "objectGUID", &v, NULL);
156 talloc_free(down_req);
160 if (add_time_element(msg, "whenCreated", t) != 0 ||
161 add_time_element(msg, "whenChanged", t) != 0) {
162 talloc_free(down_req);
163 return LDB_ERR_OPERATIONS_ERROR;
166 /* Get a sequence number from the backend */
167 ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
168 if (ret == LDB_SUCCESS) {
169 if (add_uint64_element(msg, "uSNCreated", seq_num) != 0 ||
170 add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
171 talloc_free(down_req);
172 return LDB_ERR_OPERATIONS_ERROR;
176 ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
178 /* go on with the call chain */
179 ret = ldb_next_request(module, down_req);
181 /* do not free down_req as the call results may be linked to it,
182 * it will be freed when the upper level request get freed */
183 if (ret == LDB_SUCCESS) {
184 req->handle = down_req->handle;
190 /* modify_record: update timestamps */
191 static int objectguid_modify(struct ldb_module *module, struct ldb_request *req)
193 struct ldb_request *down_req;
194 struct ldb_message *msg;
196 time_t t = time(NULL);
199 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
201 /* do not manipulate our control entries */
202 if (ldb_dn_is_special(req->op.add.message->dn)) {
203 return ldb_next_request(module, req);
206 down_req = talloc(req, struct ldb_request);
207 if (down_req == NULL) {
208 return LDB_ERR_OPERATIONS_ERROR;
213 /* we have to copy the message as the caller might have it as a const */
214 down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
216 talloc_free(down_req);
217 return LDB_ERR_OPERATIONS_ERROR;
220 if (add_time_element(msg, "whenChanged", t) != 0) {
221 talloc_free(down_req);
222 return LDB_ERR_OPERATIONS_ERROR;
225 /* Get a sequence number from the backend */
226 ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
227 if (ret == LDB_SUCCESS) {
228 if (add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
229 talloc_free(down_req);
230 return LDB_ERR_OPERATIONS_ERROR;
234 ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
236 /* go on with the call chain */
237 ret = ldb_next_request(module, down_req);
239 /* do not free down_req as the call results may be linked to it,
240 * it will be freed when the upper level request get freed */
241 if (ret == LDB_SUCCESS) {
242 req->handle = down_req->handle;
248 static const struct ldb_module_ops objectguid_ops = {
249 .name = "objectguid",
250 .add = objectguid_add,
251 .modify = objectguid_modify,
255 int objectguid_module_init(void)
257 return ldb_register_module(&objectguid_ops);