Line data Source code
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 979 : static int np_part_mod_callback(struct ldb_request *req, struct ldb_reply *ares)
49 : {
50 108 : struct ldb_context *ldb;
51 108 : struct np_context *ac;
52 :
53 979 : ac = talloc_get_type(req->context, struct np_context);
54 979 : ldb = ldb_module_get_ctx(ac->module);
55 :
56 979 : if (!ares) {
57 0 : 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 979 : if (ares->error != LDB_SUCCESS && ares->error != LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
63 0 : return ldb_module_done(ac->req, ares->controls,
64 : ares->response, ares->error);
65 : }
66 :
67 979 : if (ares->type != LDB_REPLY_DONE) {
68 0 : ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
69 0 : return ldb_module_done(ac->req, NULL, NULL,
70 : LDB_ERR_OPERATIONS_ERROR);
71 : }
72 :
73 979 : ldb_reset_err_string(ldb);
74 :
75 : /* Do the original add */
76 979 : return ldb_next_request(ac->module, ac->req);
77 : }
78 :
79 979 : static int np_part_search_callback(struct ldb_request *req, struct ldb_reply *ares)
80 : {
81 108 : struct ldb_context *ldb;
82 108 : struct np_context *ac;
83 108 : struct dsdb_create_partition_exop *ex_op;
84 108 : int ret;
85 :
86 979 : ac = talloc_get_type(req->context, struct np_context);
87 979 : ldb = ldb_module_get_ctx(ac->module);
88 :
89 979 : if (!ares) {
90 0 : 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 979 : if (ares->error != LDB_ERR_NO_SUCH_OBJECT) {
98 0 : if (ares->error == LDB_SUCCESS) {
99 0 : return ldb_module_done(ac->req, ares->controls,
100 : ares->response, LDB_ERR_ENTRY_ALREADY_EXISTS);
101 : } else {
102 0 : return ldb_module_done(ac->req, ares->controls,
103 : ares->response, ares->error);
104 : }
105 : }
106 :
107 979 : if (ares->type != LDB_REPLY_DONE) {
108 0 : ldb_set_errstring(ldb, "Invalid reply type - we must not get a result here!");
109 0 : return ldb_module_done(ac->req, NULL, NULL,
110 : LDB_ERR_OPERATIONS_ERROR);
111 : }
112 :
113 979 : ldb_reset_err_string(ldb);
114 :
115 : /* Now that we know it does not exist, we can try and create the partition */
116 979 : ex_op = talloc(ac, struct dsdb_create_partition_exop);
117 979 : if (ex_op == NULL) {
118 0 : return ldb_oom(ldb);
119 : }
120 :
121 979 : ex_op->new_dn = ac->req->op.add.message->dn;
122 :
123 979 : 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 979 : if (ldb_request_get_control(req, DSDB_CONTROL_PARTIAL_REPLICA)) {
131 0 : ret = dsdb_request_add_controls(ac->part_add, DSDB_MODIFY_PARTIAL_REPLICA);
132 0 : if (ret != LDB_SUCCESS) {
133 0 : return ret;
134 : }
135 : }
136 :
137 :
138 979 : LDB_REQ_SET_LOCATION(ac->part_add);
139 979 : if (ret != LDB_SUCCESS) {
140 0 : return ret;
141 : }
142 :
143 979 : return ldb_next_request(ac->module, ac->part_add);
144 : }
145 :
146 : /* add_record: add instancetype attribute */
147 924119 : static int new_partition_add(struct ldb_module *module, struct ldb_request *req)
148 : {
149 83787 : struct ldb_context *ldb;
150 83787 : struct np_context *ac;
151 83787 : int ret;
152 :
153 924119 : ldb = ldb_module_get_ctx(module);
154 :
155 924119 : ldb_debug(ldb, LDB_DEBUG_TRACE, "new_partition_add\n");
156 :
157 : /* do not manipulate our control entries */
158 924119 : if (ldb_dn_is_special(req->op.add.message->dn)) {
159 1517 : return ldb_next_request(module, req);
160 : }
161 :
162 922602 : 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 83611 : static const char *no_attrs[] = { NULL };
165 922602 : uint32_t instanceType = ldb_msg_find_attr_as_uint(req->op.add.message, "instanceType", 0);
166 :
167 922602 : if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
168 921623 : return ldb_next_request(module, req);
169 : }
170 :
171 979 : if (ldb_msg_find_attr_as_bool(req->op.add.message, "isDeleted", false)) {
172 0 : DEBUG(0,(__location__ ": Skipping deleted partition %s\n",
173 : ldb_dn_get_linearized(req->op.add.message->dn)));
174 0 : 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 979 : ac = talloc(req, struct np_context);
182 979 : if (ac == NULL) {
183 0 : return ldb_oom(ldb);
184 : }
185 979 : ac->module = module;
186 979 : ac->req = req;
187 :
188 979 : 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 979 : LDB_REQ_SET_LOCATION(ac->search_req);
193 979 : if (ret != LDB_SUCCESS) {
194 0 : return ret;
195 : }
196 :
197 979 : return ldb_next_request(module, ac->search_req);
198 : }
199 :
200 : /* go on with the call chain */
201 0 : 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 6040 : int ldb_new_partition_module_init(const char *version)
210 : {
211 6040 : LDB_MODULE_CHECK_VERSION(version);
212 6040 : return ldb_register_module(&ldb_new_partition_module_ops);
213 : }
|