5b288aa311570e0bbf35e6cc5b6b822285046cb0
[kamenim/samba.git] / source4 / dsdb / samdb / ldb_modules / extended_dn.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2005
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 extended dn control module
29  *
30  *  Description: this module builds a special dn
31  *
32  *  Author: Simo Sorce
33  */
34
35 #include "includes.h"
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_errors.h"
38 #include "ldb/include/ldb_private.h"
39 #include "dsdb/samdb/samdb.h"
40
41 #include <time.h>
42
43 static BOOL is_attr_in_list(const char * const * attrs, const char *attr)
44 {
45         int i;
46
47         for (i = 0; attrs[i]; i++) {
48                 if (strcasecmp(attrs[i], attr) == 0)
49                         return True;
50         }
51
52         return False;
53 }
54
55 static char **copy_attrs(void *mem_ctx, const char * const * attrs)
56 {
57         char **new;
58         int i, num;
59
60         for (num = 0; attrs[num]; num++);
61
62         new = talloc_array(mem_ctx, char *, num + 1);
63         if (!new) return NULL;
64
65         for(i = 0; i < num; i++) {
66                 new[i] = talloc_strdup(new, attrs[i]);
67                 if (!new[i]) {
68                         talloc_free(new);
69                         return NULL;
70                 }
71         }
72         new[i] = NULL;
73
74         return new;
75 }
76
77 static BOOL add_attrs(void *mem_ctx, char ***attrs, const char *attr)
78 {
79         char **new;
80         int num;
81
82         for (num = 0; (*attrs)[num]; num++);
83
84         new = talloc_realloc(mem_ctx, *attrs, char *, num + 2);
85         if (!new) return False;
86
87         *attrs = new;
88
89         new[num] = talloc_strdup(new, attr);
90         if (!new[num]) return False;
91
92         new[num + 1] = NULL;
93
94         return True;
95 }
96
97 static BOOL inject_extended_dn(struct ldb_message *msg,
98                                 int type,
99                                 BOOL remove_guid,
100                                 BOOL remove_sid)
101 {
102         const struct ldb_val *val;
103         struct GUID guid;
104         struct dom_sid *sid;
105         char *object_guid;
106         char *object_sid;
107         char *new_dn, *dn;
108
109         dn = ldb_dn_linearize(msg, msg->dn);
110         if (!dn)
111                 return False;
112
113         /* retrieve object_guid */
114         guid = samdb_result_guid(msg, "objectGUID");
115         object_guid = GUID_string(msg, &guid);
116         if (!object_guid)
117                 return False;
118
119         if (remove_guid)
120                 ldb_msg_remove_attr(msg, "objectGUID");
121
122         /* retrieve object_sid */
123         object_sid = NULL;
124         sid = samdb_result_dom_sid(msg, msg, "objectSID");
125         if (sid) {
126                 object_sid = dom_sid_string(msg, sid);
127                 if (!object_sid)
128                         return False;
129
130                 if (remove_sid)
131                         ldb_msg_remove_attr(msg, "objectSID");
132         }
133
134         /* TODO: handle type */
135         switch (type) {
136                 case 0:
137                 case 1:
138                         if (object_sid) {
139                                 new_dn = talloc_asprintf(msg, "<GUID=%s>;<SID=%s>;%s",
140                                                          object_guid, object_sid, dn);
141                         } else {
142                                 new_dn = talloc_asprintf(msg, "<GUID=%s>;%s",
143                                                          object_guid, dn);
144                         }
145                         break;
146                 default:
147                         return False;
148         }
149
150         if (!new_dn)
151                 return False;
152
153         msg->dn = ldb_dn_explode_or_special(msg, new_dn);
154         if (!msg->dn)
155                 return False;
156
157         val = ldb_msg_find_ldb_val(msg, "distinguishedName");
158         if (val) {
159                 ldb_msg_remove_attr(msg, "distinguishedName");
160                 if (ldb_msg_add_string(msg, "distinguishedName", new_dn))
161                         return False;
162         }
163
164         return True;
165 }
166
167 /* search */
168 static int extended_search(struct ldb_module *module, struct ldb_request *req)
169 {
170         struct ldb_result *extended_result;
171         struct ldb_control *control;
172         struct ldb_control **saved_controls;
173         struct ldb_extended_dn_control *extended_ctrl;
174         int i, ret;
175         const char * const *saved_attrs = NULL;
176         char **new_attrs;
177         BOOL remove_guid = False;
178         BOOL remove_sid = False;
179
180         /* check if there's a paged request control */
181         control = get_control_from_list(req->controls, LDB_CONTROL_EXTENDED_DN_OID);
182         if (control == NULL) {
183                 /* not found go on */
184                 return ldb_next_request(module, req);
185         }
186
187         extended_ctrl = talloc_get_type(control->data, struct ldb_extended_dn_control);
188         if (!extended_ctrl) {
189                 return LDB_ERR_PROTOCOL_ERROR;
190         }
191
192         /* save it locally and remove it from the list */
193         if (!save_controls(control, req, &saved_controls)) {
194                 return LDB_ERR_OPERATIONS_ERROR;
195         }
196                 
197         /* check if attrs only is specified, in that case check wether we need to modify them */
198         if (req->op.search.attrs) {
199                 if (! is_attr_in_list(req->op.search.attrs, "objectGUID")) {
200                         remove_guid = True;
201                 }
202                 if (! is_attr_in_list(req->op.search.attrs, "objectSID")) {
203                         remove_sid = True;
204                 }
205                 if (remove_guid || remove_sid) {
206                         new_attrs = copy_attrs(req, req->op.search.attrs);
207                         if (!new_attrs)
208                                 return LDB_ERR_OPERATIONS_ERROR;
209                         
210                         saved_attrs = req->op.search.attrs;
211
212                         if (remove_guid) {
213                                 if (!add_attrs(req, &new_attrs, "objectGUID"))
214                                         return LDB_ERR_OPERATIONS_ERROR;
215                         }
216                         if (remove_sid) {
217                                 if (!add_attrs(req, &new_attrs, "objectSID"))
218                                         return LDB_ERR_OPERATIONS_ERROR;
219                         }
220
221                         req->op.search.attrs = (const char * const *)new_attrs;
222                 }
223         }
224
225         ret = ldb_next_request(module, req);
226
227         /* put request back into original shape */
228         /* TODO: build a new req and don't touch the original one */
229
230         if (req->controls) talloc_free(req->controls);
231         req->controls = saved_controls;
232
233         if (saved_attrs) {
234                 talloc_free(new_attrs);
235                 req->op.search.attrs = saved_attrs;
236         }
237
238         if (ret != LDB_SUCCESS) {
239                 return ret;
240         }
241
242         extended_result = req->op.search.res;
243         
244         for (i = 0; i < extended_result->count; i++) {
245                 /* TODO: the following funtion updates only dn and
246                  * distinguishedName. We still need to address other
247                  * DN entries like objectCategory
248                  */
249                 if (!inject_extended_dn(extended_result->msgs[i], 
250                                         extended_ctrl->type,
251                                         remove_guid, remove_sid)) {
252                         return LDB_ERR_OPERATIONS_ERROR;
253                 }
254         }
255         
256         return LDB_SUCCESS;     
257 }
258
259 static int extended_request(struct ldb_module *module, struct ldb_request *req)
260 {
261         switch (req->operation) {
262
263         case LDB_REQ_SEARCH:
264                 return extended_search(module, req);
265
266         default:
267                 return ldb_next_request(module, req);
268
269         }
270 }
271
272 static int extended_init(struct ldb_module *module)
273 {
274         struct ldb_request request;
275         int ret;
276
277         request.operation = LDB_REQ_REGISTER;
278         request.op.reg.oid = LDB_CONTROL_EXTENDED_DN_OID;
279         request.controls = NULL;
280
281         ret = ldb_request(module->ldb, &request);
282         if (ret != LDB_SUCCESS) {
283                 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "extended_dn: Unable to register control with rootdse!\n");
284                 return LDB_ERR_OTHER;
285         }
286
287         return ldb_next_init(module);
288 }
289
290 static const struct ldb_module_ops extended_dn_ops = {
291         .name              = "extended_dn",
292         .request           = extended_request,
293         .init_context      = extended_init
294 };
295
296 int ldb_extended_dn_init(void)
297 {
298         return ldb_register_module(&extended_dn_ops);
299 }