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/>.
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
;
40 return DSDB_INVALID_DN
;
44 static struct dsdb_dn
*dsdb_dn_construct_internal(TALLOC_CTX
*mem_ctx
,
47 enum dsdb_dn_format dn_format
,
50 struct dsdb_dn
*dsdb_dn
= NULL
;
57 if (extra_part
.length
!= 0) {
68 dsdb_dn
= talloc(mem_ctx
, struct dsdb_dn
);
73 dsdb_dn
->dn
= talloc_steal(dsdb_dn
, dn
);
74 dsdb_dn
->extra_part
= extra_part
;
75 dsdb_dn
->dn_format
= dn_format
;
78 talloc_steal(dsdb_dn
, extra_part
.data
);
82 struct dsdb_dn
*dsdb_dn_construct(TALLOC_CTX
*mem_ctx
, struct ldb_dn
*dn
, DATA_BLOB extra_part
,
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
;
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) {
111 case DSDB_INVALID_DN
:
115 dn
= ldb_dn_from_ldb_val(mem_ctx
, ldb
, dn_blob
);
120 return dsdb_dn_construct_internal(mem_ctx
, dn
, data_blob_null
, dn_format
, dn_oid
);
123 if (dn_blob
->length
< 2 || dn_blob
->data
[0] != 'B' || dn_blob
->data
[1] != ':') {
128 if (dn_blob
->length
< 2 || dn_blob
->data
[0] != 'S' || dn_blob
->data
[1] != ':') {
136 if (strlen((const char*)dn_blob
->data
) != dn_blob
->length
) {
137 /* The RDN must not contain a character with value 0x0 */
141 tmp_ctx
= talloc_new(mem_ctx
);
142 if (tmp_ctx
== NULL
) {
146 len
= dn_blob
->length
- 2;
147 p1
= talloc_strndup(tmp_ctx
, (const char *)dn_blob
->data
+ 2, len
);
153 blen
= smb_strtoul(p1
, &p2
, 10, &error
, SMB_STR_STANDARD
);
155 DEBUG(10, (__location__
": failed\n"));
159 DEBUG(10, (__location__
": failed\n"));
163 DEBUG(10, (__location__
": failed\n"));
166 len
-= PTR_DIFF(p2
,p1
);//???
171 DEBUG(10, (__location__
": blen=%u len=%u\n", (unsigned)blen
, (unsigned)len
));
177 DEBUG(10, (__location__
": %s", p2
));
185 if ((blen
% 2 != 0)) {
186 DEBUG(10, (__location__
": blen=%u - not an even number\n", (unsigned)blen
));
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"));
197 bval
.data
[bval
.length
-1] = 0;
199 bval
.length
= strhex_to_str((char *)bval
.data
, bval
.length
,
201 if (bval
.length
!= (blen
/ 2)) {
202 DEBUG(10, (__location__
": non hexadecimal characters found in binary prefix\n"));
206 bval
= data_blob_null
;
211 bval
= data_blob(p1
, blen
);
219 dval
.data
= (uint8_t *)dn_str
;
220 dval
.length
= strlen(dn_str
);
222 dn
= ldb_dn_from_ldb_val(tmp_ctx
, ldb
, &dval
);
224 DEBUG(10, (__location__
": err\n"));
228 dsdb_dn
= dsdb_dn_construct(mem_ctx
, dn
, bval
, dn_oid
);
230 talloc_free(tmp_ctx
);
234 talloc_free(tmp_ctx
);
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
,
243 if (dsdb_dn
== 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
,
255 static char *dsdb_dn_get_with_postfix(TALLOC_CTX
*mem_ctx
,
256 struct dsdb_dn
*dsdb_dn
,
263 switch (dsdb_dn
->dn_format
) {
266 return talloc_strdup(mem_ctx
, postfix
);
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
,
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
,
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
,
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
);
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
);
323 *out
= data_blob_string_const(dsdb_dn_get_casefold(mem_ctx
, dsdb_dn
));
324 talloc_free(dsdb_dn
);
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
);
346 *out
= data_blob_string_const(dsdb_dn_get_casefold(mem_ctx
, dsdb_dn
));
347 talloc_free(dsdb_dn
);
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
)
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
);
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
);
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
);
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
,
413 if (new_dn
== NULL
) {
414 DBG_ERR("Failed to prepare drs_ObjectIdentifier "
415 "GUID %s into a DN\n",
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
,
431 if (new_dn
== NULL
) {
432 DBG_ERR("Failed to prepare drs_ObjectIdentifier "
433 "SID %s into a DN\n",
440 if (nc
->__ndr_size_dn
!= 0 && nc
->dn
) {
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");
452 new_dn_valid
= ldb_dn_validate(new_dn
);
455 * Set to WARNING as this is user-controlled,
456 * but can print the value into the logs as it
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
));
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
472 DBG_WARNING("DN [%s] in drs_ObjectIdentifier "
473 "must have 1 or more components\n",
474 ldb_dn_get_linearized(new_dn
));
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
484 DBG_WARNING("New string DN [%s] in "
485 "drs_ObjectIdentifier is a "
487 ldb_dn_get_linearized(new_dn
));
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
501 DBG_WARNING("Refusing to parse New string DN [%s] in "
502 "drs_ObjectIdentifier as an "
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
,
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");
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
)
543 struct ldb_dn
*new_dn
= NULL
;
545 new_dn
= drs_ObjectIdentifier_to_dn(mem_ctx
,
548 if (new_dn
== NULL
) {
549 return LDB_ERR_INVALID_DN_SYNTAX
;
552 ret
= dsdb_normalise_dn_and_find_nc_root(ldb
,
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),