09679435f5160b2f262479ae82fc2a500e3c0ab8
[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_close(struct ldb_module *module)
45 {
46         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_close\n");
47         return ldb_next_close(module);
48 }
49
50 static int timestamps_search(struct ldb_module *module, const char *base,
51                                   enum ldb_scope scope, const char *expression,
52                                   const char * const *attrs, struct ldb_message ***res)
53 {
54         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_search\n");
55         return ldb_next_search(module, base, scope, expression, attrs, res);
56 }
57
58 static int timestamps_search_free(struct ldb_module *module, struct ldb_message **res)
59 {
60         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_search_free\n");
61         return ldb_next_search_free(module, res);
62 }
63
64 static int add_time_element(struct ldb_module *module, struct ldb_message *msg, 
65                             const char *attr_name, const char *time_string, unsigned int flags)
66 {
67         struct ldb_val *values;
68         char *name, *timestr;
69         int i;
70
71         for (i = 0; i < msg->num_elements; i++) {
72                 if (strcasecmp(msg->elements[i].name, attr_name) == 0) {
73                         return 0;
74                 }
75         }
76
77         msg->elements = talloc_realloc_p(msg, msg->elements, 
78                                          struct ldb_message_element, msg->num_elements + 1);
79         name = talloc_strdup(msg->elements, attr_name);
80         timestr = talloc_strdup(msg->elements, time_string);
81         values = talloc_p(msg->elements, struct ldb_val);
82         if (!msg->elements || !name || !timestr || !values) {
83                 return -1;
84         }
85
86         msg->elements[msg->num_elements].name = name;
87         msg->elements[msg->num_elements].flags = flags;
88         msg->elements[msg->num_elements].num_values = 1;
89         msg->elements[msg->num_elements].values = values;
90         msg->elements[msg->num_elements].values[0].data = timestr;
91         msg->elements[msg->num_elements].values[0].length = strlen(timestr);
92
93         msg->num_elements += 1;
94
95         return 0;
96 }
97
98 /* add_record: add crateTimestamp/modifyTimestamp attributes */
99 static int timestamps_add_record(struct ldb_module *module, const struct ldb_message *msg)
100 {
101         struct ldb_message *msg2 = NULL;
102         struct tm *tm;
103         char *timestr;
104         time_t timeval;
105         int ret, i;
106
107         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_add_record\n");
108
109         if (msg->dn[0] != '@') { /* do not manipulate our control entries */
110                 timeval = time(NULL);
111                 tm = gmtime(&timeval);
112                 if (!tm) {
113                         return -1;
114                 }
115
116                 msg2 = talloc_p(module, struct ldb_message);
117                 if (!msg2) {
118                         return -1;
119                 }
120
121                 /* formatted like: 20040408072012.0Z */
122                 timestr = talloc_asprintf(msg2, "%04u%02u%02u%02u%02u%02u.0Z",
123                                           tm->tm_year+1900, tm->tm_mon+1,
124                                           tm->tm_mday, tm->tm_hour, tm->tm_min,
125                                           tm->tm_sec);
126                 if (!timestr) {
127                         return -1;
128                 }
129
130                 msg2->dn = msg->dn;
131                 msg2->num_elements = msg->num_elements;
132                 msg2->private_data = msg->private_data;
133                 msg2->elements = talloc_array_p(msg2, struct ldb_message_element, msg2->num_elements);
134                 for (i = 0; i < msg2->num_elements; i++) {
135                         msg2->elements[i] = msg->elements[i];
136                 }
137
138                 add_time_element(module, msg2, "createTimestamp", timestr, LDB_FLAG_MOD_ADD);
139                 add_time_element(module, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_ADD);
140                 add_time_element(module, msg2, "whenCreated", timestr, LDB_FLAG_MOD_ADD);
141                 add_time_element(module, msg2, "whenChanged", timestr, LDB_FLAG_MOD_ADD);
142         }
143
144         if (msg2) {
145                 ret = ldb_next_add_record(module, msg2);
146                 talloc_free(msg2);
147         } else {
148                 ret = ldb_next_add_record(module, msg);
149         }
150
151         return ret;
152 }
153
154 /* modify_record: change modifyTimestamp as well */
155 static int timestamps_modify_record(struct ldb_module *module, const struct ldb_message *msg)
156 {
157         struct ldb_message *msg2 = NULL;
158         struct tm *tm;
159         char *timestr;
160         time_t timeval;
161         int ret, i;
162
163         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_modify_record\n");
164
165         if (msg->dn[0] != '@') { /* do not manipulate our control entries */
166                 timeval = time(NULL);
167                 tm = gmtime(&timeval);
168                 if (!tm) {
169                         return -1;
170                 }
171
172                 msg2 = talloc_p(module, struct ldb_message);
173                 if (!msg2) {
174                         return -1;
175                 }
176
177                 /* formatted like: 20040408072012.0Z */
178                 timestr = talloc_asprintf(msg2, 
179                                         "%04u%02u%02u%02u%02u%02u.0Z",
180                                         tm->tm_year+1900, tm->tm_mon+1,
181                                         tm->tm_mday, tm->tm_hour, tm->tm_min,
182                                         tm->tm_sec);
183                 if (!timestr) {
184                         return -1;
185                 }
186
187                 msg2->dn = msg->dn;
188                 msg2->num_elements = msg->num_elements;
189                 msg2->private_data = msg->private_data;
190                 msg2->elements = talloc_array_p(msg2, struct ldb_message_element, msg2->num_elements);
191                 for (i = 0; i < msg2->num_elements; i++) {
192                         msg2->elements[i] = msg->elements[i];
193                 }
194
195                 add_time_element(module, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_REPLACE);
196                 add_time_element(module, msg2, "whenChanged", timestr, LDB_FLAG_MOD_REPLACE);
197         }
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 const struct ldb_module_ops timestamps_ops = {
251         "timestamps",
252         timestamps_close, 
253         timestamps_search,
254         timestamps_search_free,
255         timestamps_add_record,
256         timestamps_modify_record,
257         timestamps_delete_record,
258         timestamps_rename_record,
259         timestamps_lock,
260         timestamps_unlock,
261         timestamps_errstring
262 };
263
264
265 /* the init function */
266 #ifdef HAVE_DLOPEN_DISABLED
267  struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
268 #else
269 struct ldb_module *timestamps_module_init(struct ldb_context *ldb, const char *options[])
270 #endif
271 {
272         struct ldb_module *ctx;
273         struct private_data *data;
274
275         ctx = talloc_p(ldb, struct ldb_module);
276         if (!ctx)
277                 return NULL;
278
279         data = talloc_p(ctx, struct private_data);
280         if (!data) {
281                 talloc_free(ctx);
282                 return NULL;
283         }
284
285         data->error_string = NULL;
286         ctx->private_data = data;
287         ctx->ldb = ldb;
288         ctx->prev = ctx->next = NULL;
289         ctx->ops = &timestamps_ops;
290
291         return ctx;
292 }