d8d55ae42af310fc6de6bc4b64ba246569d77abd
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4
5    Copyright (C) Andrew Tridgell 2009
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "ldb.h"
24 #include "ldb_module.h"
25 #include "librpc/ndr/libndr.h"
26 #include "dsdb/samdb/ldb_modules/util.h"
27 #include "dsdb/samdb/samdb.h"
28
29 /*
30   add a set of controls to a ldb_request structure based on a set of
31   flags. See util.h for a list of available flags
32  */
33 int dsdb_request_add_controls(struct ldb_module *module, struct ldb_request *req, uint32_t dsdb_flags)
34 {
35         int ret;
36         if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
37                 struct ldb_search_options_control *options;
38                 /* Using the phantom root control allows us to search all partitions */
39                 options = talloc(req, struct ldb_search_options_control);
40                 if (options == NULL) {
41                         ldb_module_oom(module);
42                         return LDB_ERR_OPERATIONS_ERROR;
43                 }
44                 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
45                 
46                 ret = ldb_request_add_control(req,
47                                               LDB_CONTROL_SEARCH_OPTIONS_OID,
48                                               true, options);
49                 if (ret != LDB_SUCCESS) {
50                         return ret;
51                 }
52         }
53
54         if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
55                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
56                 if (ret != LDB_SUCCESS) {
57                         return ret;
58                 }
59         }
60
61         if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
62                 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
63                 if (ret != LDB_SUCCESS) {
64                         return ret;
65                 }
66         }
67
68         if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
69                 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
70                 if (!extended_ctrl) {
71                         ldb_module_oom(module);
72                         return LDB_ERR_OPERATIONS_ERROR;
73                 }
74                 extended_ctrl->type = 1;
75                 
76                 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
77                 if (ret != LDB_SUCCESS) {
78                         return ret;
79                 }
80         }
81
82         if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
83                 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
84                 if (ret != LDB_SUCCESS) {
85                         return ret;
86                 }
87         }
88
89         return LDB_SUCCESS;
90 }
91
92 /*
93   search for attrs on one DN, in the modules below
94  */
95 int dsdb_module_search_dn(struct ldb_module *module,
96                           TALLOC_CTX *mem_ctx,
97                           struct ldb_result **_res,
98                           struct ldb_dn *basedn,
99                           const char * const *attrs,
100                           uint32_t dsdb_flags)
101 {
102         int ret;
103         struct ldb_request *req;
104         TALLOC_CTX *tmp_ctx;
105         struct ldb_result *res;
106
107         tmp_ctx = talloc_new(mem_ctx);
108
109         res = talloc_zero(tmp_ctx, struct ldb_result);
110         if (!res) {
111                 return LDB_ERR_OPERATIONS_ERROR;
112         }
113
114         ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
115                                    basedn,
116                                    LDB_SCOPE_BASE,
117                                    NULL,
118                                    attrs,
119                                    NULL,
120                                    res,
121                                    ldb_search_default_callback,
122                                    NULL);
123         if (ret != LDB_SUCCESS) {
124                 talloc_free(tmp_ctx);
125                 return ret;
126         }
127
128         ret = dsdb_request_add_controls(module, req, dsdb_flags);
129         if (ret != LDB_SUCCESS) {
130                 talloc_free(tmp_ctx);
131                 return ret;
132         }
133
134         ret = ldb_next_request(module, req);
135         if (ret == LDB_SUCCESS) {
136                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
137         }
138
139         if (ret != LDB_SUCCESS) {
140                 talloc_free(tmp_ctx);
141                 return ret;
142         }
143
144         if (res->count != 1) {
145                 /* we may be reading a DB that does not have the 'check base on search' option... */
146                 ret = LDB_ERR_NO_SUCH_OBJECT;
147                 ldb_asprintf_errstring(ldb_module_get_ctx(module), 
148                                        "dsdb_module_search_dn: did not find base dn %s (%d results)", 
149                                        ldb_dn_get_linearized(basedn), res->count);
150         } else {
151                 *_res = talloc_steal(mem_ctx, res);
152         }
153         talloc_free(tmp_ctx);
154         return ret;
155 }
156
157 /*
158   search for attrs in the modules below
159  */
160 int dsdb_module_search(struct ldb_module *module,
161                        TALLOC_CTX *mem_ctx,
162                        struct ldb_result **_res,
163                        struct ldb_dn *basedn, enum ldb_scope scope, 
164                        const char * const *attrs,
165                        int dsdb_flags, 
166                        const char *expression)
167 {
168         int ret;
169         struct ldb_request *req;
170         TALLOC_CTX *tmp_ctx;
171         struct ldb_result *res;
172
173         tmp_ctx = talloc_new(mem_ctx);
174
175         res = talloc_zero(tmp_ctx, struct ldb_result);
176         if (!res) {
177                 return LDB_ERR_OPERATIONS_ERROR;
178         }
179
180         ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
181                                    basedn,
182                                    scope,
183                                    expression,
184                                    attrs,
185                                    NULL,
186                                    res,
187                                    ldb_search_default_callback,
188                                    NULL);
189         if (ret != LDB_SUCCESS) {
190                 talloc_free(tmp_ctx);
191                 return ret;
192         }
193
194         ret = dsdb_request_add_controls(module, req, dsdb_flags);
195         if (ret != LDB_SUCCESS) {
196                 talloc_free(tmp_ctx);
197                 return ret;
198         }
199
200         ret = ldb_next_request(module, req);
201         if (ret == LDB_SUCCESS) {
202                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
203         }
204
205         talloc_free(req);
206         if (ret == LDB_SUCCESS) {
207                 *_res = talloc_steal(mem_ctx, res);
208         }
209         talloc_free(tmp_ctx);
210         return ret;
211 }
212
213 /*
214   find a DN given a GUID. This searches across all partitions
215  */
216 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
217                            const struct GUID *guid, struct ldb_dn **dn)
218 {
219         struct ldb_result *res;
220         const char *attrs[] = { NULL };
221         char *expression;
222         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
223         int ret;
224
225         expression = talloc_asprintf(tmp_ctx, "objectGUID=%s", GUID_string(tmp_ctx, guid));
226         if (!expression) {
227                 ldb_module_oom(module);
228                 return LDB_ERR_OPERATIONS_ERROR;
229         }
230
231         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
232                                  attrs,
233                                  DSDB_SEARCH_SHOW_DELETED |
234                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
235                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
236                                  expression);
237         if (ret != LDB_SUCCESS) {
238                 talloc_free(tmp_ctx);
239                 return ret;
240         }
241         if (res->count == 0) {
242                 talloc_free(tmp_ctx);
243                 return LDB_ERR_NO_SUCH_OBJECT;
244         }
245         if (res->count != 1) {
246                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching %s\n",
247                                        expression);
248                 talloc_free(tmp_ctx);
249                 return LDB_ERR_OPERATIONS_ERROR;
250         }
251
252         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
253
254         talloc_free(tmp_ctx);
255         return LDB_SUCCESS;
256 }
257
258 /*
259   a ldb_modify request operating on modules below the
260   current module
261  */
262 int dsdb_module_modify(struct ldb_module *module,
263                        const struct ldb_message *message,
264                        uint32_t dsdb_flags)
265 {
266         struct ldb_request *mod_req;
267         int ret;
268         struct ldb_context *ldb = ldb_module_get_ctx(module);
269         TALLOC_CTX *tmp_ctx = talloc_new(module);
270
271         ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
272                                 message,
273                                 NULL,
274                                 NULL,
275                                 ldb_op_default_callback,
276                                 NULL);
277         if (ret != LDB_SUCCESS) {
278                 talloc_free(tmp_ctx);
279                 return ret;
280         }
281
282         ret = dsdb_request_add_controls(module, mod_req, dsdb_flags);
283         if (ret != LDB_SUCCESS) {
284                 talloc_free(tmp_ctx);
285                 return ret;
286         }
287
288         /* Run the new request */
289         ret = ldb_next_request(module, mod_req);
290         if (ret == LDB_SUCCESS) {
291                 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
292         }
293
294         talloc_free(tmp_ctx);
295         return ret;
296 }
297
298
299
300 /*
301   a ldb_rename request operating on modules below the
302   current module
303  */
304 int dsdb_module_rename(struct ldb_module *module,
305                       struct ldb_dn *olddn, struct ldb_dn *newdn,
306                       uint32_t dsdb_flags)
307 {
308         struct ldb_request *req;
309         int ret;
310         struct ldb_context *ldb = ldb_module_get_ctx(module);
311         TALLOC_CTX *tmp_ctx = talloc_new(module);
312
313         ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
314                                    olddn,
315                                    newdn,
316                                    NULL,
317                                    NULL,
318                                    ldb_op_default_callback,
319                                    NULL);
320         if (ret != LDB_SUCCESS) {
321                 talloc_free(tmp_ctx);
322                 return ret;
323         }
324
325         ret = dsdb_request_add_controls(module, req, dsdb_flags);
326         if (ret != LDB_SUCCESS) {
327                 talloc_free(tmp_ctx);
328                 return ret;
329         }
330
331         /* Run the new request */
332         ret = ldb_next_request(module, req);
333         if (ret == LDB_SUCCESS) {
334                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
335         }
336
337         talloc_free(tmp_ctx);
338         return ret;
339 }