r10913: This patch isn't as big as it looks ...
[abartlet/samba.git/.git] / source4 / lib / ldb / modules / rdn_name.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 objectguid module
29  *
30  *  Description: add a unique objectGUID onto every new record
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 rdn_name_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
41                                   enum ldb_scope scope, struct ldb_parse_tree *tree,
42                                   const char * const *attrs, struct ldb_message ***res)
43 {
44         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_search\n");
45         return ldb_next_search_bytree(module, base, scope, tree, attrs, res);
46 }
47
48 static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name)
49 {
50         int i;
51
52         for (i = 0; i < msg->num_elements; i++) {
53                 if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
54                         return &msg->elements[i];
55                 }
56         }
57
58         return NULL;
59 }
60
61 /* add_record: add crateTimestamp/modifyTimestamp attributes */
62 static int rdn_name_add_record(struct ldb_module *module, const struct ldb_message *msg)
63 {
64         struct ldb_message *msg2;
65         struct ldb_message_element *attribute;
66         struct ldb_dn_component *rdn;
67         int i, ret;
68
69         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_add_record\n");
70
71         /* do not manipulate our control entries */
72         if (ldb_dn_is_special(msg->dn)) {
73                 return ldb_next_add_record(module, msg);
74         }
75
76         /* Perhaps someone above us knows better */
77         if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
78                 return ldb_next_add_record(module, msg);
79         }
80
81         msg2 = talloc(module, struct ldb_message);
82         if (!msg2) {
83                 return -1;
84         }
85
86         msg2->dn = msg->dn;
87         msg2->num_elements = msg->num_elements;
88         msg2->private_data = msg->private_data;
89         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
90         for (i = 0; i < msg2->num_elements; i++) {
91                 msg2->elements[i] = msg->elements[i];
92         }
93
94         rdn = ldb_dn_get_rdn(msg2, msg2->dn);
95         if (!rdn) {
96                 talloc_free(msg2);
97                 return -1;
98         }
99         
100         if (ldb_msg_add_value(msg2, "name", &rdn->value) != 0) {
101                 talloc_free(msg2);
102                 return -1;
103         }
104
105         attribute = rdn_name_find_attribute(msg2, rdn->name);
106
107         if (!attribute) {
108                 if (ldb_msg_add_value(msg2, rdn->name, &rdn->value) != 0) {
109                         talloc_free(msg2);
110                         return -1;
111                 }
112         } else {
113                 const struct ldb_attrib_handler *handler
114                         = ldb_attrib_handler(module->ldb, rdn->name);
115                 for (i=0; i < attribute->num_values; i++) {
116                         if (handler->comparison_fn(module->ldb, msg2, &rdn->value, &attribute->values[i]) == 0) {
117                                 /* overwrite so it matches in case */
118                                 attribute->values[i] = rdn->value;
119                                 break;
120                         }
121                 }
122                 if (i == attribute->num_values) {
123                         char *error_string = talloc_asprintf(module, "RDN mismatch on %s: %s", ldb_dn_linearize(msg2, msg2->dn), rdn->name);
124                         if (error_string) {
125                                 ldb_set_errstring(module, error_string);
126                                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "%s\n", error_string);
127                         }
128                         talloc_free(msg2);
129                         return -1;
130                 }
131         }
132
133         ret = ldb_next_add_record(module, msg2);
134         talloc_free(msg2);
135
136         return ret;
137 }
138
139 /* modify_record: change modifyTimestamp as well */
140 static int rdn_name_modify_record(struct ldb_module *module, const struct ldb_message *msg)
141 {
142         struct ldb_message *msg2;
143         struct ldb_message_element *attribute;
144         struct ldb_dn_component *rdn;
145         int ret, i;
146
147         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_modify_record\n");
148
149         /* do not manipulate our control entries */
150         if (ldb_dn_is_special(msg->dn)) {
151                 return ldb_next_modify_record(module, msg);
152         }
153
154         /* Perhaps someone above us knows better */
155         if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
156                 return ldb_next_modify_record(module, msg);
157         }
158
159         msg2 = talloc(module, struct ldb_message);
160         if (!msg2) {
161                 return -1;
162         }
163
164         msg2->dn = msg->dn;
165         msg2->num_elements = msg->num_elements;
166         msg2->private_data = msg->private_data;
167         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
168         for (i = 0; i < msg2->num_elements; i++) {
169                 msg2->elements[i] = msg->elements[i];
170         }
171         
172         rdn = ldb_dn_get_rdn(msg2, msg2->dn);
173         if (!rdn) {
174                 talloc_free(msg2);
175                 return -1;
176         }
177         
178         if (ldb_msg_add_value(msg2, "name", &rdn->value) != 0) {
179                 talloc_free(msg2);
180                 return -1;
181         }
182
183         attribute = rdn_name_find_attribute(msg2, "name");
184         if (!attribute) {
185                 talloc_free(msg2);
186                 return -1;
187         }
188
189         attribute->flags = LDB_FLAG_MOD_REPLACE;
190
191         ret = ldb_next_modify_record(module, msg2);
192         talloc_free(msg2);
193
194         return ret;
195 }
196
197 static int rdn_name_rename_record(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
198 {
199         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename_record\n");
200         return ldb_next_rename_record(module, olddn, newdn);
201 }
202
203 static const struct ldb_module_ops rdn_name_ops = {
204         .name              = "rdn_name",
205         .search_bytree     = rdn_name_search_bytree,
206         .add_record        = rdn_name_add_record,
207         .modify_record     = rdn_name_modify_record,
208         .rename_record     = rdn_name_rename_record
209 };
210
211
212 /* the init function */
213 #ifdef HAVE_DLOPEN_DISABLED
214  struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
215 #else
216 struct ldb_module *rdn_name_module_init(struct ldb_context *ldb, const char *options[])
217 #endif
218 {
219         struct ldb_module *ctx;
220
221         ctx = talloc(ldb, struct ldb_module);
222         if (!ctx)
223                 return NULL;
224
225         ctx->private_data = NULL;
226         ctx->ldb = ldb;
227         ctx->prev = ctx->next = NULL;
228         ctx->ops = &rdn_name_ops;
229
230         return ctx;
231 }