ldb-samba: Reenable recursive search
[obnox/samba/samba-obnox.git] / source4 / dsdb / samdb / ldb_modules / new_partition.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /*
24  *  Name: ldb
25  *
26  *  Component: ldb new partition module
27  *
28  *  Description: Handle the add of new partitions
29  *
30  *  Author: Andrew Bartlett
31  */
32
33 #include "includes.h"
34 #include "ldb.h"
35 #include "ldb_module.h"
36 #include "librpc/gen_ndr/ndr_misc.h"
37 #include "dsdb/samdb/samdb.h"
38 #include "../libds/common/flags.h"
39 #include "dsdb/common/util.h"
40
41 struct np_context {
42         struct ldb_module *module;
43         struct ldb_request *req;
44         struct ldb_request *search_req;
45         struct ldb_request *part_add;
46 };
47
48 static int np_part_mod_callback(struct ldb_request *req, struct ldb_reply *ares)
49 {
50         struct ldb_context *ldb;
51         struct np_context *ac;
52
53         ac = talloc_get_type(req->context, struct np_context);
54         ldb = ldb_module_get_ctx(ac->module);
55
56         if (!ares) {
57                 return ldb_module_done(ac->req, NULL, NULL,
58                                         LDB_ERR_OPERATIONS_ERROR);
59         }
60
61         /* We just want to update the @PARTITIONS record if the value does not exist */
62         if (ares->error != LDB_SUCCESS && ares->error != LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
63                 return ldb_module_done(ac->req, ares->controls,
64                                         ares->response, ares->error);
65         }
66
67         if (ares->type != LDB_REPLY_DONE) {
68                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
69                 return ldb_module_done(ac->req, NULL, NULL,
70                                         LDB_ERR_OPERATIONS_ERROR);
71         }
72
73         ldb_reset_err_string(ldb);
74
75         /* Do the original add */
76         return ldb_next_request(ac->module, ac->req);
77 }
78
79 static int np_part_search_callback(struct ldb_request *req, struct ldb_reply *ares)
80 {
81         struct ldb_context *ldb;
82         struct np_context *ac;
83         struct dsdb_create_partition_exop *ex_op;
84         int ret;
85
86         ac = talloc_get_type(req->context, struct np_context);
87         ldb = ldb_module_get_ctx(ac->module);
88
89         if (!ares) {
90                 return ldb_module_done(ac->req, NULL, NULL,
91                                         LDB_ERR_OPERATIONS_ERROR);
92         }
93
94         /* If this already exists, we really don't want to create a
95          * partition - it would allow a duplicate entry to be
96          * created */
97         if (ares->error != LDB_ERR_NO_SUCH_OBJECT) {
98                 if (ares->error == LDB_SUCCESS) {
99                         return ldb_module_done(ac->req, ares->controls,
100                                                ares->response, LDB_ERR_ENTRY_ALREADY_EXISTS);
101                 } else {
102                         return ldb_module_done(ac->req, ares->controls,
103                                                ares->response, ares->error);
104                 }
105         }
106
107         if (ares->type != LDB_REPLY_DONE) {
108                 ldb_set_errstring(ldb, "Invalid reply type - we must not get a result here!");
109                 return ldb_module_done(ac->req, NULL, NULL,
110                                         LDB_ERR_OPERATIONS_ERROR);
111         }
112
113         ldb_reset_err_string(ldb);
114
115         /* Now that we know it does not exist, we can try and create the partition */
116         ex_op = talloc(ac, struct dsdb_create_partition_exop);
117         if (ex_op == NULL) {
118                 return ldb_oom(ldb);
119         }
120         
121         ex_op->new_dn = ac->req->op.add.message->dn;
122         
123         ret = ldb_build_extended_req(&ac->part_add, 
124                                      ldb, ac, DSDB_EXTENDED_CREATE_PARTITION_OID, ex_op, 
125                                      NULL, ac, np_part_mod_callback, req);
126
127         /* if the parent was asking for a partial replica, then we
128          * need the extended operation to also ask for a partial
129          * replica */
130         if (ldb_request_get_control(req, DSDB_CONTROL_PARTIAL_REPLICA)) {
131                 ret = dsdb_request_add_controls(ac->part_add, DSDB_MODIFY_PARTIAL_REPLICA);
132                 if (ret != LDB_SUCCESS) {
133                         return ret;
134                 }
135         }
136
137         
138         LDB_REQ_SET_LOCATION(ac->part_add);
139         if (ret != LDB_SUCCESS) {
140                 return ret;
141         }
142         
143         return ldb_next_request(ac->module, ac->part_add);
144 }
145
146 /* add_record: add instancetype attribute */
147 static int new_partition_add(struct ldb_module *module, struct ldb_request *req)
148 {
149         struct ldb_context *ldb;
150         struct np_context *ac;
151         int ret;
152
153         ldb = ldb_module_get_ctx(module);
154
155         ldb_debug(ldb, LDB_DEBUG_TRACE, "new_partition_add\n");
156
157         /* do not manipulate our control entries */
158         if (ldb_dn_is_special(req->op.add.message->dn)) {
159                 return ldb_next_request(module, req);
160         }
161
162         if (ldb_msg_find_element(req->op.add.message, "instanceType")) {
163                 /* This needs to be 'static' to ensure it does not move, and is not on the stack */
164                 static const char *no_attrs[] = { NULL };
165                 uint32_t instanceType = ldb_msg_find_attr_as_uint(req->op.add.message, "instanceType", 0);
166
167                 if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
168                         return ldb_next_request(module, req);
169                 }
170
171                 if (ldb_msg_find_attr_as_bool(req->op.add.message, "isDeleted", false)) {
172                         DEBUG(0,(__location__ ": Skipping deleted partition %s\n",
173                                  ldb_dn_get_linearized(req->op.add.message->dn)));
174                         return ldb_next_request(module, req);           
175                 }
176
177                 /* Create an @PARTITIONS record for this partition -
178                  * by asking the partitions module to do so via an
179                  * extended operation, after first checking if the
180                  * record already exists */
181                 ac = talloc(req, struct np_context);
182                 if (ac == NULL) {
183                         return ldb_oom(ldb);
184                 }
185                 ac->module = module;
186                 ac->req = req;
187                 
188                 ret = ldb_build_search_req(&ac->search_req, ldb, ac, req->op.add.message->dn, 
189                                            LDB_SCOPE_BASE, NULL, no_attrs, req->controls, ac, 
190                                            np_part_search_callback,
191                                            req);
192                 LDB_REQ_SET_LOCATION(ac->search_req);
193                 if (ret != LDB_SUCCESS) {
194                         return ret;
195                 }
196                 
197                 return ldb_next_request(module, ac->search_req);
198         }
199
200         /* go on with the call chain */
201         return ldb_next_request(module, req);
202 }
203
204 static const struct ldb_module_ops ldb_new_partition_module_ops = {
205         .name          = "new_partition",
206         .add           = new_partition_add,
207 };
208
209 int ldb_new_partition_module_init(const char *version)
210 {
211         LDB_MODULE_CHECK_VERSION(version);
212         return ldb_register_module(&ldb_new_partition_module_ops);
213 }