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
dsdb_dn_oid_to_format(const char * oid)28 enum dsdb_dn_format dsdb_dn_oid_to_format(const char *oid)
29 {
30 if (strcmp(oid, LDB_SYNTAX_DN) == 0) {
31 return DSDB_NORMAL_DN;
32 } else if (strcmp(oid, DSDB_SYNTAX_BINARY_DN) == 0) {
33 return DSDB_BINARY_DN;
34 } else if (strcmp(oid, DSDB_SYNTAX_STRING_DN) == 0) {
35 return DSDB_STRING_DN;
36 } else if (strcmp(oid, DSDB_SYNTAX_OR_NAME) == 0) {
37 return DSDB_NORMAL_DN;
38 } else {
39 return DSDB_INVALID_DN;
40 }
41 }
42
dsdb_dn_construct_internal(TALLOC_CTX * mem_ctx,struct ldb_dn * dn,DATA_BLOB extra_part,enum dsdb_dn_format dn_format,const char * oid)43 static struct dsdb_dn *dsdb_dn_construct_internal(TALLOC_CTX *mem_ctx,
44 struct ldb_dn *dn,
45 DATA_BLOB extra_part,
46 enum dsdb_dn_format dn_format,
47 const char *oid)
48 {
49 struct dsdb_dn *dsdb_dn = talloc(mem_ctx, struct dsdb_dn);
50 if (!dsdb_dn) {
51 return NULL;
52 }
53 dsdb_dn->dn = talloc_steal(dsdb_dn, dn);
54 dsdb_dn->extra_part = extra_part;
55 dsdb_dn->dn_format = dn_format;
56 /* Look to see if this attributeSyntax is a DN */
57 if (dsdb_dn->dn_format == DSDB_INVALID_DN) {
58 talloc_free(dsdb_dn);
59 return NULL;
60 }
61
62 dsdb_dn->oid = oid;
63 talloc_steal(dsdb_dn, extra_part.data);
64 return dsdb_dn;
65 }
66
dsdb_dn_construct(TALLOC_CTX * mem_ctx,struct ldb_dn * dn,DATA_BLOB extra_part,const char * oid)67 struct dsdb_dn *dsdb_dn_construct(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, DATA_BLOB extra_part,
68 const char *oid)
69 {
70 enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(oid);
71 return dsdb_dn_construct_internal(mem_ctx, dn, extra_part, dn_format, oid);
72 }
73
dsdb_dn_parse_trusted(TALLOC_CTX * mem_ctx,struct ldb_context * ldb,const struct ldb_val * dn_blob,const char * dn_oid)74 struct dsdb_dn *dsdb_dn_parse_trusted(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
75 const struct ldb_val *dn_blob, const char *dn_oid)
76 {
77 struct dsdb_dn *dsdb_dn;
78 struct ldb_dn *dn;
79 size_t len;
80 TALLOC_CTX *tmp_ctx;
81 char *p1;
82 char *p2;
83 uint32_t blen;
84 struct ldb_val bval;
85 struct ldb_val dval;
86 char *dn_str;
87 int error = 0;
88
89 enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(dn_oid);
90
91 if (dn_blob == NULL || dn_blob->data == NULL || dn_blob->length == 0) {
92 return NULL;
93 }
94
95 switch (dn_format) {
96 case DSDB_INVALID_DN:
97 return NULL;
98 case DSDB_NORMAL_DN:
99 {
100 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, dn_blob);
101 if (!dn) {
102 talloc_free(dn);
103 return NULL;
104 }
105 return dsdb_dn_construct_internal(mem_ctx, dn, data_blob_null, dn_format, dn_oid);
106 }
107 case DSDB_BINARY_DN:
108 if (dn_blob->length < 2 || dn_blob->data[0] != 'B' || dn_blob->data[1] != ':') {
109 return NULL;
110 }
111 break;
112 case DSDB_STRING_DN:
113 if (dn_blob->length < 2 || dn_blob->data[0] != 'S' || dn_blob->data[1] != ':') {
114 return NULL;
115 }
116 break;
117 default:
118 return NULL;
119 }
120
121 if (strlen((const char*)dn_blob->data) != dn_blob->length) {
122 /* The RDN must not contain a character with value 0x0 */
123 return NULL;
124 }
125
126 tmp_ctx = talloc_new(mem_ctx);
127 if (tmp_ctx == NULL) {
128 return NULL;
129 }
130
131 len = dn_blob->length - 2;
132 p1 = talloc_strndup(tmp_ctx, (const char *)dn_blob->data + 2, len);
133 if (!p1) {
134 goto failed;
135 }
136
137 errno = 0;
138 blen = smb_strtoul(p1, &p2, 10, &error, SMB_STR_STANDARD);
139 if (error != 0) {
140 DEBUG(10, (__location__ ": failed\n"));
141 goto failed;
142 }
143 if (p2 == NULL) {
144 DEBUG(10, (__location__ ": failed\n"));
145 goto failed;
146 }
147 if (p2[0] != ':') {
148 DEBUG(10, (__location__ ": failed\n"));
149 goto failed;
150 }
151 len -= PTR_DIFF(p2,p1);//???
152 p1 = p2+1;
153 len--;
154
155 if (blen >= len) {
156 DEBUG(10, (__location__ ": blen=%u len=%u\n", (unsigned)blen, (unsigned)len));
157 goto failed;
158 }
159
160 p2 = p1 + blen;
161 if (p2[0] != ':') {
162 DEBUG(10, (__location__ ": %s", p2));
163 goto failed;
164 }
165 dn_str = p2+1;
166
167
168 switch (dn_format) {
169 case DSDB_BINARY_DN:
170 if ((blen % 2 != 0)) {
171 DEBUG(10, (__location__ ": blen=%u - not an even number\n", (unsigned)blen));
172 goto failed;
173 }
174
175 if (blen >= 2) {
176 bval.length = (blen/2)+1;
177 bval.data = talloc_size(tmp_ctx, bval.length);
178 if (bval.data == NULL) {
179 DEBUG(10, (__location__ ": err\n"));
180 goto failed;
181 }
182 bval.data[bval.length-1] = 0;
183
184 bval.length = strhex_to_str((char *)bval.data, bval.length,
185 p1, blen);
186 if (bval.length != (blen / 2)) {
187 DEBUG(10, (__location__ ": non hexadecimal characters found in binary prefix\n"));
188 goto failed;
189 }
190 } else {
191 bval = data_blob_null;
192 }
193
194 break;
195 case DSDB_STRING_DN:
196 bval = data_blob(p1, blen);
197 break;
198 default:
199 /* never reached */
200 return NULL;
201 }
202
203
204 dval.data = (uint8_t *)dn_str;
205 dval.length = strlen(dn_str);
206
207 dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &dval);
208 if (!dn) {
209 DEBUG(10, (__location__ ": err\n"));
210 goto failed;
211 }
212
213 dsdb_dn = dsdb_dn_construct(mem_ctx, dn, bval, dn_oid);
214
215 talloc_free(tmp_ctx);
216 return dsdb_dn;
217
218 failed:
219 talloc_free(tmp_ctx);
220 return NULL;
221 }
222
dsdb_dn_parse(TALLOC_CTX * mem_ctx,struct ldb_context * ldb,const struct ldb_val * dn_blob,const char * dn_oid)223 struct dsdb_dn *dsdb_dn_parse(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
224 const struct ldb_val *dn_blob, const char *dn_oid)
225 {
226 struct dsdb_dn *dsdb_dn = dsdb_dn_parse_trusted(mem_ctx, ldb,
227 dn_blob, dn_oid);
228 if (dsdb_dn == NULL) {
229 return NULL;
230 }
231 if (ldb_dn_validate(dsdb_dn->dn) == false) {
232 DEBUG(10, ("could not parse %.*s as a %s DN",
233 (int)dn_blob->length, dn_blob->data,
234 dn_oid));
235 return NULL;
236 }
237 return dsdb_dn;
238 }
239
dsdb_dn_get_with_postfix(TALLOC_CTX * mem_ctx,struct dsdb_dn * dsdb_dn,const char * postfix)240 static char *dsdb_dn_get_with_postfix(TALLOC_CTX *mem_ctx,
241 struct dsdb_dn *dsdb_dn,
242 const char *postfix)
243 {
244 if (!postfix) {
245 return NULL;
246 }
247
248 switch (dsdb_dn->dn_format) {
249 case DSDB_NORMAL_DN:
250 {
251 return talloc_strdup(mem_ctx, postfix);
252 }
253 case DSDB_BINARY_DN:
254 {
255 char *hexstr = data_blob_hex_string_upper(mem_ctx, &dsdb_dn->extra_part);
256
257 char *p = talloc_asprintf(mem_ctx, "B:%u:%s:%s", (unsigned)(dsdb_dn->extra_part.length*2), hexstr,
258 postfix);
259 talloc_free(hexstr);
260 return p;
261 }
262 case DSDB_STRING_DN:
263 {
264 return talloc_asprintf(mem_ctx, "S:%u:%*.*s:%s",
265 (unsigned)(dsdb_dn->extra_part.length),
266 (int)(dsdb_dn->extra_part.length),
267 (int)(dsdb_dn->extra_part.length),
268 (const char *)dsdb_dn->extra_part.data,
269 postfix);
270 }
271 default:
272 return NULL;
273 }
274 }
275
dsdb_dn_get_linearized(TALLOC_CTX * mem_ctx,struct dsdb_dn * dsdb_dn)276 char *dsdb_dn_get_linearized(TALLOC_CTX *mem_ctx,
277 struct dsdb_dn *dsdb_dn)
278 {
279 const char *postfix = ldb_dn_get_linearized(dsdb_dn->dn);
280 return dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
281 }
282
dsdb_dn_get_casefold(TALLOC_CTX * mem_ctx,struct dsdb_dn * dsdb_dn)283 char *dsdb_dn_get_casefold(TALLOC_CTX *mem_ctx,
284 struct dsdb_dn *dsdb_dn)
285 {
286 const char *postfix = ldb_dn_get_casefold(dsdb_dn->dn);
287 return dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
288 }
289
dsdb_dn_get_extended_linearized(TALLOC_CTX * mem_ctx,struct dsdb_dn * dsdb_dn,int mode)290 char *dsdb_dn_get_extended_linearized(TALLOC_CTX *mem_ctx,
291 struct dsdb_dn *dsdb_dn,
292 int mode)
293 {
294 char *postfix = ldb_dn_get_extended_linearized(mem_ctx, dsdb_dn->dn, mode);
295 char *ret = dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
296 talloc_free(postfix);
297 return ret;
298 }
299
dsdb_dn_binary_canonicalise(struct ldb_context * ldb,void * mem_ctx,const struct ldb_val * in,struct ldb_val * out)300 int dsdb_dn_binary_canonicalise(struct ldb_context *ldb, void *mem_ctx,
301 const struct ldb_val *in, struct ldb_val *out)
302 {
303 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_BINARY_DN);
304
305 if (!dsdb_dn) {
306 return -1;
307 }
308 *out = data_blob_string_const(dsdb_dn_get_casefold(mem_ctx, dsdb_dn));
309 talloc_free(dsdb_dn);
310 if (!out->data) {
311 return -1;
312 }
313 return 0;
314 }
315
dsdb_dn_binary_comparison(struct ldb_context * ldb,void * mem_ctx,const struct ldb_val * v1,const struct ldb_val * v2)316 int dsdb_dn_binary_comparison(struct ldb_context *ldb, void *mem_ctx,
317 const struct ldb_val *v1,
318 const struct ldb_val *v2)
319 {
320 return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_binary_canonicalise, v1, v2);
321 }
322
dsdb_dn_string_canonicalise(struct ldb_context * ldb,void * mem_ctx,const struct ldb_val * in,struct ldb_val * out)323 int dsdb_dn_string_canonicalise(struct ldb_context *ldb, void *mem_ctx,
324 const struct ldb_val *in, struct ldb_val *out)
325 {
326 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_STRING_DN);
327
328 if (!dsdb_dn) {
329 return -1;
330 }
331 *out = data_blob_string_const(dsdb_dn_get_casefold(mem_ctx, dsdb_dn));
332 talloc_free(dsdb_dn);
333 if (!out->data) {
334 return -1;
335 }
336 return 0;
337 }
338
dsdb_dn_string_comparison(struct ldb_context * ldb,void * mem_ctx,const struct ldb_val * v1,const struct ldb_val * v2)339 int dsdb_dn_string_comparison(struct ldb_context *ldb, void *mem_ctx,
340 const struct ldb_val *v1,
341 const struct ldb_val *v2)
342 {
343 return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_string_canonicalise, v1, v2);
344 }
345
346 /*
347 format a drsuapi_DsReplicaObjectIdentifier naming context as a string
348 */
drs_ObjectIdentifier_to_string(TALLOC_CTX * mem_ctx,struct drsuapi_DsReplicaObjectIdentifier * nc)349 char *drs_ObjectIdentifier_to_string(TALLOC_CTX *mem_ctx,
350 struct drsuapi_DsReplicaObjectIdentifier *nc)
351 {
352 char *ret = NULL;
353 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
354 if (!GUID_all_zero(&nc->guid)) {
355 char *guid = GUID_string(tmp_ctx, &nc->guid);
356 if (guid) {
357 ret = talloc_asprintf_append(ret, "<GUID=%s>;", guid);
358 }
359 }
360 if (nc->__ndr_size_sid != 0 && nc->sid.sid_rev_num != 0) {
361 const char *sid = dom_sid_string(tmp_ctx, &nc->sid);
362 if (sid) {
363 ret = talloc_asprintf_append(ret, "<SID=%s>;", sid);
364 }
365 }
366 if (nc->__ndr_size_dn != 0 && nc->dn) {
367 ret = talloc_asprintf_append(ret, "%s", nc->dn);
368 }
369 talloc_free(tmp_ctx);
370 talloc_steal(mem_ctx, ret);
371 return ret;
372 }
373
drs_ObjectIdentifier_to_dn(TALLOC_CTX * mem_ctx,struct ldb_context * ldb,struct drsuapi_DsReplicaObjectIdentifier * nc)374 struct ldb_dn *drs_ObjectIdentifier_to_dn(TALLOC_CTX *mem_ctx,
375 struct ldb_context *ldb,
376 struct drsuapi_DsReplicaObjectIdentifier *nc)
377 {
378 char *dn_string = drs_ObjectIdentifier_to_string(mem_ctx, nc);
379 struct ldb_dn *new_dn;
380 new_dn = ldb_dn_new(mem_ctx, ldb, dn_string);
381 talloc_free(dn_string);
382 return new_dn;
383 }
384