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