The DN in objectCategory should, if possible, be returned pretty...
[jelmer/samba4-debian.git] / source / 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                 /* Look to see if this attributeSyntax is a DN */
109                 if (!((strcmp(attribute->attributeSyntax_oid, "2.5.5.1") == 0) ||
110                       (strcmp(attribute->attributeSyntax_oid, "2.5.5.7") == 0))) {
111                         continue;
112                 }
113                 for (j = 0; j < ares->message->elements[i].num_values; j++) {
114                         const char *dn_str;
115                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, (const char *)ares->message->elements[i].values[j].data);
116                         if (!dn) {
117                                 talloc_free(mem_ctx);
118                                 return LDB_ERR_OPERATIONS_ERROR;
119                         }
120                         ret = fix_dn(ares->message->dn);
121                         if (ret != LDB_SUCCESS) {
122                                 talloc_free(mem_ctx);
123                                 return ret;
124                         }
125                         dn_str = talloc_steal(ares->message->elements[i].values, ldb_dn_get_linearized(dn));
126                         ares->message->elements[i].values[j] = data_blob_string_const(dn_str);
127                         talloc_free(dn);
128                 }
129         }
130         talloc_free(mem_ctx);
131         return orig_req->callback(ldb, orig_req->context, ares);
132 }
133
134 /* search */
135 static int normalise_search(struct ldb_module *module, struct ldb_request *req)
136 {
137         int ret;
138         struct ldb_request *down_req = talloc(req, struct ldb_request);
139         if (!down_req) {
140                 ldb_oom(module->ldb);
141                 return LDB_ERR_OPERATIONS_ERROR;
142         }
143         
144         *down_req = *req;
145         down_req->context = req;
146         down_req->callback = normalise_search_callback;
147
148         ret = ldb_next_request(module, down_req);
149
150         /* do not free down_req as the call results may be linked to it,
151          * it will be freed when the upper level request get freed */
152         if (ret == LDB_SUCCESS) {
153                 req->handle = down_req->handle;
154         }
155         return ret;
156 }
157
158
159 _PUBLIC_ const struct ldb_module_ops ldb_normalise_module_ops = {
160         .name              = "normalise",
161         .search            = normalise_search,
162 };