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 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/include/ldb_includes.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;
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;
115 enum ndr_err_code ndr_err;
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 ndr_err = ndr_push_struct_blob(&v, msg,
148 lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
150 (ndr_push_flags_fn_t)ndr_push_GUID);
151 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
152 talloc_free(down_req);
153 return LDB_ERR_OPERATIONS_ERROR;
156 ret = ldb_msg_add_value(msg, "objectGUID", &v, NULL);
158 talloc_free(down_req);
162 if (add_time_element(msg, "whenCreated", t) != 0 ||
163 add_time_element(msg, "whenChanged", t) != 0) {
164 talloc_free(down_req);
165 return LDB_ERR_OPERATIONS_ERROR;
168 /* Get a sequence number from the backend */
169 ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
170 if (ret == LDB_SUCCESS) {
171 if (add_uint64_element(msg, "uSNCreated", seq_num) != 0 ||
172 add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
173 talloc_free(down_req);
174 return LDB_ERR_OPERATIONS_ERROR;
178 ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
180 /* go on with the call chain */
181 ret = ldb_next_request(module, down_req);
183 /* do not free down_req as the call results may be linked to it,
184 * it will be freed when the upper level request get freed */
185 if (ret == LDB_SUCCESS) {
186 req->handle = down_req->handle;
192 /* modify_record: update timestamps */
193 static int objectguid_modify(struct ldb_module *module, struct ldb_request *req)
195 struct ldb_request *down_req;
196 struct ldb_message *msg;
198 time_t t = time(NULL);
201 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
203 /* do not manipulate our control entries */
204 if (ldb_dn_is_special(req->op.add.message->dn)) {
205 return ldb_next_request(module, req);
208 down_req = talloc(req, struct ldb_request);
209 if (down_req == NULL) {
210 return LDB_ERR_OPERATIONS_ERROR;
215 /* we have to copy the message as the caller might have it as a const */
216 down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
218 talloc_free(down_req);
219 return LDB_ERR_OPERATIONS_ERROR;
222 if (add_time_element(msg, "whenChanged", t) != 0) {
223 talloc_free(down_req);
224 return LDB_ERR_OPERATIONS_ERROR;
227 /* Get a sequence number from the backend */
228 ret = ldb_sequence_number(module->ldb, LDB_SEQ_NEXT, &seq_num);
229 if (ret == LDB_SUCCESS) {
230 if (add_uint64_element(msg, "uSNChanged", seq_num) != 0) {
231 talloc_free(down_req);
232 return LDB_ERR_OPERATIONS_ERROR;
236 ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
238 /* go on with the call chain */
239 ret = ldb_next_request(module, down_req);
241 /* do not free down_req as the call results may be linked to it,
242 * it will be freed when the upper level request get freed */
243 if (ret == LDB_SUCCESS) {
244 req->handle = down_req->handle;
250 _PUBLIC_ const struct ldb_module_ops ldb_objectguid_module_ops = {
251 .name = "objectguid",
252 .add = objectguid_add,
253 .modify = objectguid_modify,