smbd: use metadata_fsp(fsp) in copy_access_posix_acl() for SMB_VFS_SYS_ACL_SET_FD
[Samba.git] / source4 / dsdb / common / dsdb_dn.c
blob9886d831488d4803546e99fdb9d541749e76e4eb
1 /*
2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2009
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "dsdb/samdb/samdb.h"
24 #include <ldb_module.h>
25 #include "librpc/ndr/libndr.h"
26 #include "libcli/security/dom_sid.h"
27 #include "lib/util/smb_strtox.h"
29 enum dsdb_dn_format dsdb_dn_oid_to_format(const char *oid)
31 if (strcmp(oid, LDB_SYNTAX_DN) == 0) {
32 return DSDB_NORMAL_DN;
33 } else if (strcmp(oid, DSDB_SYNTAX_BINARY_DN) == 0) {
34 return DSDB_BINARY_DN;
35 } else if (strcmp(oid, DSDB_SYNTAX_STRING_DN) == 0) {
36 return DSDB_STRING_DN;
37 } else if (strcmp(oid, DSDB_SYNTAX_OR_NAME) == 0) {
38 return DSDB_NORMAL_DN;
39 } else {
40 return DSDB_INVALID_DN;
44 static struct dsdb_dn *dsdb_dn_construct_internal(TALLOC_CTX *mem_ctx,
45 struct ldb_dn *dn,
46 DATA_BLOB extra_part,
47 enum dsdb_dn_format dn_format,
48 const char *oid)
50 struct dsdb_dn *dsdb_dn = NULL;
52 switch (dn_format) {
53 case DSDB_BINARY_DN:
54 case DSDB_STRING_DN:
55 break;
56 case DSDB_NORMAL_DN:
57 if (extra_part.length != 0) {
58 errno = EINVAL;
59 return NULL;
61 break;
62 case DSDB_INVALID_DN:
63 default:
64 errno = EINVAL;
65 return NULL;
68 dsdb_dn = talloc(mem_ctx, struct dsdb_dn);
69 if (!dsdb_dn) {
70 errno = ENOMEM;
71 return NULL;
73 dsdb_dn->dn = talloc_steal(dsdb_dn, dn);
74 dsdb_dn->extra_part = extra_part;
75 dsdb_dn->dn_format = dn_format;
77 dsdb_dn->oid = oid;
78 talloc_steal(dsdb_dn, extra_part.data);
79 return dsdb_dn;
82 struct dsdb_dn *dsdb_dn_construct(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, DATA_BLOB extra_part,
83 const char *oid)
85 enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(oid);
86 return dsdb_dn_construct_internal(mem_ctx, dn, extra_part, dn_format, oid);
89 struct dsdb_dn *dsdb_dn_parse_trusted(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
90 const struct ldb_val *dn_blob, const char *dn_oid)
92 struct dsdb_dn *dsdb_dn;
93 struct ldb_dn *dn;
94 size_t len;
95 TALLOC_CTX *tmp_ctx;
96 char *p1;
97 char *p2;
98 uint32_t blen;
99 struct ldb_val bval;
100 struct ldb_val dval;
101 char *dn_str;
102 int error = 0;
104 enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(dn_oid);
106 if (dn_blob == NULL || dn_blob->data == NULL || dn_blob->length == 0) {
107 return NULL;
110 switch (dn_format) {
111 case DSDB_INVALID_DN:
112 return NULL;
113 case DSDB_NORMAL_DN:
115 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, dn_blob);
116 if (!dn) {
117 talloc_free(dn);
118 return NULL;
120 return dsdb_dn_construct_internal(mem_ctx, dn, data_blob_null, dn_format, dn_oid);
122 case DSDB_BINARY_DN:
123 if (dn_blob->length < 2 || dn_blob->data[0] != 'B' || dn_blob->data[1] != ':') {
124 return NULL;
126 break;
127 case DSDB_STRING_DN:
128 if (dn_blob->length < 2 || dn_blob->data[0] != 'S' || dn_blob->data[1] != ':') {
129 return NULL;
131 break;
132 default:
133 return NULL;
136 if (strlen((const char*)dn_blob->data) != dn_blob->length) {
137 /* The RDN must not contain a character with value 0x0 */
138 return NULL;
141 tmp_ctx = talloc_new(mem_ctx);
142 if (tmp_ctx == NULL) {
143 return NULL;
146 len = dn_blob->length - 2;
147 p1 = talloc_strndup(tmp_ctx, (const char *)dn_blob->data + 2, len);
148 if (!p1) {
149 goto failed;
152 errno = 0;
153 blen = smb_strtoul(p1, &p2, 10, &error, SMB_STR_STANDARD);
154 if (error != 0) {
155 DEBUG(10, (__location__ ": failed\n"));
156 goto failed;
158 if (p2 == NULL) {
159 DEBUG(10, (__location__ ": failed\n"));
160 goto failed;
162 if (p2[0] != ':') {
163 DEBUG(10, (__location__ ": failed\n"));
164 goto failed;
166 len -= PTR_DIFF(p2,p1);//???
167 p1 = p2+1;
168 len--;
170 if (blen >= len) {
171 DEBUG(10, (__location__ ": blen=%u len=%u\n", (unsigned)blen, (unsigned)len));
172 goto failed;
175 p2 = p1 + blen;
176 if (p2[0] != ':') {
177 DEBUG(10, (__location__ ": %s", p2));
178 goto failed;
180 dn_str = p2+1;
183 switch (dn_format) {
184 case DSDB_BINARY_DN:
185 if ((blen % 2 != 0)) {
186 DEBUG(10, (__location__ ": blen=%u - not an even number\n", (unsigned)blen));
187 goto failed;
190 if (blen >= 2) {
191 bval.length = (blen/2)+1;
192 bval.data = talloc_size(tmp_ctx, bval.length);
193 if (bval.data == NULL) {
194 DEBUG(10, (__location__ ": err\n"));
195 goto failed;
197 bval.data[bval.length-1] = 0;
199 bval.length = strhex_to_str((char *)bval.data, bval.length,
200 p1, blen);
201 if (bval.length != (blen / 2)) {
202 DEBUG(10, (__location__ ": non hexadecimal characters found in binary prefix\n"));
203 goto failed;
205 } else {
206 bval = data_blob_null;
209 break;
210 case DSDB_STRING_DN:
211 bval = data_blob(p1, blen);
212 break;
213 default:
214 /* never reached */
215 return NULL;
219 dval.data = (uint8_t *)dn_str;
220 dval.length = strlen(dn_str);
222 dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &dval);
223 if (!dn) {
224 DEBUG(10, (__location__ ": err\n"));
225 goto failed;
228 dsdb_dn = dsdb_dn_construct(mem_ctx, dn, bval, dn_oid);
230 talloc_free(tmp_ctx);
231 return dsdb_dn;
233 failed:
234 talloc_free(tmp_ctx);
235 return NULL;
238 struct dsdb_dn *dsdb_dn_parse(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
239 const struct ldb_val *dn_blob, const char *dn_oid)
241 struct dsdb_dn *dsdb_dn = dsdb_dn_parse_trusted(mem_ctx, ldb,
242 dn_blob, dn_oid);
243 if (dsdb_dn == NULL) {
244 return NULL;
246 if (ldb_dn_validate(dsdb_dn->dn) == false) {
247 DEBUG(10, ("could not parse %.*s as a %s DN\n",
248 (int)dn_blob->length, dn_blob->data,
249 dn_oid));
250 return NULL;
252 return dsdb_dn;
255 static char *dsdb_dn_get_with_postfix(TALLOC_CTX *mem_ctx,
256 struct dsdb_dn *dsdb_dn,
257 const char *postfix)
259 if (!postfix) {
260 return NULL;
263 switch (dsdb_dn->dn_format) {
264 case DSDB_NORMAL_DN:
266 return talloc_strdup(mem_ctx, postfix);
268 case DSDB_BINARY_DN:
270 char *hexstr = data_blob_hex_string_upper(mem_ctx, &dsdb_dn->extra_part);
272 char *p = talloc_asprintf(mem_ctx, "B:%u:%s:%s", (unsigned)(dsdb_dn->extra_part.length*2), hexstr,
273 postfix);
274 talloc_free(hexstr);
275 return p;
277 case DSDB_STRING_DN:
279 return talloc_asprintf(mem_ctx, "S:%u:%*.*s:%s",
280 (unsigned)(dsdb_dn->extra_part.length),
281 (int)(dsdb_dn->extra_part.length),
282 (int)(dsdb_dn->extra_part.length),
283 (const char *)dsdb_dn->extra_part.data,
284 postfix);
286 default:
287 return NULL;
291 char *dsdb_dn_get_linearized(TALLOC_CTX *mem_ctx,
292 struct dsdb_dn *dsdb_dn)
294 const char *postfix = ldb_dn_get_linearized(dsdb_dn->dn);
295 return dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
298 char *dsdb_dn_get_casefold(TALLOC_CTX *mem_ctx,
299 struct dsdb_dn *dsdb_dn)
301 const char *postfix = ldb_dn_get_casefold(dsdb_dn->dn);
302 return dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
305 char *dsdb_dn_get_extended_linearized(TALLOC_CTX *mem_ctx,
306 struct dsdb_dn *dsdb_dn,
307 int mode)
309 char *postfix = ldb_dn_get_extended_linearized(mem_ctx, dsdb_dn->dn, mode);
310 char *ret = dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
311 talloc_free(postfix);
312 return ret;
315 int dsdb_dn_binary_canonicalise(struct ldb_context *ldb, void *mem_ctx,
316 const struct ldb_val *in, struct ldb_val *out)
318 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_BINARY_DN);
320 if (!dsdb_dn) {
321 return -1;
323 *out = data_blob_string_const(dsdb_dn_get_casefold(mem_ctx, dsdb_dn));
324 talloc_free(dsdb_dn);
325 if (!out->data) {
326 return -1;
328 return 0;
331 int dsdb_dn_binary_comparison(struct ldb_context *ldb, void *mem_ctx,
332 const struct ldb_val *v1,
333 const struct ldb_val *v2)
335 return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_binary_canonicalise, v1, v2);
338 int dsdb_dn_string_canonicalise(struct ldb_context *ldb, void *mem_ctx,
339 const struct ldb_val *in, struct ldb_val *out)
341 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_STRING_DN);
343 if (!dsdb_dn) {
344 return -1;
346 *out = data_blob_string_const(dsdb_dn_get_casefold(mem_ctx, dsdb_dn));
347 talloc_free(dsdb_dn);
348 if (!out->data) {
349 return -1;
351 return 0;
354 int dsdb_dn_string_comparison(struct ldb_context *ldb, void *mem_ctx,
355 const struct ldb_val *v1,
356 const struct ldb_val *v2)
358 return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_string_canonicalise, v1, v2);
362 * format a drsuapi_DsReplicaObjectIdentifier naming context as a string for debugging
364 * When forming a DN for DB access you must use drs_ObjectIdentifier_to_dn()
366 char *drs_ObjectIdentifier_to_debug_string(TALLOC_CTX *mem_ctx,
367 struct drsuapi_DsReplicaObjectIdentifier *nc)
369 char *ret = NULL;
370 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
371 if (!GUID_all_zero(&nc->guid)) {
372 char *guid = GUID_string(tmp_ctx, &nc->guid);
373 if (guid) {
374 ret = talloc_asprintf_append(ret, "<GUID=%s>;", guid);
377 if (nc->__ndr_size_sid != 0 && nc->sid.sid_rev_num != 0) {
378 const char *sid = dom_sid_string(tmp_ctx, &nc->sid);
379 if (sid) {
380 ret = talloc_asprintf_append(ret, "<SID=%s>;", sid);
383 if (nc->__ndr_size_dn != 0 && nc->dn) {
384 ret = talloc_asprintf_append(ret, "%s", nc->dn);
386 talloc_free(tmp_ctx);
387 talloc_steal(mem_ctx, ret);
388 return ret;
392 * Safely convert a drsuapi_DsReplicaObjectIdentifier into an LDB DN
394 * We need to have GUID and SID priority and not allow extended
395 * components in the DN.
397 * We must also totally honour the priority even if the string DN is not valid or able to parse as a DN.
399 static struct ldb_dn *drs_ObjectIdentifier_to_dn(TALLOC_CTX *mem_ctx,
400 struct ldb_context *ldb,
401 struct drsuapi_DsReplicaObjectIdentifier *nc)
403 struct ldb_dn *new_dn = NULL;
405 if (!GUID_all_zero(&nc->guid)) {
406 struct GUID_txt_buf buf;
407 char *guid = GUID_buf_string(&nc->guid, &buf);
409 new_dn = ldb_dn_new_fmt(mem_ctx,
410 ldb,
411 "<GUID=%s>",
412 guid);
413 if (new_dn == NULL) {
414 DBG_ERR("Failed to prepare drs_ObjectIdentifier "
415 "GUID %s into a DN\n",
416 guid);
417 return NULL;
420 return new_dn;
423 if (nc->__ndr_size_sid != 0 && nc->sid.sid_rev_num != 0) {
424 struct dom_sid_buf buf;
425 char *sid = dom_sid_str_buf(&nc->sid, &buf);
427 new_dn = ldb_dn_new_fmt(mem_ctx,
428 ldb,
429 "<SID=%s>",
430 sid);
431 if (new_dn == NULL) {
432 DBG_ERR("Failed to prepare drs_ObjectIdentifier "
433 "SID %s into a DN\n",
434 sid);
435 return NULL;
437 return new_dn;
440 if (nc->__ndr_size_dn != 0 && nc->dn) {
441 int dn_comp_num = 0;
442 bool new_dn_valid = false;
444 new_dn = ldb_dn_new(mem_ctx, ldb, nc->dn);
445 if (new_dn == NULL) {
446 /* Set to WARNING as this is user-controlled, don't print the value into the logs */
447 DBG_WARNING("Failed to parse string DN in "
448 "drs_ObjectIdentifier into an LDB DN\n");
449 return NULL;
452 new_dn_valid = ldb_dn_validate(new_dn);
453 if (!new_dn_valid) {
455 * Set to WARNING as this is user-controlled,
456 * but can print the value into the logs as it
457 * parsed a bit
459 DBG_WARNING("Failed to validate string DN [%s] in "
460 "drs_ObjectIdentifier as an LDB DN\n",
461 ldb_dn_get_linearized(new_dn));
462 return NULL;
465 dn_comp_num = ldb_dn_get_comp_num(new_dn);
466 if (dn_comp_num <= 0) {
468 * Set to WARNING as this is user-controlled,
469 * but can print the value into the logs as it
470 * parsed a bit
472 DBG_WARNING("DN [%s] in drs_ObjectIdentifier "
473 "must have 1 or more components\n",
474 ldb_dn_get_linearized(new_dn));
475 return NULL;
478 if (ldb_dn_is_special(new_dn)) {
480 * Set to WARNING as this is user-controlled,
481 * but can print the value into the logs as it
482 * parsed a bit
484 DBG_WARNING("New string DN [%s] in "
485 "drs_ObjectIdentifier is a "
486 "special LDB DN\n",
487 ldb_dn_get_linearized(new_dn));
488 return NULL;
492 * We want this just to be a string DN, extended
493 * components are manually handled above
495 if (ldb_dn_has_extended(new_dn)) {
497 * Set to WARNING as this is user-controlled,
498 * but can print the value into the logs as it
499 * parsed a bit
501 DBG_WARNING("Refusing to parse New string DN [%s] in "
502 "drs_ObjectIdentifier as an "
503 "extended LDB DN "
504 "(GUIDs and SIDs should be in the "
505 ".guid and .sid IDL elements, "
506 "not in the string\n",
507 ldb_dn_get_extended_linearized(mem_ctx,
508 new_dn,
509 1));
510 return NULL;
512 return new_dn;
515 DBG_WARNING("Refusing to parse empty string DN "
516 "(and no GUID or SID) "
517 "drs_ObjectIdentifier into a empty "
518 "(eg RootDSE) LDB DN\n");
519 return NULL;
523 * Safely convert a drsuapi_DsReplicaObjectIdentifier into a validated
524 * LDB DN of an existing DB entry, and/or find the NC root
526 * We need to have GUID and SID priority and not allow extended
527 * components in the DN.
529 * We must also totally honour the priority even if the string DN is
530 * not valid or able to parse as a DN.
532 * Finally, we must return the DN as found in the DB, as otherwise a
533 * subsequent ldb_dn_compare(dn, nc_root) will fail (as this is based
534 * on the string components).
536 int drs_ObjectIdentifier_to_dn_and_nc_root(TALLOC_CTX *mem_ctx,
537 struct ldb_context *ldb,
538 struct drsuapi_DsReplicaObjectIdentifier *nc,
539 struct ldb_dn **normalised_dn,
540 struct ldb_dn **nc_root)
542 int ret;
543 struct ldb_dn *new_dn = NULL;
545 new_dn = drs_ObjectIdentifier_to_dn(mem_ctx,
546 ldb,
547 nc);
548 if (new_dn == NULL) {
549 return LDB_ERR_INVALID_DN_SYNTAX;
552 ret = dsdb_normalise_dn_and_find_nc_root(ldb,
553 mem_ctx,
554 new_dn,
555 normalised_dn,
556 nc_root);
557 if (ret != LDB_SUCCESS) {
559 * dsdb_normalise_dn_and_find_nc_root() sets LDB error
560 * strings, and the functions it calls do also
562 DBG_NOTICE("Failed to find DN \"%s\" -> \"%s\" for normalisation: %s (%s)\n",
563 drs_ObjectIdentifier_to_debug_string(mem_ctx, nc),
564 ldb_dn_get_extended_linearized(mem_ctx, new_dn, 1),
565 ldb_errstring(ldb),
566 ldb_strerror(ret));
569 TALLOC_FREE(new_dn);
570 return ret;