r5585: LDB interfaces change:
[kai/samba-autobuild/.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_free(struct ldb_module *module, struct ldb_message **res)
53 {
54         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_search_free\n");
55         return ldb_next_search_free(module, res);
56 }
57
58 static int add_time_element(struct ldb_module *module, struct ldb_message *msg, 
59                             const char *attr_name, const char *time_string, unsigned int flags)
60 {
61         struct ldb_val *values;
62         char *name, *timestr;
63         int i;
64
65         for (i = 0; i < msg->num_elements; i++) {
66                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
67                         return 0;
68                 }
69         }
70
71         msg->elements = talloc_realloc(msg, msg->elements, 
72                                          struct ldb_message_element, msg->num_elements + 1);
73         name = talloc_strdup(msg->elements, attr_name);
74         timestr = talloc_strdup(msg->elements, time_string);
75         values = talloc(msg->elements, struct ldb_val);
76         if (!msg->elements || !name || !timestr || !values) {
77                 return -1;
78         }
79
80         msg->elements[msg->num_elements].name = name;
81         msg->elements[msg->num_elements].flags = flags;
82         msg->elements[msg->num_elements].num_values = 1;
83         msg->elements[msg->num_elements].values = values;
84         msg->elements[msg->num_elements].values[0].data = timestr;
85         msg->elements[msg->num_elements].values[0].length = strlen(timestr);
86
87         msg->num_elements += 1;
88
89         return 0;
90 }
91
92 /* add_record: add crateTimestamp/modifyTimestamp attributes */
93 static int timestamps_add_record(struct ldb_module *module, const struct ldb_message *msg)
94 {
95         struct ldb_message *msg2 = NULL;
96         struct tm *tm;
97         char *timestr;
98         time_t timeval;
99         int ret, i;
100
101         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_add_record\n");
102
103         if (msg->dn[0] == '@') { /* do not manipulate our control entries */
104                 return ldb_next_add_record(module, msg);
105         }
106
107         timeval = time(NULL);
108         tm = gmtime(&timeval);
109         if (!tm) {
110                 return -1;
111         }
112
113         msg2 = talloc(module, struct ldb_message);
114         if (!msg2) {
115                 return -1;
116         }
117
118         /* formatted like: 20040408072012.0Z */
119         timestr = talloc_asprintf(msg2, "%04u%02u%02u%02u%02u%02u.0Z",
120                                   tm->tm_year+1900, tm->tm_mon+1,
121                                   tm->tm_mday, tm->tm_hour, tm->tm_min,
122                                   tm->tm_sec);
123         if (!timestr) {
124                 return -1;
125         }
126
127         msg2->dn = msg->dn;
128         msg2->num_elements = msg->num_elements;
129         msg2->private_data = msg->private_data;
130         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
131         for (i = 0; i < msg2->num_elements; i++) {
132                 msg2->elements[i] = msg->elements[i];
133         }
134
135         add_time_element(module, msg2, "createTimestamp", timestr, LDB_FLAG_MOD_ADD);
136         add_time_element(module, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_ADD);
137         add_time_element(module, msg2, "whenCreated", timestr, LDB_FLAG_MOD_ADD);
138         add_time_element(module, msg2, "whenChanged", timestr, LDB_FLAG_MOD_ADD);
139
140         if (msg2) {
141                 ret = ldb_next_add_record(module, msg2);
142                 talloc_free(msg2);
143         } else {
144                 ret = ldb_next_add_record(module, msg);
145         }
146
147         return ret;
148 }
149
150 /* modify_record: change modifyTimestamp as well */
151 static int timestamps_modify_record(struct ldb_module *module, const struct ldb_message *msg)
152 {
153         struct ldb_message *msg2 = NULL;
154         struct tm *tm;
155         char *timestr;
156         time_t timeval;
157         int ret, i;
158
159         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_modify_record\n");
160
161         if (msg->dn[0] == '@') { /* do not manipulate our control entries */
162                 return ldb_next_modify_record(module, msg);
163         }
164
165         timeval = time(NULL);
166         tm = gmtime(&timeval);
167         if (!tm) {
168                 return -1;
169         }
170
171         msg2 = talloc(module, struct ldb_message);
172         if (!msg2) {
173                 return -1;
174         }
175
176         /* formatted like: 20040408072012.0Z */
177         timestr = talloc_asprintf(msg2, 
178                                 "%04u%02u%02u%02u%02u%02u.0Z",
179                                 tm->tm_year+1900, tm->tm_mon+1,
180                                 tm->tm_mday, tm->tm_hour, tm->tm_min,
181                                 tm->tm_sec);
182         if (!timestr) {
183                 return -1;
184         }
185
186         msg2->dn = msg->dn;
187         msg2->num_elements = msg->num_elements;
188         msg2->private_data = msg->private_data;
189         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
190         for (i = 0; i < msg2->num_elements; i++) {
191                 msg2->elements[i] = msg->elements[i];
192         }
193
194         add_time_element(module, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_REPLACE);
195         add_time_element(module, msg2, "whenChanged", timestr, LDB_FLAG_MOD_REPLACE);
196
197         if (msg2) {
198                 ret = ldb_next_modify_record(module, msg2);
199                 talloc_free(msg2);
200         } else {
201                 ret = ldb_next_modify_record(module, msg);
202         }
203
204         return ret;
205 }
206
207 static int timestamps_delete_record(struct ldb_module *module, const char *dn)
208 {
209         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_delete_record\n");
210         return ldb_next_delete_record(module, dn);
211 }
212
213 static int timestamps_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
214 {
215         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_rename_record\n");
216         return ldb_next_rename_record(module, olddn, newdn);
217 }
218
219 static int timestamps_lock(struct ldb_module *module, const char *lockname)
220 {
221         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_lock\n");
222         return ldb_next_named_lock(module, lockname);
223 }
224
225 static int timestamps_unlock(struct ldb_module *module, const char *lockname)
226 {
227         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_unlock\n");
228         return ldb_next_named_unlock(module, lockname);
229 }
230
231 /* return extended error information */
232 static const char *timestamps_errstring(struct ldb_module *module)
233 {
234         struct private_data *data = (struct private_data *)module->private_data;
235
236         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_errstring\n");
237         if (data->error_string) {
238                 const char *error;
239
240                 error = data->error_string;
241                 data->error_string = NULL;
242                 return error;
243         }
244
245         return ldb_next_errstring(module);
246 }
247
248 static int timestamps_destructor(void *module_ctx)
249 {
250         struct ldb_module *ctx = module_ctx;
251         /* put your clean-up functions here */
252         return 0;
253 }
254
255 static const struct ldb_module_ops timestamps_ops = {
256         "timestamps",
257         timestamps_search,
258         timestamps_search_free,
259         timestamps_add_record,
260         timestamps_modify_record,
261         timestamps_delete_record,
262         timestamps_rename_record,
263         timestamps_lock,
264         timestamps_unlock,
265         timestamps_errstring
266 };
267
268
269 /* the init function */
270 #ifdef HAVE_DLOPEN_DISABLED
271  struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
272 #else
273 struct ldb_module *timestamps_module_init(struct ldb_context *ldb, const char *options[])
274 #endif
275 {
276         struct ldb_module *ctx;
277         struct private_data *data;
278
279         ctx = talloc(ldb, struct ldb_module);
280         if (!ctx)
281                 return NULL;
282
283         data = talloc(ctx, struct private_data);
284         if (!data) {
285                 talloc_free(ctx);
286                 return NULL;
287         }
288
289         data->error_string = NULL;
290         ctx->private_data = data;
291         ctx->ldb = ldb;
292         ctx->prev = ctx->next = NULL;
293         ctx->ops = &timestamps_ops;
294
295         talloc_set_destructor (ctx, timestamps_destructor);
296
297         return ctx;
298 }