Correct authorship of instanceType module
[samba.git] / source4 / dsdb / samdb / ldb_modules / normalise.c
1 /* 
2    ldb database library
3
4    Copyright (C) Amdrew Bartlett <abartlet@samba.org> 2007-2008
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21  *  Name: ldb
22  *
23  *  Component: ldb normalisation module
24  *
25  *  Description: module to ensure all DNs and attribute names are normalised
26  *
27  *  Author: Andrew Bartlett
28  */
29
30 #include "includes.h"
31 #include "ldb/include/ldb.h"
32 #include "ldb/include/ldb_errors.h"
33 #include "ldb/include/ldb_private.h"
34 #include "dsdb/samdb/samdb.h"
35
36 /* Fix up the DN to be in the standard form, taking particular care to match the parent DN
37
38    This should mean that if the parent is:
39     CN=Users,DC=samba,DC=example,DC=com
40    and a proposed child is
41     cn=Admins ,cn=USERS,dc=Samba,dc=example,dc=COM
42
43    The resulting DN should be:
44
45     CN=Admins,CN=Users,DC=samba,DC=example,DC=com
46    
47  */
48 static int fix_dn(struct ldb_dn *dn) 
49 {
50         int i, ret;
51         char *upper_rdn_attr;
52
53         for (i=0; i < ldb_dn_get_comp_num(dn); i++) {
54                 /* We need the attribute name in upper case */
55                 upper_rdn_attr = strupper_talloc(dn,
56                                                  ldb_dn_get_component_name(dn, i));
57                 if (!upper_rdn_attr) {
58                         return LDB_ERR_OPERATIONS_ERROR;
59                 }
60                 
61                 /* And replace it with CN=foo (we need the attribute in upper case */
62                 ret = ldb_dn_set_component(dn, i, upper_rdn_attr,
63                                            *ldb_dn_get_component_val(dn, i));
64                 talloc_free(upper_rdn_attr);
65                 if (ret != LDB_SUCCESS) {
66                         return ret;
67                 }
68         }
69         return LDB_SUCCESS;
70 }
71
72 static int normalise_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) 
73 {
74         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
75         struct ldb_request *orig_req = talloc_get_type(context, struct ldb_request);
76         TALLOC_CTX *mem_ctx;
77         int i, j, ret;
78
79         /* Only entries are interesting, and we handle the case of the parent seperatly */
80         if (ares->type != LDB_REPLY_ENTRY) {
81                 return orig_req->callback(ldb, orig_req->context, ares);
82         }
83
84         if (!schema) {
85                 return orig_req->callback(ldb, orig_req->context, ares);
86         }
87
88         mem_ctx = talloc_new(ares);
89         if (!mem_ctx) {
90                 ldb_oom(ldb);
91                 return LDB_ERR_OPERATIONS_ERROR;
92         }
93
94         /* OK, we have one of *many* search results passing by here,
95          * but we should get them one at a time */
96
97         ret = fix_dn(ares->message->dn);
98         if (ret != LDB_SUCCESS) {
99                 talloc_free(mem_ctx);
100                 return ret;
101         }
102
103         for (i = 0; i < ares->message->num_elements; i++) {
104                 const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema, ares->message->elements[i].name);
105                 if (!attribute) {
106                         continue;
107                 }
108                 if ((strcmp(attribute->attributeSyntax_oid, "2.5.5.1") != 0) &&
109                     (strcmp(attribute->attributeSyntax_oid, "2.5.5.7") != 0)) {
110                         continue;
111                 }
112                 for (j = 0; j < ares->message->elements[i].num_values; j++) {
113                         const char *dn_str;
114                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, (const char *)ares->message->elements[i].values[j].data);
115                         if (!dn) {
116                                 talloc_free(mem_ctx);
117                                 return LDB_ERR_OPERATIONS_ERROR;
118                         }
119                         ret = fix_dn(ares->message->dn);
120                         if (ret != LDB_SUCCESS) {
121                                 talloc_free(mem_ctx);
122                                 return ret;
123                         }
124                         dn_str = talloc_steal(ares->message->elements[i].values, ldb_dn_get_linearized(dn));
125                         ares->message->elements[i].values[j] = data_blob_string_const(dn_str);
126                         talloc_free(dn);
127                 }
128         }
129         talloc_free(mem_ctx);
130         return orig_req->callback(ldb, orig_req->context, ares);
131 }
132
133 /* search */
134 static int normalise_search(struct ldb_module *module, struct ldb_request *req)
135 {
136         int ret;
137         struct ldb_request *down_req = talloc(req, struct ldb_request);
138         if (!down_req) {
139                 ldb_oom(module->ldb);
140                 return LDB_ERR_OPERATIONS_ERROR;
141         }
142         
143         *down_req = *req;
144         down_req->context = req;
145         down_req->callback = normalise_search_callback;
146
147         ret = ldb_next_request(module, down_req);
148
149         /* do not free down_req as the call results may be linked to it,
150          * it will be freed when the upper level request get freed */
151         if (ret == LDB_SUCCESS) {
152                 req->handle = down_req->handle;
153         }
154         return ret;
155 }
156
157
158 static const struct ldb_module_ops normalise_ops = {
159         .name              = "normalise",
160         .search            = normalise_search,
161 };
162
163 int ldb_normalise_init(void)
164 {
165         return ldb_register_module(&normalise_ops);
166 }