r4474: - converted ldb to use talloc internally
[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 static int timestamps_close(struct ldb_module *module)
41 {
42         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_close\n");
43         return ldb_next_close(module);
44 }
45
46 static int timestamps_search(struct ldb_module *module, const char *base,
47                                   enum ldb_scope scope, const char *expression,
48                                   const char * const *attrs, struct ldb_message ***res)
49 {
50         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_search\n");
51         return ldb_next_search(module, base, scope, expression, attrs, res);
52 }
53
54 static int timestamps_search_free(struct ldb_module *module, struct ldb_message **res)
55 {
56         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_search_free\n");
57         return ldb_next_search_free(module, res);
58 }
59
60 static int add_time_element(struct ldb_context *ldb, 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 (strcasecmp(msg->elements[i].name, attr_name) == 0) {
69                         return 0;
70                 }
71         }
72
73         msg->elements = talloc_realloc_p(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_p(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                 timeval = time(NULL);
107                 tm = gmtime(&timeval);
108                 if (!tm) {
109                         return -1;
110                 }
111
112                 msg2 = talloc_p(module, struct ldb_message);
113                 if (!msg2) {
114                         return -1;
115                 }
116
117                 /* formatted like: 20040408072012.0Z */
118                 timestr = talloc_asprintf(msg2, "%04u%02u%02u%02u%02u%02u.0Z",
119                                           tm->tm_year+1900, tm->tm_mon+1,
120                                           tm->tm_mday, tm->tm_hour, tm->tm_min,
121                                           tm->tm_sec);
122                 if (!timestr) {
123                         return -1;
124                 }
125
126                 msg2->dn = msg->dn;
127                 msg2->num_elements = msg->num_elements;
128                 msg2->private_data = msg->private_data;
129                 msg2->elements = talloc_array_p(msg2, struct ldb_message_element, msg2->num_elements);
130                 for (i = 0; i < msg2->num_elements; i++) {
131                         msg2->elements[i] = msg->elements[i];
132                 }
133
134                 add_time_element(module->ldb, msg2, "createTimestamp", timestr, LDB_FLAG_MOD_ADD);
135                 add_time_element(module->ldb, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_ADD);
136                 add_time_element(module->ldb, msg2, "whenCreated", timestr, LDB_FLAG_MOD_ADD);
137                 add_time_element(module->ldb, msg2, "whenChanged", timestr, LDB_FLAG_MOD_ADD);
138         }
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                 timeval = time(NULL);
163                 tm = gmtime(&timeval);
164                 if (!tm) {
165                         return -1;
166                 }
167
168                 msg2 = talloc_p(module, struct ldb_message);
169                 if (!msg2) {
170                         return -1;
171                 }
172
173                 /* formatted like: 20040408072012.0Z */
174                 timestr = talloc_asprintf(msg2, 
175                                         "%04u%02u%02u%02u%02u%02u.0Z",
176                                         tm->tm_year+1900, tm->tm_mon+1,
177                                         tm->tm_mday, tm->tm_hour, tm->tm_min,
178                                         tm->tm_sec);
179                 if (!timestr) {
180                         return -1;
181                 }
182
183                 msg2->dn = msg->dn;
184                 msg2->num_elements = msg->num_elements;
185                 msg2->private_data = msg->private_data;
186                 msg2->elements = talloc_array_p(msg2, struct ldb_message_element, msg2->num_elements);
187                 for (i = 0; i < msg2->num_elements; i++) {
188                         msg2->elements[i] = msg->elements[i];
189                 }
190
191                 add_time_element(module->ldb, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_REPLACE);
192                 add_time_element(module->ldb, msg2, "whenChanged", timestr, LDB_FLAG_MOD_REPLACE);
193         }
194
195         if (msg2) {
196                 ret = ldb_next_modify_record(module, msg2);
197                 talloc_free(msg2);
198         } else {
199                 ret = ldb_next_modify_record(module, msg);
200         }
201
202         return ret;
203 }
204
205 static int timestamps_delete_record(struct ldb_module *module, const char *dn)
206 {
207         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_delete_record\n");
208         return ldb_next_delete_record(module, dn);
209 }
210
211 static int timestamps_rename_record(struct ldb_module *module, const char *olddn, const char *newdn)
212 {
213         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_rename_record\n");
214         return ldb_next_rename_record(module, olddn, newdn);
215 }
216
217 static int timestamps_lock(struct ldb_module *module, const char *lockname)
218 {
219         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_lock\n");
220         return ldb_next_named_lock(module, lockname);
221 }
222
223 static int timestamps_unlock(struct ldb_module *module, const char *lockname)
224 {
225         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_unlock\n");
226         return ldb_next_named_unlock(module, lockname);
227 }
228
229 /* return extended error information */
230 static const char *timestamps_errstring(struct ldb_module *module)
231 {
232         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_errstring\n");
233         return ldb_next_errstring(module);
234 }
235
236 static const struct ldb_module_ops timestamps_ops = {
237         "timestamps",
238         timestamps_close, 
239         timestamps_search,
240         timestamps_search_free,
241         timestamps_add_record,
242         timestamps_modify_record,
243         timestamps_delete_record,
244         timestamps_rename_record,
245         timestamps_lock,
246         timestamps_unlock,
247         timestamps_errstring
248 };
249
250
251 /* the init function */
252 #ifdef HAVE_DLOPEN_DISABLED
253  struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
254 #else
255 struct ldb_module *timestamps_module_init(struct ldb_context *ldb, const char *options[])
256 #endif
257 {
258         struct ldb_module *ctx;
259
260         ctx = talloc_p(ldb, struct ldb_module);
261         if (!ctx)
262                 return NULL;
263
264         ctx->ldb = ldb;
265         ctx->prev = ctx->next = NULL;
266         ctx->private_data = NULL;
267         ctx->ops = &timestamps_ops;
268
269         return ctx;
270 }