Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba utility functions
4 :
5 : Copyright (C) Andrew Tridgell 2009
6 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
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"
28 :
29 73491772 : enum dsdb_dn_format dsdb_dn_oid_to_format(const char *oid)
30 : {
31 73491772 : if (strcmp(oid, LDB_SYNTAX_DN) == 0) {
32 17559748 : return DSDB_NORMAL_DN;
33 55340375 : } else if (strcmp(oid, DSDB_SYNTAX_BINARY_DN) == 0) {
34 20854573 : return DSDB_BINARY_DN;
35 34457075 : } else if (strcmp(oid, DSDB_SYNTAX_STRING_DN) == 0) {
36 28147 : return DSDB_STRING_DN;
37 34428565 : } else if (strcmp(oid, DSDB_SYNTAX_OR_NAME) == 0) {
38 0 : return DSDB_NORMAL_DN;
39 : } else {
40 34428561 : return DSDB_INVALID_DN;
41 : }
42 : }
43 :
44 23401424 : 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)
49 : {
50 23401424 : struct dsdb_dn *dsdb_dn = NULL;
51 :
52 23401424 : switch (dn_format) {
53 10296311 : case DSDB_BINARY_DN:
54 : case DSDB_STRING_DN:
55 10296311 : break;
56 13092230 : case DSDB_NORMAL_DN:
57 13092230 : if (extra_part.length != 0) {
58 0 : errno = EINVAL;
59 0 : return NULL;
60 : }
61 12563888 : break;
62 0 : case DSDB_INVALID_DN:
63 : default:
64 0 : errno = EINVAL;
65 0 : return NULL;
66 : }
67 :
68 23401424 : dsdb_dn = talloc(mem_ctx, struct dsdb_dn);
69 23401424 : if (!dsdb_dn) {
70 0 : errno = ENOMEM;
71 0 : return NULL;
72 : }
73 23401424 : dsdb_dn->dn = talloc_steal(dsdb_dn, dn);
74 23401424 : dsdb_dn->extra_part = extra_part;
75 23401424 : dsdb_dn->dn_format = dn_format;
76 :
77 23401424 : dsdb_dn->oid = oid;
78 23401424 : talloc_steal(dsdb_dn, extra_part.data);
79 23401424 : return dsdb_dn;
80 : }
81 :
82 10451579 : struct dsdb_dn *dsdb_dn_construct(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, DATA_BLOB extra_part,
83 : const char *oid)
84 : {
85 10451579 : enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(oid);
86 10451579 : return dsdb_dn_construct_internal(mem_ctx, dn, extra_part, dn_format, oid);
87 : }
88 :
89 23227568 : 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)
91 : {
92 535378 : struct dsdb_dn *dsdb_dn;
93 535378 : struct ldb_dn *dn;
94 535378 : size_t len;
95 535378 : TALLOC_CTX *tmp_ctx;
96 535378 : char *p1;
97 535378 : char *p2;
98 535378 : uint32_t blen;
99 535378 : struct ldb_val bval;
100 535378 : struct ldb_val dval;
101 535378 : char *dn_str;
102 23227568 : int error = 0;
103 :
104 23227568 : enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(dn_oid);
105 :
106 23227568 : if (dn_blob == NULL || dn_blob->data == NULL || dn_blob->length == 0) {
107 1 : return NULL;
108 : }
109 :
110 23227567 : switch (dn_format) {
111 0 : case DSDB_INVALID_DN:
112 0 : return NULL;
113 12949846 : case DSDB_NORMAL_DN:
114 : {
115 12949846 : dn = ldb_dn_from_ldb_val(mem_ctx, ldb, dn_blob);
116 12949846 : if (!dn) {
117 1 : talloc_free(dn);
118 1 : return NULL;
119 : }
120 12949845 : return dsdb_dn_construct_internal(mem_ctx, dn, data_blob_null, dn_format, dn_oid);
121 : }
122 10277709 : case DSDB_BINARY_DN:
123 10277709 : if (dn_blob->length < 2 || dn_blob->data[0] != 'B' || dn_blob->data[1] != ':') {
124 11 : return NULL;
125 : }
126 10265474 : break;
127 12 : case DSDB_STRING_DN:
128 12 : if (dn_blob->length < 2 || dn_blob->data[0] != 'S' || dn_blob->data[1] != ':') {
129 0 : return NULL;
130 : }
131 0 : break;
132 0 : default:
133 0 : return NULL;
134 : }
135 :
136 10277707 : if (strlen((const char*)dn_blob->data) != dn_blob->length) {
137 : /* The RDN must not contain a character with value 0x0 */
138 0 : return NULL;
139 : }
140 :
141 10277706 : tmp_ctx = talloc_new(mem_ctx);
142 10277706 : if (tmp_ctx == NULL) {
143 0 : return NULL;
144 : }
145 :
146 10277706 : len = dn_blob->length - 2;
147 10277706 : p1 = talloc_strndup(tmp_ctx, (const char *)dn_blob->data + 2, len);
148 10277706 : if (!p1) {
149 0 : goto failed;
150 : }
151 :
152 10277706 : errno = 0;
153 10277706 : blen = smb_strtoul(p1, &p2, 10, &error, SMB_STR_STANDARD);
154 10277706 : if (error != 0) {
155 0 : DEBUG(10, (__location__ ": failed\n"));
156 0 : goto failed;
157 : }
158 10277706 : if (p2 == NULL) {
159 0 : DEBUG(10, (__location__ ": failed\n"));
160 0 : goto failed;
161 : }
162 10277706 : if (p2[0] != ':') {
163 0 : DEBUG(10, (__location__ ": failed\n"));
164 0 : goto failed;
165 : }
166 10277706 : len -= PTR_DIFF(p2,p1);//???
167 10277706 : p1 = p2+1;
168 10277706 : len--;
169 :
170 10277706 : if (blen >= len) {
171 12 : DEBUG(10, (__location__ ": blen=%u len=%u\n", (unsigned)blen, (unsigned)len));
172 12 : goto failed;
173 : }
174 :
175 10277694 : p2 = p1 + blen;
176 10277694 : if (p2[0] != ':') {
177 6 : DEBUG(10, (__location__ ": %s", p2));
178 6 : goto failed;
179 : }
180 10277688 : dn_str = p2+1;
181 :
182 :
183 10277688 : switch (dn_format) {
184 10277679 : case DSDB_BINARY_DN:
185 10277679 : if ((blen % 2 != 0)) {
186 0 : DEBUG(10, (__location__ ": blen=%u - not an even number\n", (unsigned)blen));
187 0 : goto failed;
188 : }
189 :
190 10277679 : if (blen >= 2) {
191 10277678 : bval.length = (blen/2)+1;
192 10277678 : bval.data = talloc_size(tmp_ctx, bval.length);
193 10277678 : if (bval.data == NULL) {
194 0 : DEBUG(10, (__location__ ": err\n"));
195 0 : goto failed;
196 : }
197 10277678 : bval.data[bval.length-1] = 0;
198 :
199 10277678 : bval.length = strhex_to_str((char *)bval.data, bval.length,
200 : p1, blen);
201 10277678 : if (bval.length != (blen / 2)) {
202 2 : DEBUG(10, (__location__ ": non hexadecimal characters found in binary prefix\n"));
203 2 : goto failed;
204 : }
205 : } else {
206 1 : bval = data_blob_null;
207 : }
208 :
209 10265463 : break;
210 9 : case DSDB_STRING_DN:
211 9 : bval = data_blob(p1, blen);
212 9 : break;
213 0 : default:
214 : /* never reached */
215 0 : return NULL;
216 : }
217 :
218 :
219 10277686 : dval.data = (uint8_t *)dn_str;
220 10277686 : dval.length = strlen(dn_str);
221 :
222 10277686 : dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &dval);
223 10277686 : if (!dn) {
224 0 : DEBUG(10, (__location__ ": err\n"));
225 0 : goto failed;
226 : }
227 :
228 10277686 : dsdb_dn = dsdb_dn_construct(mem_ctx, dn, bval, dn_oid);
229 :
230 10277686 : talloc_free(tmp_ctx);
231 10277686 : return dsdb_dn;
232 :
233 20 : failed:
234 20 : talloc_free(tmp_ctx);
235 20 : return NULL;
236 : }
237 :
238 1400118 : 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)
240 : {
241 1400118 : struct dsdb_dn *dsdb_dn = dsdb_dn_parse_trusted(mem_ctx, ldb,
242 : dn_blob, dn_oid);
243 1400118 : if (dsdb_dn == NULL) {
244 23 : return NULL;
245 : }
246 1400081 : if (ldb_dn_validate(dsdb_dn->dn) == false) {
247 15 : DEBUG(10, ("could not parse %.*s as a %s DN\n",
248 : (int)dn_blob->length, dn_blob->data,
249 : dn_oid));
250 15 : return NULL;
251 : }
252 1278825 : return dsdb_dn;
253 : }
254 :
255 21668758 : static char *dsdb_dn_get_with_postfix(TALLOC_CTX *mem_ctx,
256 : struct dsdb_dn *dsdb_dn,
257 : const char *postfix)
258 : {
259 21668758 : if (!postfix) {
260 0 : return NULL;
261 : }
262 :
263 21668758 : switch (dsdb_dn->dn_format) {
264 11758128 : case DSDB_NORMAL_DN:
265 : {
266 11758128 : return talloc_strdup(mem_ctx, postfix);
267 : }
268 9910616 : case DSDB_BINARY_DN:
269 : {
270 9910616 : char *hexstr = data_blob_hex_string_upper(mem_ctx, &dsdb_dn->extra_part);
271 :
272 9910616 : char *p = talloc_asprintf(mem_ctx, "B:%u:%s:%s", (unsigned)(dsdb_dn->extra_part.length*2), hexstr,
273 : postfix);
274 9910616 : talloc_free(hexstr);
275 9910616 : return p;
276 : }
277 14 : case DSDB_STRING_DN:
278 : {
279 14 : return talloc_asprintf(mem_ctx, "S:%u:%*.*s:%s",
280 0 : (unsigned)(dsdb_dn->extra_part.length),
281 0 : (int)(dsdb_dn->extra_part.length),
282 14 : (int)(dsdb_dn->extra_part.length),
283 14 : (const char *)dsdb_dn->extra_part.data,
284 : postfix);
285 : }
286 0 : default:
287 0 : return NULL;
288 : }
289 : }
290 :
291 4856833 : char *dsdb_dn_get_linearized(TALLOC_CTX *mem_ctx,
292 : struct dsdb_dn *dsdb_dn)
293 : {
294 4856833 : const char *postfix = ldb_dn_get_linearized(dsdb_dn->dn);
295 4856833 : return dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
296 : }
297 :
298 1138 : char *dsdb_dn_get_casefold(TALLOC_CTX *mem_ctx,
299 : struct dsdb_dn *dsdb_dn)
300 : {
301 1138 : const char *postfix = ldb_dn_get_casefold(dsdb_dn->dn);
302 1138 : return dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
303 : }
304 :
305 16810787 : char *dsdb_dn_get_extended_linearized(TALLOC_CTX *mem_ctx,
306 : struct dsdb_dn *dsdb_dn,
307 : int mode)
308 : {
309 16810787 : char *postfix = ldb_dn_get_extended_linearized(mem_ctx, dsdb_dn->dn, mode);
310 16810787 : char *ret = dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
311 16810787 : talloc_free(postfix);
312 16810787 : return ret;
313 : }
314 :
315 1147 : int dsdb_dn_binary_canonicalise(struct ldb_context *ldb, void *mem_ctx,
316 : const struct ldb_val *in, struct ldb_val *out)
317 : {
318 1147 : struct dsdb_dn *dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_BINARY_DN);
319 :
320 1147 : if (!dsdb_dn) {
321 22 : return -1;
322 : }
323 1124 : *out = data_blob_string_const(dsdb_dn_get_casefold(mem_ctx, dsdb_dn));
324 1124 : talloc_free(dsdb_dn);
325 1124 : if (!out->data) {
326 0 : return -1;
327 : }
328 1110 : return 0;
329 : }
330 :
331 403 : int dsdb_dn_binary_comparison(struct ldb_context *ldb, void *mem_ctx,
332 : const struct ldb_val *v1,
333 : const struct ldb_val *v2)
334 : {
335 403 : return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_binary_canonicalise, v1, v2);
336 : }
337 :
338 9 : int dsdb_dn_string_canonicalise(struct ldb_context *ldb, void *mem_ctx,
339 : const struct ldb_val *in, struct ldb_val *out)
340 : {
341 9 : struct dsdb_dn *dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_STRING_DN);
342 :
343 9 : if (!dsdb_dn) {
344 0 : return -1;
345 : }
346 8 : *out = data_blob_string_const(dsdb_dn_get_casefold(mem_ctx, dsdb_dn));
347 8 : talloc_free(dsdb_dn);
348 8 : if (!out->data) {
349 0 : return -1;
350 : }
351 0 : return 0;
352 : }
353 :
354 4 : int dsdb_dn_string_comparison(struct ldb_context *ldb, void *mem_ctx,
355 : const struct ldb_val *v1,
356 : const struct ldb_val *v2)
357 : {
358 4 : return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_string_canonicalise, v1, v2);
359 : }
360 :
361 : /*
362 : * format a drsuapi_DsReplicaObjectIdentifier naming context as a string for debugging
363 : *
364 : * When forming a DN for DB access you must use drs_ObjectIdentifier_to_dn()
365 : */
366 8 : char *drs_ObjectIdentifier_to_debug_string(TALLOC_CTX *mem_ctx,
367 : struct drsuapi_DsReplicaObjectIdentifier *nc)
368 : {
369 8 : char *ret = NULL;
370 8 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
371 8 : if (!GUID_all_zero(&nc->guid)) {
372 0 : char *guid = GUID_string(tmp_ctx, &nc->guid);
373 0 : if (guid) {
374 0 : ret = talloc_asprintf_append(ret, "<GUID=%s>;", guid);
375 : }
376 : }
377 8 : if (nc->__ndr_size_sid != 0 && nc->sid.sid_rev_num != 0) {
378 0 : const char *sid = dom_sid_string(tmp_ctx, &nc->sid);
379 0 : if (sid) {
380 0 : ret = talloc_asprintf_append(ret, "<SID=%s>;", sid);
381 : }
382 : }
383 8 : if (nc->__ndr_size_dn != 0 && nc->dn) {
384 8 : ret = talloc_asprintf_append(ret, "%s", nc->dn);
385 : }
386 8 : talloc_free(tmp_ctx);
387 8 : talloc_steal(mem_ctx, ret);
388 8 : return ret;
389 : }
390 :
391 : /*
392 : * Safely convert a drsuapi_DsReplicaObjectIdentifier into an LDB DN
393 : *
394 : * We need to have GUID and SID priority and not allow extended
395 : * components in the DN.
396 : *
397 : * We must also totally honour the priority even if the string DN is not valid or able to parse as a DN.
398 : */
399 35618 : static struct ldb_dn *drs_ObjectIdentifier_to_dn(TALLOC_CTX *mem_ctx,
400 : struct ldb_context *ldb,
401 : struct drsuapi_DsReplicaObjectIdentifier *nc)
402 : {
403 35618 : struct ldb_dn *new_dn = NULL;
404 :
405 35618 : if (!GUID_all_zero(&nc->guid)) {
406 0 : struct GUID_txt_buf buf;
407 15302 : char *guid = GUID_buf_string(&nc->guid, &buf);
408 :
409 15302 : new_dn = ldb_dn_new_fmt(mem_ctx,
410 : ldb,
411 : "<GUID=%s>",
412 : guid);
413 15302 : if (new_dn == NULL) {
414 0 : DBG_ERR("Failed to prepare drs_ObjectIdentifier "
415 : "GUID %s into a DN\n",
416 : guid);
417 0 : return NULL;
418 : }
419 :
420 15302 : return new_dn;
421 : }
422 :
423 20316 : if (nc->__ndr_size_sid != 0 && nc->sid.sid_rev_num != 0) {
424 0 : struct dom_sid_buf buf;
425 0 : char *sid = dom_sid_str_buf(&nc->sid, &buf);
426 :
427 0 : new_dn = ldb_dn_new_fmt(mem_ctx,
428 : ldb,
429 : "<SID=%s>",
430 : sid);
431 0 : if (new_dn == NULL) {
432 0 : DBG_ERR("Failed to prepare drs_ObjectIdentifier "
433 : "SID %s into a DN\n",
434 : sid);
435 0 : return NULL;
436 : }
437 0 : return new_dn;
438 : }
439 :
440 20316 : if (nc->__ndr_size_dn != 0 && nc->dn) {
441 20316 : int dn_comp_num = 0;
442 20316 : bool new_dn_valid = false;
443 :
444 20316 : new_dn = ldb_dn_new(mem_ctx, ldb, nc->dn);
445 20316 : if (new_dn == NULL) {
446 : /* Set to WARNING as this is user-controlled, don't print the value into the logs */
447 0 : DBG_WARNING("Failed to parse string DN in "
448 : "drs_ObjectIdentifier into an LDB DN\n");
449 0 : return NULL;
450 : }
451 :
452 20316 : new_dn_valid = ldb_dn_validate(new_dn);
453 20316 : if (!new_dn_valid) {
454 : /*
455 : * Set to WARNING as this is user-controlled,
456 : * but can print the value into the logs as it
457 : * parsed a bit
458 : */
459 0 : 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 0 : return NULL;
463 : }
464 :
465 20316 : dn_comp_num = ldb_dn_get_comp_num(new_dn);
466 20316 : if (dn_comp_num <= 0) {
467 : /*
468 : * Set to WARNING as this is user-controlled,
469 : * but can print the value into the logs as it
470 : * parsed a bit
471 : */
472 0 : DBG_WARNING("DN [%s] in drs_ObjectIdentifier "
473 : "must have 1 or more components\n",
474 : ldb_dn_get_linearized(new_dn));
475 0 : return NULL;
476 : }
477 :
478 20316 : if (ldb_dn_is_special(new_dn)) {
479 : /*
480 : * Set to WARNING as this is user-controlled,
481 : * but can print the value into the logs as it
482 : * parsed a bit
483 : */
484 0 : 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 0 : return NULL;
489 : }
490 :
491 : /*
492 : * We want this just to be a string DN, extended
493 : * components are manually handled above
494 : */
495 20316 : if (ldb_dn_has_extended(new_dn)) {
496 : /*
497 : * Set to WARNING as this is user-controlled,
498 : * but can print the value into the logs as it
499 : * parsed a bit
500 : */
501 0 : 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 0 : return NULL;
511 : }
512 20316 : return new_dn;
513 : }
514 :
515 0 : 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 0 : return NULL;
520 : }
521 :
522 : /*
523 : * Safely convert a drsuapi_DsReplicaObjectIdentifier into a validated
524 : * LDB DN of an existing DB entry, and/or find the NC root
525 : *
526 : * We need to have GUID and SID priority and not allow extended
527 : * components in the DN.
528 : *
529 : * We must also totally honour the priority even if the string DN is
530 : * not valid or able to parse as a DN.
531 : *
532 : * Finally, we must return the DN as found in the DB, as otherwise a
533 : * subsequence ldb_dn_compare(dn, nc_root) will fail (as this is based
534 : * on the string components).
535 : */
536 35618 : 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)
541 : {
542 0 : int ret;
543 35618 : struct ldb_dn *new_dn = NULL;
544 :
545 35618 : new_dn = drs_ObjectIdentifier_to_dn(mem_ctx,
546 : ldb,
547 : nc);
548 35618 : if (new_dn == NULL) {
549 0 : return LDB_ERR_INVALID_DN_SYNTAX;
550 : }
551 :
552 35618 : ret = dsdb_normalise_dn_and_find_nc_root(ldb,
553 : mem_ctx,
554 : new_dn,
555 : normalised_dn,
556 : nc_root);
557 35618 : if (ret != LDB_SUCCESS) {
558 : /*
559 : * dsdb_normalise_dn_and_find_nc_root() sets LDB error
560 : * strings, and the functions it calls do also
561 : */
562 16 : 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));
567 : }
568 :
569 35618 : TALLOC_FREE(new_dn);
570 35618 : return ret;
571 : }
|