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
,