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
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.
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.
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/>.
26 * Component: ldb new partition module
28 * Description: Handle the add of new partitions
30 * Author: Andrew Bartlett
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"
42 struct ldb_module
*module
;
43 struct ldb_request
*req
;
44 struct ldb_request
*search_req
;
45 struct ldb_request
*part_add
;
48 static int np_part_mod_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
50 struct ldb_context
*ldb
;
51 struct np_context
*ac
;
53 ac
= talloc_get_type(req
->context
, struct np_context
);
54 ldb
= ldb_module_get_ctx(ac
->module
);
57 return ldb_module_done(ac
->req
, NULL
, NULL
,
58 LDB_ERR_OPERATIONS_ERROR
);
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
);
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
);
73 ldb_reset_err_string(ldb
);
75 /* Do the original add */
76 return ldb_next_request(ac
->module
, ac
->req
);
79 static int np_part_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
81 struct ldb_context
*ldb
;
82 struct np_context
*ac
;
83 struct dsdb_create_partition_exop
*ex_op
;
86 ac
= talloc_get_type(req
->context
, struct np_context
);
87 ldb
= ldb_module_get_ctx(ac
->module
);
90 return ldb_module_done(ac
->req
, NULL
, NULL
,
91 LDB_ERR_OPERATIONS_ERROR
);
94 /* If this already exists, we really don't want to create a
95 * partition - it would allow a duplicate entry to be
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
);
102 return ldb_module_done(ac
->req
, ares
->controls
,
103 ares
->response
, ares
->error
);
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
);
113 ldb_reset_err_string(ldb
);
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
);
121 ex_op
->new_dn
= ac
->req
->op
.add
.message
->dn
;
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
);
127 /* if the parent was asking for a partial replica, then we
128 * need the extended operation to also ask for a partial
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
) {
138 LDB_REQ_SET_LOCATION(ac
->part_add
);
139 if (ret
!= LDB_SUCCESS
) {
143 return ldb_next_request(ac
->module
, ac
->part_add
);
146 /* add_record: add instancetype attribute */
147 static int new_partition_add(struct ldb_module
*module
, struct ldb_request
*req
)
149 struct ldb_context
*ldb
;
150 struct np_context
*ac
;
153 ldb
= ldb_module_get_ctx(module
);
155 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "new_partition_add\n");
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
);
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);
167 if (!(instanceType
& INSTANCE_TYPE_IS_NC_HEAD
)) {
168 return ldb_next_request(module
, req
);
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
);
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
);
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
,
192 LDB_REQ_SET_LOCATION(ac
->search_req
);
193 if (ret
!= LDB_SUCCESS
) {
197 return ldb_next_request(module
, ac
->search_req
);
200 /* go on with the call chain */
201 return ldb_next_request(module
, req
);
204 static const struct ldb_module_ops ldb_new_partition_module_ops
= {
205 .name
= "new_partition",
206 .add
= new_partition_add
,
209 int ldb_new_partition_module_init(const char *version
)
211 LDB_MODULE_CHECK_VERSION(version
);
212 return ldb_register_module(&ldb_new_partition_module_ops
);