1/* 2 ldb database library 3 4 Copyright (C) Andrew Bartlett 2005 5 Copyright (C) Simo Sorce 2006-2008 6 7 ** NOTE! The following LGPL license applies to the ldb 8 ** library. This does NOT imply that all of Samba is released 9 ** under the LGPL 10 11 This library is free software; you can redistribute it and/or 12 modify it under the terms of the GNU Lesser General Public 13 License as published by the Free Software Foundation; either 14 version 3 of the License, or (at your option) any later version. 15 16 This library is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 Lesser General Public License for more details. 20 21 You should have received a copy of the GNU Lesser General Public 22 License along with this library; if not, see <http://www.gnu.org/licenses/>. 23*/ 24 25/* 26 * Name: rdn_name 27 * 28 * Component: ldb rdn name module 29 * 30 * Description: keep a consistent name attribute on objects manpulations 31 * 32 * Author: Andrew Bartlett 33 * 34 * Modifications: 35 * - made the module async 36 * Simo Sorce Mar 2006 37 */ 38 39#include "ldb_includes.h" 40#include "ldb_module.h" 41 42struct rename_context { 43 44 struct ldb_module *module; 45 struct ldb_request *req; 46 47 struct ldb_reply *ares; 48}; 49 50static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name) 51{ 52 int i; 53 54 for (i = 0; i < msg->num_elements; i++) { 55 if (ldb_attr_cmp(name, msg->elements[i].name) == 0) { 56 return &msg->elements[i]; 57 } 58 } 59 60 return NULL; 61} 62 63static int rdn_name_add_callback(struct ldb_request *req, 64 struct ldb_reply *ares) 65{ 66 struct rename_context *ac; 67 68 ac = talloc_get_type(req->context, struct rename_context); 69 70 if (!ares) { 71 return ldb_module_done(ac->req, NULL, NULL, 72 LDB_ERR_OPERATIONS_ERROR); 73 } 74 if (ares->error != LDB_SUCCESS) { 75 return ldb_module_done(ac->req, ares->controls, 76 ares->response, ares->error); 77 } 78 79 if (ares->type != LDB_REPLY_DONE) { 80 return ldb_module_done(ac->req, NULL, NULL, 81 LDB_ERR_OPERATIONS_ERROR); 82 } 83 84 return ldb_module_done(ac->req, ares->controls, 85 ares->response, LDB_SUCCESS); 86} 87 88static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) 89{ 90 struct ldb_context *ldb; 91 struct ldb_request *down_req; 92 struct rename_context *ac; 93 struct ldb_message *msg; 94 struct ldb_message_element *attribute; 95 const struct ldb_schema_attribute *a; 96 const char *rdn_name; 97 struct ldb_val rdn_val; 98 int i, ret; 99 100 ldb = ldb_module_get_ctx(module); 101 ldb_debug(ldb, LDB_DEBUG_TRACE, "rdn_name_add_record"); 102 103 /* do not manipulate our control entries */ 104 if (ldb_dn_is_special(req->op.add.message->dn)) { 105 return ldb_next_request(module, req); 106 } 107 108 ac = talloc_zero(req, struct rename_context); 109 if (ac == NULL) { 110 return LDB_ERR_OPERATIONS_ERROR; 111 } 112 113 ac->module = module; 114 ac->req = req; 115 116 msg = ldb_msg_copy_shallow(req, req->op.add.message); 117 if (msg == NULL) { 118 return LDB_ERR_OPERATIONS_ERROR; 119 } 120 121 rdn_name = ldb_dn_get_rdn_name(msg->dn); 122 if (rdn_name == NULL) { 123 talloc_free(ac); 124 return LDB_ERR_OPERATIONS_ERROR; 125 } 126 127 rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn)); 128 129 /* Perhaps someone above us tried to set this? */ 130 if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) { 131 attribute->num_values = 0; 132 } 133 134 if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { 135 talloc_free(ac); 136 return LDB_ERR_OPERATIONS_ERROR; 137 } 138 139 attribute = rdn_name_find_attribute(msg, rdn_name); 140 141 if (!attribute) { 142 if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { 143 talloc_free(ac); 144 return LDB_ERR_OPERATIONS_ERROR; 145 } 146 } else { 147 a = ldb_schema_attribute_by_name(ldb, rdn_name); 148 149 for (i = 0; i < attribute->num_values; i++) { 150 ret = a->syntax->comparison_fn(ldb, msg, 151 &rdn_val, &attribute->values[i]); 152 if (ret == 0) { 153 /* overwrite so it matches in case */ 154 attribute->values[i] = rdn_val; 155 break; 156 } 157 } 158 if (i == attribute->num_values) { 159 char *rdn_errstring = talloc_asprintf(ac, "RDN mismatch on %s: %s (%.*s) should match one of:", 160 ldb_dn_get_linearized(msg->dn), rdn_name, 161 (int)rdn_val.length, (const char *)rdn_val.data); 162 for (i = 0; i < attribute->num_values; i++) { 163 rdn_errstring = talloc_asprintf_append(rdn_errstring, " (%.*s)", 164 (int)attribute->values[i].length, 165 (const char *)attribute->values[i].data); 166 } 167 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "%s", rdn_errstring); 168 talloc_free(ac); 169 /* Match AD's error here */ 170 return LDB_ERR_INVALID_DN_SYNTAX; 171 } 172 } 173 174 ret = ldb_build_add_req(&down_req, ldb, req, 175 msg, 176 req->controls, 177 ac, rdn_name_add_callback, 178 req); 179 if (ret != LDB_SUCCESS) { 180 return ret; 181 } 182 183 talloc_steal(down_req, msg); 184 185 /* go on with the call chain */ 186 return ldb_next_request(module, down_req); 187} 188 189static int rdn_modify_callback(struct ldb_request *req, struct ldb_reply *ares) 190{ 191 struct rename_context *ac; 192 193 ac = talloc_get_type(req->context, struct rename_context); 194 195 if (!ares) { 196 return ldb_module_done(ac->req, NULL, NULL, 197 LDB_ERR_OPERATIONS_ERROR); 198 } 199 if (ares->error != LDB_SUCCESS) { 200 return ldb_module_done(ac->req, ares->controls, 201 ares->response, ares->error); 202 } 203 204 /* the only supported reply right now is a LDB_REPLY_DONE */ 205 if (ares->type != LDB_REPLY_DONE) { 206 return ldb_module_done(ac->req, NULL, NULL, 207 LDB_ERR_OPERATIONS_ERROR); 208 } 209 210 /* send saved controls eventually */ 211 return ldb_module_done(ac->req, ac->ares->controls, 212 ac->ares->response, LDB_SUCCESS); 213} 214 215static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares) 216{ 217 struct ldb_context *ldb; 218 struct rename_context *ac; 219 struct ldb_request *mod_req; 220 const char *rdn_name; 221 struct ldb_val rdn_val; 222 struct ldb_message *msg; 223 int ret; 224 225 ac = talloc_get_type(req->context, struct rename_context); 226 ldb = ldb_module_get_ctx(ac->module); 227 228 if (!ares) { 229 goto error; 230 } 231 if (ares->error != LDB_SUCCESS) { 232 return ldb_module_done(ac->req, ares->controls, 233 ares->response, ares->error); 234 } 235 236 /* the only supported reply right now is a LDB_REPLY_DONE */ 237 if (ares->type != LDB_REPLY_DONE) { 238 goto error; 239 } 240 241 /* save reply for caller */ 242 ac->ares = talloc_steal(ac, ares); 243 244 msg = ldb_msg_new(ac); 245 if (msg == NULL) { 246 goto error; 247 } 248 msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn); 249 if (msg->dn == NULL) { 250 goto error; 251 } 252 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn); 253 if (rdn_name == NULL) { 254 goto error; 255 } 256 257 rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->req->op.rename.newdn)); 258 259 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { 260 goto error; 261 } 262 if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { 263 goto error; 264 } 265 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { 266 goto error; 267 } 268 if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { 269 goto error; 270 } 271 272 ret = ldb_build_mod_req(&mod_req, ldb, 273 ac, msg, NULL, 274 ac, rdn_modify_callback, 275 req); 276 if (ret != LDB_SUCCESS) { 277 return ldb_module_done(ac->req, NULL, NULL, ret); 278 } 279 talloc_steal(mod_req, msg); 280 281 /* do the mod call */ 282 return ldb_request(ldb, mod_req); 283 284error: 285 return ldb_module_done(ac->req, NULL, NULL, 286 LDB_ERR_OPERATIONS_ERROR); 287} 288 289static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req) 290{ 291 struct ldb_context *ldb; 292 struct rename_context *ac; 293 struct ldb_request *down_req; 294 int ret; 295 296 ldb = ldb_module_get_ctx(module); 297 ldb_debug(ldb, LDB_DEBUG_TRACE, "rdn_name_rename"); 298 299 /* do not manipulate our control entries */ 300 if (ldb_dn_is_special(req->op.rename.newdn)) { 301 return ldb_next_request(module, req); 302 } 303 304 ac = talloc_zero(req, struct rename_context); 305 if (ac == NULL) { 306 return LDB_ERR_OPERATIONS_ERROR; 307 } 308 309 ac->module = module; 310 ac->req = req; 311 312 ret = ldb_build_rename_req(&down_req, 313 ldb, 314 ac, 315 req->op.rename.olddn, 316 req->op.rename.newdn, 317 req->controls, 318 ac, 319 rdn_rename_callback, 320 req); 321 322 if (ret != LDB_SUCCESS) { 323 return LDB_ERR_OPERATIONS_ERROR; 324 } 325 326 /* rename first, modify "name" if rename is ok */ 327 return ldb_next_request(module, down_req); 328} 329 330const struct ldb_module_ops ldb_rdn_name_module_ops = { 331 .name = "rdn_name", 332 .add = rdn_name_add, 333 .rename = rdn_name_rename, 334}; 335