Line data Source code
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 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : /*
23 : * Name: ldb
24 : *
25 : * Component: ldb objectguid module
26 : *
27 : * Description: add a unique objectGUID onto every new record
28 : *
29 : * Author: Simo Sorce
30 : */
31 :
32 : #include "includes.h"
33 : #include "ldb_module.h"
34 : #include "dsdb/samdb/samdb.h"
35 : #include "dsdb/samdb/ldb_modules/util.h"
36 : #include "librpc/gen_ndr/ndr_misc.h"
37 : #include "param/param.h"
38 :
39 : /*
40 : add a time element to a record
41 : */
42 5885 : static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
43 : {
44 : struct ldb_message_element *el;
45 : char *s;
46 : int ret;
47 :
48 5885 : if (ldb_msg_find_element(msg, attr) != NULL) {
49 0 : return LDB_SUCCESS;
50 : }
51 :
52 5885 : s = ldb_timestring(msg, t);
53 5885 : if (s == NULL) {
54 0 : return LDB_ERR_OPERATIONS_ERROR;
55 : }
56 :
57 5885 : ret = ldb_msg_add_string(msg, attr, s);
58 5885 : if (ret != LDB_SUCCESS) {
59 0 : return ret;
60 : }
61 :
62 5885 : el = ldb_msg_find_element(msg, attr);
63 : /* always set as replace. This works because on add ops, the flag
64 : is ignored */
65 5885 : el->flags = LDB_FLAG_MOD_REPLACE;
66 :
67 5885 : return LDB_SUCCESS;
68 : }
69 :
70 : /*
71 : add a uint64_t element to a record
72 : */
73 5885 : static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
74 : const char *attr, uint64_t v)
75 : {
76 : struct ldb_message_element *el;
77 : int ret;
78 :
79 5885 : if (ldb_msg_find_element(msg, attr) != NULL) {
80 0 : return LDB_SUCCESS;
81 : }
82 :
83 5885 : ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
84 5885 : if (ret != LDB_SUCCESS) {
85 0 : return ret;
86 : }
87 :
88 5885 : el = ldb_msg_find_element(msg, attr);
89 : /* always set as replace. This works because on add ops, the flag
90 : is ignored */
91 5885 : el->flags = LDB_FLAG_MOD_REPLACE;
92 :
93 5885 : return LDB_SUCCESS;
94 : }
95 :
96 : struct og_context {
97 : struct ldb_module *module;
98 : struct ldb_request *req;
99 : };
100 :
101 : /* add_record: add objectGUID and timestamp attributes */
102 2297 : static int objectguid_add(struct ldb_module *module, struct ldb_request *req)
103 : {
104 : struct ldb_context *ldb;
105 : struct ldb_request *down_req;
106 : struct ldb_message *msg;
107 : struct ldb_message_element *el;
108 : struct GUID guid;
109 : uint64_t seq_num;
110 : int ret;
111 2297 : time_t t = time(NULL);
112 : struct og_context *ac;
113 :
114 2297 : ldb = ldb_module_get_ctx(module);
115 :
116 2297 : ldb_debug(ldb, LDB_DEBUG_TRACE, "objectguid_add_record\n");
117 :
118 : /* do not manipulate our control entries */
119 2297 : if (ldb_dn_is_special(req->op.add.message->dn)) {
120 0 : return ldb_next_request(module, req);
121 : }
122 :
123 2297 : el = ldb_msg_find_element(req->op.add.message, "objectGUID");
124 2297 : if (el != NULL) {
125 0 : ldb_set_errstring(ldb,
126 : "objectguid: objectGUID must not be specified!");
127 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
128 : }
129 :
130 2297 : ac = talloc(req, struct og_context);
131 2297 : if (ac == NULL) {
132 0 : return ldb_oom(ldb);
133 : }
134 2297 : ac->module = module;
135 2297 : ac->req = req;
136 :
137 : /* we have to copy the message as the caller might have it as a const */
138 2297 : msg = ldb_msg_copy_shallow(ac, req->op.add.message);
139 2297 : if (msg == NULL) {
140 0 : talloc_free(ac);
141 0 : return ldb_operr(ldb);
142 : }
143 :
144 : /* a new GUID */
145 2297 : guid = GUID_random();
146 :
147 2297 : ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
148 2297 : if (ret != LDB_SUCCESS) {
149 0 : return ret;
150 : }
151 :
152 4594 : if (add_time_element(msg, "whenCreated", t) != LDB_SUCCESS ||
153 2297 : add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
154 0 : return ldb_operr(ldb);
155 : }
156 :
157 : /* Get a sequence number from the backend */
158 2297 : ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
159 2297 : if (ret == LDB_SUCCESS) {
160 2297 : if (add_uint64_element(ldb, msg, "uSNCreated",
161 2297 : seq_num) != LDB_SUCCESS ||
162 2297 : add_uint64_element(ldb, msg, "uSNChanged",
163 : seq_num) != LDB_SUCCESS) {
164 0 : return ldb_operr(ldb);
165 : }
166 : }
167 :
168 2297 : ret = ldb_build_add_req(&down_req, ldb, ac,
169 : msg,
170 : req->controls,
171 : req, dsdb_next_callback,
172 : req);
173 2297 : LDB_REQ_SET_LOCATION(down_req);
174 2297 : if (ret != LDB_SUCCESS) {
175 0 : return ret;
176 : }
177 :
178 : /* go on with the call chain */
179 2297 : return ldb_next_request(module, down_req);
180 : }
181 :
182 : /* modify_record: update timestamps */
183 1298 : static int objectguid_modify(struct ldb_module *module, struct ldb_request *req)
184 : {
185 : struct ldb_context *ldb;
186 : struct ldb_request *down_req;
187 : struct ldb_message *msg;
188 : struct ldb_message_element *el;
189 : int ret;
190 1298 : time_t t = time(NULL);
191 : uint64_t seq_num;
192 : struct og_context *ac;
193 :
194 1298 : ldb = ldb_module_get_ctx(module);
195 :
196 1298 : ldb_debug(ldb, LDB_DEBUG_TRACE, "objectguid_modify_record\n");
197 :
198 : /* do not manipulate our control entries */
199 1298 : if (ldb_dn_is_special(req->op.mod.message->dn)) {
200 7 : return ldb_next_request(module, req);
201 : }
202 :
203 1291 : el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
204 1291 : if (el != NULL) {
205 0 : ldb_set_errstring(ldb,
206 : "objectguid: objectGUID must not be specified!");
207 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
208 : }
209 :
210 1291 : ac = talloc(req, struct og_context);
211 1291 : if (ac == NULL) {
212 0 : return ldb_oom(ldb);
213 : }
214 1291 : ac->module = module;
215 1291 : ac->req = req;
216 :
217 : /* we have to copy the message as the caller might have it as a const */
218 1291 : msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
219 1291 : if (msg == NULL) {
220 0 : return ldb_operr(ldb);
221 : }
222 :
223 1291 : if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
224 0 : return ldb_operr(ldb);
225 : }
226 :
227 : /* Get a sequence number from the backend */
228 1291 : ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
229 1291 : if (ret == LDB_SUCCESS) {
230 1291 : if (add_uint64_element(ldb, msg, "uSNChanged",
231 : seq_num) != LDB_SUCCESS) {
232 0 : return ldb_operr(ldb);
233 : }
234 : }
235 :
236 1291 : ret = ldb_build_mod_req(&down_req, ldb, ac,
237 : msg,
238 : req->controls,
239 : req, dsdb_next_callback,
240 : req);
241 1291 : LDB_REQ_SET_LOCATION(down_req);
242 1291 : if (ret != LDB_SUCCESS) {
243 0 : return ret;
244 : }
245 :
246 : /* go on with the call chain */
247 1291 : return ldb_next_request(module, down_req);
248 : }
249 :
250 : static const struct ldb_module_ops ldb_objectguid_module_ops = {
251 : .name = "objectguid",
252 : .add = objectguid_add,
253 : .modify = objectguid_modify
254 : };
255 :
256 5536 : int ldb_objectguid_module_init(const char *version)
257 : {
258 5536 : LDB_MODULE_CHECK_VERSION(version);
259 5536 : return ldb_register_module(&ldb_objectguid_module_ops);
260 : }
|