librpc/ndr: Fix fuzz CI on latest tumbleweed
[samba.git] / lib / ldb / modules / rdn_name.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Bartlett 2005-2009
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 "replace.h"
40 #include "system/filesys.h"
41 #include "system/time.h"
42 #include "ldb_module.h"
43
44 struct rename_context {
45         struct ldb_module *module;
46         struct ldb_request *req;
47
48         struct ldb_reply *ares;
49 };
50
51 static int rdn_name_add_callback(struct ldb_request *req,
52                                  struct ldb_reply *ares)
53 {
54         struct rename_context *ac;
55
56         ac = talloc_get_type(req->context, struct rename_context);
57
58         if (!ares) {
59                 return ldb_module_done(ac->req, NULL, NULL,
60                                         LDB_ERR_OPERATIONS_ERROR);
61         }
62
63         if (ares->type == LDB_REPLY_REFERRAL) {
64                 return ldb_module_send_referral(ac->req, ares->referral);
65         }
66
67         if (ares->error != LDB_SUCCESS) {
68                 return ldb_module_done(ac->req, ares->controls,
69                                         ares->response, ares->error);
70         }
71
72         if (ares->type != LDB_REPLY_DONE) {
73                 return ldb_module_done(ac->req, NULL, NULL,
74                                         LDB_ERR_OPERATIONS_ERROR);
75         }
76
77         return ldb_module_done(ac->req, ares->controls,
78                                         ares->response, LDB_SUCCESS);
79 }
80
81 static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
82 {
83         struct ldb_context *ldb;
84         struct ldb_request *down_req;
85         struct rename_context *ac;
86         struct ldb_message *msg;
87         struct ldb_message_element *attribute;
88         const struct ldb_schema_attribute *a;
89         const char *rdn_name;
90         const struct ldb_val *rdn_val_p;
91         struct ldb_val rdn_val;
92         unsigned int i;
93         int ret;
94
95         ldb = ldb_module_get_ctx(module);
96
97         /* do not manipulate our control entries */
98         if (ldb_dn_is_special(req->op.add.message->dn)) {
99                 return ldb_next_request(module, req);
100         }
101
102         ac = talloc_zero(req, struct rename_context);
103         if (ac == NULL) {
104                 return LDB_ERR_OPERATIONS_ERROR;
105         }
106
107         ac->module = module;
108         ac->req = req;
109
110         msg = ldb_msg_copy_shallow(req, req->op.add.message);
111         if (msg == NULL) {
112                 return LDB_ERR_OPERATIONS_ERROR;
113         }
114
115         rdn_name = ldb_dn_get_rdn_name(msg->dn);
116         if (rdn_name == NULL) {
117                 return LDB_ERR_OPERATIONS_ERROR;
118         }
119         
120         rdn_val_p = ldb_dn_get_rdn_val(msg->dn);
121         if (rdn_val_p == NULL) {
122                 return LDB_ERR_OPERATIONS_ERROR;
123         }
124         if (rdn_val_p->length == 0) {
125                 ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
126                                        ldb_dn_get_linearized(req->op.add.message->dn));
127                 return LDB_ERR_INVALID_DN_SYNTAX;
128         }
129         rdn_val = ldb_val_dup(msg, rdn_val_p);
130
131         /* Perhaps someone above us tried to set this? Then ignore it */
132         ldb_msg_remove_attr(msg, "name");
133
134         ret = ldb_msg_add_value(msg, "name", &rdn_val, NULL);
135         if (ret != LDB_SUCCESS) {
136                 return ret;
137         }
138
139         a = ldb_schema_attribute_by_name(ldb, rdn_name);
140         if (a == NULL) {
141                 return LDB_ERR_OPERATIONS_ERROR;
142         }
143
144         attribute = ldb_msg_find_element(msg, rdn_name);
145         if (!attribute) {
146                 /* add entry with normalised RDN information if possible */
147                 if (a->name != NULL) {
148                         ret = ldb_msg_add_value(msg, a->name, &rdn_val, NULL);
149                 } else {
150                         ret = ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL);
151                 }
152                 if (ret != LDB_SUCCESS) {
153                         return ret;
154                 }
155         } else {
156                 /* normalise attribute name if possible */
157                 if (a->name != NULL) {
158                         attribute->name = a->name;
159                 }
160                 /* normalise attribute value */
161                 for (i = 0; i < attribute->num_values; i++) {
162                         bool matched;
163                         if (a->syntax->operator_fn) {
164                                 ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
165                                                              &rdn_val, &attribute->values[i], &matched);
166                                 if (ret != LDB_SUCCESS) return ret;
167                         } else {
168                                 matched = (a->syntax->comparison_fn(ldb, msg,
169                                                                     &rdn_val, &attribute->values[i]) == 0);
170                         }
171                         if (matched) {
172                                 /* overwrite so it matches in case */
173                                 attribute->values[i] = rdn_val;
174                                 break;
175                         }
176                 }
177                 if (i == attribute->num_values) {
178                         char *rdn_errstring = talloc_asprintf(ac,
179                                 "RDN mismatch on %s: %s (%.*s) should match one of:", 
180                                 ldb_dn_get_linearized(msg->dn), rdn_name, 
181                                 (int)rdn_val.length, (const char *)rdn_val.data);
182                         for (i = 0; i < attribute->num_values; i++) {
183                                 rdn_errstring = talloc_asprintf_append(
184                                         rdn_errstring, " (%.*s)",
185                                         (int)attribute->values[i].length, 
186                                         (const char *)attribute->values[i].data);
187                         }
188                         ldb_set_errstring(ldb, rdn_errstring);
189                         /* Match AD's error here */
190                         return LDB_ERR_INVALID_DN_SYNTAX;
191                 }
192         }
193
194         ret = ldb_build_add_req(&down_req, ldb, req,
195                                 msg,
196                                 req->controls,
197                                 ac, rdn_name_add_callback,
198                                 req);
199         if (ret != LDB_SUCCESS) {
200                 return ret;
201         }
202
203         talloc_steal(down_req, msg);
204
205         /* go on with the call chain */
206         return ldb_next_request(module, down_req);
207 }
208
209 static int rdn_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
210 {
211         struct rename_context *ac;
212
213         ac = talloc_get_type(req->context, struct rename_context);
214
215         if (!ares) {
216                 return ldb_module_done(ac->req, NULL, NULL,
217                                         LDB_ERR_OPERATIONS_ERROR);
218         }
219
220         if (ares->type == LDB_REPLY_REFERRAL) {
221                 return ldb_module_send_referral(ac->req, ares->referral);
222         }
223
224         if (ares->error != LDB_SUCCESS) {
225                 return ldb_module_done(ac->req, ares->controls,
226                                         ares->response, ares->error);
227         }
228
229         /* the only supported reply right now is a LDB_REPLY_DONE */
230         if (ares->type != LDB_REPLY_DONE) {
231                 return ldb_module_done(ac->req, NULL, NULL,
232                                         LDB_ERR_OPERATIONS_ERROR);
233         }
234
235         /* send saved controls eventually */
236         return ldb_module_done(ac->req, ac->ares->controls,
237                                 ac->ares->response, LDB_SUCCESS);
238 }
239
240 static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
241 {
242         struct ldb_context *ldb;
243         struct rename_context *ac;
244         struct ldb_request *mod_req;
245         const char *rdn_name;
246         const struct ldb_val *rdn_val_p;
247         struct ldb_val rdn_val;
248         struct ldb_message *msg;
249         int ret;
250
251         ac = talloc_get_type(req->context, struct rename_context);
252         ldb = ldb_module_get_ctx(ac->module);
253
254         if (!ares) {
255                 goto error;
256         }
257
258         if (ares->type == LDB_REPLY_REFERRAL) {
259                 return ldb_module_send_referral(ac->req, ares->referral);
260         }
261
262         if (ares->error != LDB_SUCCESS) {
263                 return ldb_module_done(ac->req, ares->controls,
264                                         ares->response, ares->error);
265         }
266
267         /* the only supported reply right now is a LDB_REPLY_DONE */
268         if (ares->type != LDB_REPLY_DONE) {
269                 goto error;
270         }
271
272         /* save reply for caller */
273         ac->ares = talloc_steal(ac, ares);
274
275         msg = ldb_msg_new(ac);
276         if (msg == NULL) {
277                 goto error;
278         }
279         msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn);
280         if (msg->dn == NULL) {
281                 goto error;
282         }
283
284         rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
285         if (rdn_name == NULL) {
286                 goto error;
287         }
288
289         rdn_val_p = ldb_dn_get_rdn_val(msg->dn);
290         if (rdn_val_p == NULL) {
291                 goto error;
292         }
293         if (rdn_val_p->length == 0) {
294                 ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
295                                        ldb_dn_get_linearized(req->op.rename.olddn));
296                 return ldb_module_done(ac->req, NULL, NULL,
297                                        LDB_ERR_NAMING_VIOLATION);
298         }
299         rdn_val = ldb_val_dup(msg, rdn_val_p);
300
301         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
302                 goto error;
303         }
304         if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
305                 goto error;
306         }
307         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
308                 goto error;
309         }
310         if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
311                 goto error;
312         }
313
314         ret = ldb_build_mod_req(&mod_req, ldb,
315                                 ac, msg, NULL,
316                                 ac, rdn_modify_callback,
317                                 req);
318         if (ret != LDB_SUCCESS) {
319                 return ldb_module_done(ac->req, NULL, NULL, ret);
320         }
321         talloc_steal(mod_req, msg);
322
323         /* go on with the call chain */
324         return ldb_next_request(ac->module, mod_req);
325
326 error:
327         return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
328 }
329
330 static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
331 {
332         struct ldb_context *ldb;
333         struct rename_context *ac;
334         struct ldb_request *down_req;
335         int ret;
336
337         ldb = ldb_module_get_ctx(module);
338
339         /* do not manipulate our control entries */
340         if (ldb_dn_is_special(req->op.rename.newdn)) {
341                 return ldb_next_request(module, req);
342         }
343
344         ac = talloc_zero(req, struct rename_context);
345         if (ac == NULL) {
346                 return LDB_ERR_OPERATIONS_ERROR;
347         }
348
349         ac->module = module;
350         ac->req = req;
351
352         ret = ldb_build_rename_req(&down_req,
353                                    ldb,
354                                    ac,
355                                    req->op.rename.olddn,
356                                    req->op.rename.newdn,
357                                    req->controls,
358                                    ac,
359                                    rdn_rename_callback,
360                                    req);
361
362         if (ret != LDB_SUCCESS) {
363                 return ret;
364         }
365
366         /* rename first, modify "name" if rename is ok */
367         return ldb_next_request(module, down_req);
368 }
369
370 static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
371 {
372         struct ldb_context *ldb;
373         const struct ldb_val *rdn_val_p;
374         struct ldb_message_element *e = NULL;
375
376         ldb = ldb_module_get_ctx(module);
377
378         /* do not manipulate our control entries */
379         if (ldb_dn_is_special(req->op.mod.message->dn)) {
380                 return ldb_next_request(module, req);
381         }
382
383         rdn_val_p = ldb_dn_get_rdn_val(req->op.mod.message->dn);
384         if (rdn_val_p == NULL) {
385                 return LDB_ERR_OPERATIONS_ERROR;
386         }
387         if (rdn_val_p->length == 0) {
388                 ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
389                                        ldb_dn_get_linearized(req->op.mod.message->dn));
390                 return LDB_ERR_INVALID_DN_SYNTAX;
391         }
392
393         e = ldb_msg_find_element(req->op.mod.message, "distinguishedName");
394         if (e != NULL) {
395                 ldb_asprintf_errstring(ldb, "Modify of 'distinguishedName' on %s not permitted, must use 'rename' operation instead",
396                                        ldb_dn_get_linearized(req->op.mod.message->dn));
397                 if (e->flags == LDB_FLAG_MOD_REPLACE) {
398                         return LDB_ERR_CONSTRAINT_VIOLATION;
399                 } else {
400                         return LDB_ERR_UNWILLING_TO_PERFORM;
401                 }
402         }
403
404         if (ldb_msg_find_element(req->op.mod.message, "name")) {
405                 ldb_asprintf_errstring(ldb, "Modify of 'name' on %s not permitted, must use 'rename' operation instead",
406                                        ldb_dn_get_linearized(req->op.mod.message->dn));
407                 return LDB_ERR_NOT_ALLOWED_ON_RDN;
408         }
409
410         if (ldb_msg_find_element(req->op.mod.message, ldb_dn_get_rdn_name(req->op.mod.message->dn))) {
411                 ldb_asprintf_errstring(ldb, "Modify of RDN '%s' on %s not permitted, must use 'rename' operation instead",
412                                        ldb_dn_get_rdn_name(req->op.mod.message->dn), ldb_dn_get_linearized(req->op.mod.message->dn));
413                 return LDB_ERR_NOT_ALLOWED_ON_RDN;
414         }
415
416         /* All OK, they kept their fingers out of the special attributes */
417         return ldb_next_request(module, req);
418 }
419
420 static int rdn_name_search(struct ldb_module *module, struct ldb_request *req)
421 {
422         struct ldb_context *ldb;
423         const char *rdn_name;
424         const struct ldb_val *rdn_val_p;
425
426         ldb = ldb_module_get_ctx(module);
427
428         /* do not manipulate our control entries */
429         if (ldb_dn_is_special(req->op.search.base)) {
430                 return ldb_next_request(module, req);
431         }
432
433         rdn_name = ldb_dn_get_rdn_name(req->op.search.base);
434         rdn_val_p = ldb_dn_get_rdn_val(req->op.search.base);
435         if ((rdn_name != NULL) && (rdn_val_p == NULL)) {
436                 return LDB_ERR_OPERATIONS_ERROR;
437         }
438         if ((rdn_val_p != NULL) && (rdn_val_p->length == 0)) {
439                 ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
440                                        ldb_dn_get_linearized(req->op.search.base));
441                 return LDB_ERR_INVALID_DN_SYNTAX;
442         }
443
444         return ldb_next_request(module, req);
445 }
446
447 static const struct ldb_module_ops ldb_rdn_name_module_ops = {
448         .name              = "rdn_name",
449         .add               = rdn_name_add,
450         .modify            = rdn_name_modify,
451         .rename            = rdn_name_rename,
452         .search            = rdn_name_search
453 };
454
455 int ldb_rdn_name_init(const char *version)
456 {
457         LDB_MODULE_CHECK_VERSION(version);
458         return ldb_register_module(&ldb_rdn_name_module_ops);
459 }