dc91937f857bb644b4db5d7be364a15436f051fc
[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_search(struct ldb_module *module, const struct ldb_dn *base,
41                                   enum ldb_scope scope, const char *expression,
42                                   const char * const *attrs, struct ldb_message ***res)
43 {
44         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_search\n");
45         return ldb_next_search(module, base, scope, expression, attrs, res);
46 }
47
48 static int timestamps_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
49                                     enum ldb_scope scope, struct ldb_parse_tree *tree,
50                                     const char * const *attrs, struct ldb_message ***res)
51 {
52         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_search\n");
53         return ldb_next_search_bytree(module, base, scope, tree, attrs, res);
54 }
55
56 static int add_time_element(struct ldb_module *module, struct ldb_message *msg, 
57                             const char *attr_name, const char *time_string, unsigned int flags)
58 {
59         struct ldb_message_element *attribute = NULL;
60
61         int i;
62
63         for (i = 0; i < msg->num_elements; i++) {
64                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
65                         return 0;
66                 }
67         }
68
69         if (ldb_msg_add_string(module->ldb, msg, attr_name, time_string) != 0) {
70                 return -1;
71         }
72
73         for (i = 0; i < msg->num_elements; i++) {
74                 if (ldb_attr_cmp(attr_name, msg->elements[i].name) == 0) {
75                         attribute = &msg->elements[i];
76                         break;
77                 }
78         }
79
80         if (!attribute) {
81                 return -1;
82         }
83
84         attribute->flags = flags;
85
86         return 0;
87 }
88
89 /* add_record: add crateTimestamp/modifyTimestamp attributes */
90 static int timestamps_add_record(struct ldb_module *module, const struct ldb_message *msg)
91 {
92         struct ldb_message *msg2 = NULL;
93         struct tm *tm;
94         char *timestr;
95         time_t timeval;
96         int ret, i;
97
98         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_add_record\n");
99
100         /* do not manipulate our control entries */
101         if (ldb_dn_is_special(msg->dn)) {
102                 return ldb_next_add_record(module, msg);
103         }
104
105         timeval = time(NULL);
106         tm = gmtime(&timeval);
107         if (!tm) {
108                 return -1;
109         }
110
111         msg2 = talloc(module, struct ldb_message);
112         if (!msg2) {
113                 return -1;
114         }
115
116         /* formatted like: 20040408072012.0Z */
117         timestr = talloc_asprintf(msg2, "%04u%02u%02u%02u%02u%02u.0Z",
118                                   tm->tm_year+1900, tm->tm_mon+1,
119                                   tm->tm_mday, tm->tm_hour, tm->tm_min,
120                                   tm->tm_sec);
121         if (!timestr) {
122                 return -1;
123         }
124
125         msg2->dn = msg->dn;
126         msg2->num_elements = msg->num_elements;
127         msg2->private_data = msg->private_data;
128         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
129         for (i = 0; i < msg2->num_elements; i++) {
130                 msg2->elements[i] = msg->elements[i];
131         }
132
133         add_time_element(module, msg2, "createTimestamp", timestr, LDB_FLAG_MOD_ADD);
134         add_time_element(module, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_ADD);
135         add_time_element(module, msg2, "whenCreated", timestr, LDB_FLAG_MOD_ADD);
136         add_time_element(module, msg2, "whenChanged", timestr, LDB_FLAG_MOD_ADD);
137
138         if (msg2) {
139                 ret = ldb_next_add_record(module, msg2);
140                 talloc_free(msg2);
141         } else {
142                 ret = ldb_next_add_record(module, msg);
143         }
144
145         return ret;
146 }
147
148 /* modify_record: change modifyTimestamp as well */
149 static int timestamps_modify_record(struct ldb_module *module, const struct ldb_message *msg)
150 {
151         struct ldb_message *msg2 = NULL;
152         struct tm *tm;
153         char *timestr;
154         time_t timeval;
155         int ret, i;
156
157         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_modify_record\n");
158
159         /* do not manipulate our control entries */
160         if (ldb_dn_is_special(msg->dn)) {
161                 return ldb_next_modify_record(module, msg);
162         }
163
164         timeval = time(NULL);
165         tm = gmtime(&timeval);
166         if (!tm) {
167                 return -1;
168         }
169
170         msg2 = talloc(module, struct ldb_message);
171         if (!msg2) {
172                 return -1;
173         }
174
175         /* formatted like: 20040408072012.0Z */
176         timestr = talloc_asprintf(msg2, 
177                                 "%04u%02u%02u%02u%02u%02u.0Z",
178                                 tm->tm_year+1900, tm->tm_mon+1,
179                                 tm->tm_mday, tm->tm_hour, tm->tm_min,
180                                 tm->tm_sec);
181         if (!timestr) {
182                 return -1;
183         }
184
185         msg2->dn = msg->dn;
186         msg2->num_elements = msg->num_elements;
187         msg2->private_data = msg->private_data;
188         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
189         for (i = 0; i < msg2->num_elements; i++) {
190                 msg2->elements[i] = msg->elements[i];
191         }
192
193         add_time_element(module, msg2, "modifyTimestamp", timestr, LDB_FLAG_MOD_REPLACE);
194         add_time_element(module, msg2, "whenChanged", timestr, LDB_FLAG_MOD_REPLACE);
195
196         ret = ldb_next_modify_record(module, msg2);
197         talloc_free(msg2);
198
199         return ret;
200 }
201
202 static int timestamps_delete_record(struct ldb_module *module, const struct ldb_dn *dn)
203 {
204         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_delete_record\n");
205         return ldb_next_delete_record(module, dn);
206 }
207
208 static int timestamps_rename_record(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
209 {
210         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_rename_record\n");
211         return ldb_next_rename_record(module, olddn, newdn);
212 }
213
214 static int timestamps_start_trans(struct ldb_module *module)
215 {
216         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_start_trans\n");
217         return ldb_next_start_trans(module);
218 }
219
220 static int timestamps_end_trans(struct ldb_module *module, int status)
221 {
222         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "timestamps_end_trans\n");
223         return ldb_next_end_trans(module, status);
224 }
225
226 static int timestamps_destructor(void *module_ctx)
227 {
228         /* struct ldb_module *ctx = module_ctx; */
229         /* put your clean-up functions here */
230         return 0;
231 }
232
233 static const struct ldb_module_ops timestamps_ops = {
234         .name              = "timestamps",
235         .search            = timestamps_search,
236         .search_bytree     = timestamps_search_bytree,
237         .add_record        = timestamps_add_record,
238         .modify_record     = timestamps_modify_record,
239         .delete_record     = timestamps_delete_record,
240         .rename_record     = timestamps_rename_record,
241         .start_transaction = timestamps_start_trans,
242         .end_transaction   = timestamps_end_trans
243 };
244
245
246 /* the init function */
247 #ifdef HAVE_DLOPEN_DISABLED
248  struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
249 #else
250 struct ldb_module *timestamps_module_init(struct ldb_context *ldb, const char *options[])
251 #endif
252 {
253         struct ldb_module *ctx;
254
255         ctx = talloc(ldb, struct ldb_module);
256         if (!ctx)
257                 return NULL;
258
259         ctx->private_data = NULL;
260         ctx->ldb = ldb;
261         ctx->prev = ctx->next = NULL;
262         ctx->ops = &timestamps_ops;
263
264         talloc_set_destructor (ctx, timestamps_destructor);
265
266         return ctx;
267 }