r7527: - added a ldb_search_bytree() interface, which takes a ldb_parse_tree
[kamenim/samba.git] / source4 / lib / ldb / modules / timestamps.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb timestamps module
29  *
30  *  Description: add object timestamping functionality
31  *
32  *  Author: Simo Sorce
33  */
34
35 #include "includes.h"
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
38 #include <time.h>
39
40 struct private_data {
41         const char *error_string;
42 };
43
44 static int timestamps_search(struct ldb_module *module, const char *base,
45                                   enum ldb_scope scope, const char *expression,
46                                   const char * const *attrs, struct ldb_message ***res)
47 {
48         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_search\n");
49         return ldb_next_search(module, base, scope, expression, attrs, res);
50 }
51
52 static int timestamps_search_bytree(struct ldb_module *module, const char *base,
53                                     enum ldb_scope scope, struct ldb_parse_tree *tree,
54                                     const char * const *attrs, struct ldb_message ***res)
55 {
56         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_search\n");
57         return ldb_next_search_bytree(module, base, scope, tree, attrs, res);
58 }
59
60 static int add_time_element(struct ldb_module *module, struct ldb_message *msg, 
61                             const char *attr_name, const char *time_string, unsigned int flags)
62 {
63         struct ldb_val *values;
64         char *name, *timestr;
65         int i;
66
67         for (i = 0; i < msg->num_elements; i++) {
68                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
69                         return 0;
70                 }
71         }
72
73         msg->elements = talloc_realloc(msg, msg->elements, 
74                                          struct ldb_message_element, msg->num_elements + 1);
75         name = talloc_strdup(msg->elements, attr_name);
76         timestr = talloc_strdup(msg->elements, time_string);
77         values = talloc(msg->elements, struct ldb_val);
78         if (!msg->elements || !name || !timestr || !values) {
79                 return -1;
80         }
81
82         msg->elements[msg->num_elements].name = name;
83         msg->elements[msg->num_elements].flags = flags;
84         msg->elements[msg->num_elements].num_values = 1;
85         msg->elements[msg->num_elements].values = values;
86         msg->elements[msg->num_elements].values[0].data = timestr;
87         msg->elements[msg->num_elements].values[0].length = strlen(timestr);
88
89         msg->num_elements += 1;
90
91         return 0;
92 }
93
94 /* add_record: add crateTimestamp/modifyTimestamp attributes */
95 static int timestamps_add_record(struct ldb_module *module, const struct ldb_message *msg)
96 {
97         struct ldb_message *msg2 = NULL;
98         struct tm *tm;
99         char *timestr;
100         time_t timeval;
101         int ret, i;
102
103         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_add_record\n");
104
105         if (msg->dn[0] == '@') { /* do not manipulate our control entries */
106                 return ldb_next_add_record(module, msg);
107         }
108
109         timeval = time(NULL);
110         tm = gmtime(&timeval);
111         if (!tm) {
112                 return -1;
113         }
114
115         msg2 = talloc(module, struct ldb_message);
116         if (!msg2) {
117                 return -1;
118         }
119
120         /* formatted like: 20040408072012.0Z */
121         timestr = talloc_asprintf(msg2, "%04u%02u%02u%02u%02u%02u.0Z",
122                                   tm->tm_year+1900, tm->tm_mon+1,
123                                   tm->tm_mday, tm->tm_hour, tm->tm_min,
124                                   tm->tm_sec);
125         if (!timestr) {
126                 return -1;
127         }
128
129         msg2->dn = msg->dn;
130         msg2->num_elements = msg->num_elements;
131         msg2->private_data = msg->private_data;
132         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
133         for (i = 0; i < msg2->num_elements; i++) {
134                 msg2->elements[i] = msg->elements[i];
135         }
136
137         add_time_element(module, msg2, "createTimestamp", timestr, LDB_FLAG_MOD_ADD);
138         add_time_element(module, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_ADD);
139         add_time_element(module, msg2, "whenCreated", timestr, LDB_FLAG_MOD_ADD);
140         add_time_element(module, msg2, "whenChanged", timestr, LDB_FLAG_MOD_ADD);
141
142         if (msg2) {
143                 ret = ldb_next_add_record(module, msg2);
144                 talloc_free(msg2);
145         } else {
146                 ret = ldb_next_add_record(module, msg);
147         }
148
149         return ret;
150 }
151
152 /* modify_record: change modifyTimestamp as well */
153 static int timestamps_modify_record(struct ldb_module *module, const struct ldb_message *msg)
154 {
155         struct ldb_message *msg2 = NULL;
156         struct tm *tm;
157         char *timestr;
158         time_t timeval;
159         int ret, i;
160
161         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_modify_record\n");
162
163         if (msg->dn[0] == '@') { /* do not manipulate our control entries */
164                 return ldb_next_modify_record(module, msg);
165         }
166
167         timeval = time(NULL);
168         tm = gmtime(&timeval);
169         if (!tm) {
170                 return -1;
171         }
172
173         msg2 = talloc(module, struct ldb_message);
174         if (!msg2) {
175                 return -1;
176         }
177
178         /* formatted like: 20040408072012.0Z */
179         timestr = talloc_asprintf(msg2, 
180                                 "%04u%02u%02u%02u%02u%02u.0Z",
181                                 tm->tm_year+1900, tm->tm_mon+1,
182                                 tm->tm_mday, tm->tm_hour, tm->tm_min,
183                                 tm->tm_sec);
184         if (!timestr) {
185                 return -1;
186         }
187
188         msg2->dn = msg->dn;
189         msg2->num_elements = msg->num_elements;
190         msg2->private_data = msg->private_data;
191         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
192         for (i = 0; i < msg2->num_elements; i++) {
193                 msg2->elements[i] = msg->elements[i];
194         }
195
196         add_time_element(module, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_REPLACE);
197         add_time_element(module, msg2, "whenChanged", timestr, LDB_FLAG_MOD_REPLACE);
198
199         if (msg2) {
200                 ret = ldb_next_modify_record(module, msg2);
201                 talloc_free(msg2);
202         } else {
203                 ret = ldb_next_modify_record(module, msg);
204         }
205
206         return ret;
207 }
208
209 static int timestamps_delete_record(struct ldb_module *module, const char *dn)
210 {
211         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_delete_record\n");
212         return ldb_next_delete_record(module, dn);
213 }
214
215 static int timestamps_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
216 {
217         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_rename_record\n");
218         return ldb_next_rename_record(module, olddn, newdn);
219 }
220
221 static int timestamps_lock(struct ldb_module *module, const char *lockname)
222 {
223         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_lock\n");
224         return ldb_next_named_lock(module, lockname);
225 }
226
227 static int timestamps_unlock(struct ldb_module *module, const char *lockname)
228 {
229         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_unlock\n");
230         return ldb_next_named_unlock(module, lockname);
231 }
232
233 /* return extended error information */
234 static const char *timestamps_errstring(struct ldb_module *module)
235 {
236         struct private_data *data = (struct private_data *)module->private_data;
237
238         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_errstring\n");
239         if (data->error_string) {
240                 const char *error;
241
242                 error = data->error_string;
243                 data->error_string = NULL;
244                 return error;
245         }
246
247         return ldb_next_errstring(module);
248 }
249
250 static int timestamps_destructor(void *module_ctx)
251 {
252         /* struct ldb_module *ctx = module_ctx; */
253         /* put your clean-up functions here */
254         return 0;
255 }
256
257 static const struct ldb_module_ops timestamps_ops = {
258         .name          = "timestamps",
259         .search        = timestamps_search,
260         .search_bytree = timestamps_search_bytree,
261         .add_record    = timestamps_add_record,
262         .modify_record = timestamps_modify_record,
263         .delete_record = timestamps_delete_record,
264         .rename_record = timestamps_rename_record,
265         .named_lock    = timestamps_lock,
266         .named_unlock  = timestamps_unlock,
267         .errstring     = timestamps_errstring
268 };
269
270
271 /* the init function */
272 #ifdef HAVE_DLOPEN_DISABLED
273  struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
274 #else
275 struct ldb_module *timestamps_module_init(struct ldb_context *ldb, const char *options[])
276 #endif
277 {
278         struct ldb_module *ctx;
279         struct private_data *data;
280
281         ctx = talloc(ldb, struct ldb_module);
282         if (!ctx)
283                 return NULL;
284
285         data = talloc(ctx, struct private_data);
286         if (!data) {
287                 talloc_free(ctx);
288                 return NULL;
289         }
290
291         data->error_string = NULL;
292         ctx->private_data = data;
293         ctx->ldb = ldb;
294         ctx->prev = ctx->next = NULL;
295         ctx->ops = &timestamps_ops;
296
297         talloc_set_destructor (ctx, timestamps_destructor);
298
299         return ctx;
300 }