Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : CLDAP server - netlogon handling
5 :
6 : Copyright (C) Andrew Tridgell 2005
7 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include <ldb.h>
25 : #include <ldb_errors.h>
26 : #include "lib/events/events.h"
27 : #include "samba/service_task.h"
28 : #include "librpc/gen_ndr/ndr_misc.h"
29 : #include "libcli/ldap/ldap_ndr.h"
30 : #include "libcli/security/security.h"
31 : #include "dsdb/samdb/samdb.h"
32 : #include "dsdb/samdb/ldb_modules/util.h"
33 : #include "auth/auth.h"
34 : #include "ldb_wrap.h"
35 : #include "system/network.h"
36 : #include "lib/socket/netif.h"
37 : #include "param/param.h"
38 : #include "../lib/tsocket/tsocket.h"
39 : #include "libds/common/flag_mapping.h"
40 : #include "lib/util/util_net.h"
41 :
42 : #undef strcasecmp
43 :
44 : /*
45 : fill in the cldap netlogon union for a given version
46 : */
47 1771 : NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx,
48 : TALLOC_CTX *mem_ctx,
49 : const char *domain,
50 : const char *netbios_domain,
51 : struct dom_sid *domain_sid,
52 : const char *domain_guid,
53 : const char *user,
54 : uint32_t acct_control,
55 : const char *src_address,
56 : uint32_t version,
57 : struct loadparm_context *lp_ctx,
58 : struct netlogon_samlogon_response *netlogon,
59 : bool fill_on_blank_request)
60 : {
61 1771 : const char *dom_attrs[] = {"objectGUID", NULL};
62 1771 : const char *none_attrs[] = {NULL};
63 1771 : struct ldb_result *dom_res = NULL;
64 : int ret;
65 1771 : const char **services = lpcfg_server_services(lp_ctx);
66 : uint32_t server_type;
67 : const char *pdc_name;
68 : struct GUID domain_uuid;
69 : const char *dns_domain;
70 : const char *forest_domain;
71 : const char *pdc_dns_name;
72 : const char *flatname;
73 : const char *server_site;
74 : const char *client_site;
75 : const char *pdc_ip;
76 1771 : struct ldb_dn *domain_dn = NULL;
77 : struct interface *ifaces;
78 1771 : bool user_known = false, am_rodc = false;
79 1771 : uint32_t uac = 0;
80 : int dc_level;
81 : NTSTATUS status;
82 :
83 : /* the domain parameter could have an optional trailing "." */
84 1771 : if (domain && domain[strlen(domain)-1] == '.') {
85 0 : domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1);
86 0 : NT_STATUS_HAVE_NO_MEMORY(domain);
87 : }
88 :
89 : /* Lookup using long or short domainname */
90 1771 : if (domain && (strcasecmp_m(domain, lpcfg_dnsdomain(lp_ctx)) == 0)) {
91 1586 : domain_dn = ldb_get_default_basedn(sam_ctx);
92 : }
93 1771 : if (netbios_domain && (strcasecmp_m(netbios_domain, lpcfg_sam_name(lp_ctx)) == 0)) {
94 53 : domain_dn = ldb_get_default_basedn(sam_ctx);
95 : }
96 1771 : if (domain_dn) {
97 1639 : const char *domain_identifier = domain != NULL ? domain
98 1639 : : netbios_domain;
99 1639 : ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
100 : domain_dn, LDB_SCOPE_BASE, dom_attrs,
101 : "objectClass=domain");
102 1639 : if (ret != LDB_SUCCESS) {
103 0 : DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n",
104 : domain_identifier,
105 : ldb_dn_get_linearized(domain_dn),
106 : ldb_errstring(sam_ctx)));
107 0 : return NT_STATUS_NO_SUCH_DOMAIN;
108 : }
109 1639 : if (dom_res->count != 1) {
110 0 : DEBUG(2,("Error finding domain '%s'/'%s' in sam\n",
111 : domain_identifier,
112 : ldb_dn_get_linearized(domain_dn)));
113 0 : return NT_STATUS_NO_SUCH_DOMAIN;
114 : }
115 : }
116 :
117 : /* Lookup using GUID or SID */
118 1771 : if ((dom_res == NULL) && (domain_guid || domain_sid)) {
119 8 : if (domain_guid) {
120 : struct GUID binary_guid;
121 : struct ldb_val guid_val;
122 :
123 : /* By this means, we ensure we don't have funny stuff in the GUID */
124 :
125 8 : status = GUID_from_string(domain_guid, &binary_guid);
126 8 : if (!NT_STATUS_IS_OK(status)) {
127 0 : return status;
128 : }
129 :
130 : /* And this gets the result into the binary format we want anyway */
131 8 : status = GUID_to_ndr_blob(&binary_guid, mem_ctx, &guid_val);
132 8 : if (!NT_STATUS_IS_OK(status)) {
133 0 : return status;
134 : }
135 8 : ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
136 : NULL, LDB_SCOPE_SUBTREE,
137 : dom_attrs,
138 : "(&(objectCategory=DomainDNS)(objectGUID=%s))",
139 : ldb_binary_encode(mem_ctx, guid_val));
140 : } else { /* domain_sid case */
141 0 : ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
142 : NULL, LDB_SCOPE_SUBTREE,
143 : dom_attrs,
144 : "(&(objectCategory=DomainDNS)(objectSid=%s))",
145 : dom_sid_string(mem_ctx, domain_sid));
146 : }
147 :
148 8 : if (ret != LDB_SUCCESS) {
149 0 : DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam: %s\n",
150 : domain_guid, dom_sid_string(mem_ctx, domain_sid),
151 : ldb_errstring(sam_ctx)));
152 0 : return NT_STATUS_NO_SUCH_DOMAIN;
153 8 : } else if (dom_res->count == 1) {
154 : /* Ok, now just check it is our domain */
155 4 : if (ldb_dn_compare(ldb_get_default_basedn(sam_ctx),
156 4 : dom_res->msgs[0]->dn) != 0) {
157 0 : DEBUG(2,("The GUID '%s' or SID '%s' doesn't identify our domain\n",
158 : domain_guid,
159 : dom_sid_string(mem_ctx, domain_sid)));
160 0 : return NT_STATUS_NO_SUCH_DOMAIN;
161 : }
162 : } else {
163 4 : DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam\n",
164 : domain_guid, dom_sid_string(mem_ctx, domain_sid)));
165 4 : return NT_STATUS_NO_SUCH_DOMAIN;
166 : }
167 : }
168 :
169 1767 : if (dom_res == NULL && fill_on_blank_request) {
170 : /* blank inputs gives our domain - tested against
171 : w2k8r2. Without this ADUC on Win7 won't start */
172 122 : domain_dn = ldb_get_default_basedn(sam_ctx);
173 122 : ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
174 : domain_dn, LDB_SCOPE_BASE, dom_attrs,
175 : "objectClass=domain");
176 122 : if (ret != LDB_SUCCESS) {
177 0 : DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n",
178 : lpcfg_dnsdomain(lp_ctx),
179 : ldb_dn_get_linearized(domain_dn),
180 : ldb_errstring(sam_ctx)));
181 0 : return NT_STATUS_NO_SUCH_DOMAIN;
182 : }
183 : }
184 :
185 1767 : if (dom_res == NULL) {
186 2 : DEBUG(2,(__location__ ": Unable to get domain information with no inputs\n"));
187 2 : return NT_STATUS_NO_SUCH_DOMAIN;
188 : }
189 :
190 : /* work around different inputs for not-specified users */
191 1765 : if (!user) {
192 1085 : user = "";
193 : }
194 :
195 : /* Enquire about any valid username with just a CLDAP packet -
196 : * if kerberos didn't also do this, the security folks would
197 : * scream... */
198 1765 : if (user[0]) {
199 : /* Only allow some bits to be enquired: [MS-ATDS] 7.3.3.2 */
200 679 : if (acct_control == (uint32_t)-1) {
201 590 : acct_control = 0;
202 : }
203 : /*
204 : * ACB_AUTOLOCK/UF_LOCKOUT seems to be a special
205 : * hack for SEC_CHAN_DNS_DOMAIN.
206 : *
207 : * It's used together with user = "example.com."
208 : */
209 679 : if (acct_control != ACB_AUTOLOCK) {
210 643 : acct_control &= (ACB_TEMPDUP | ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST);
211 : }
212 679 : uac = ds_acb2uf(acct_control);
213 : }
214 :
215 1765 : if (uac == UF_LOCKOUT) {
216 36 : struct ldb_message *tdo_msg = NULL;
217 :
218 : /*
219 : * ACB_AUTOLOCK/UF_LOCKOUT seems to be a special
220 : * hack for SEC_CHAN_DNS_DOMAIN.
221 : *
222 : * It's used together with user = "example.com."
223 : */
224 36 : status = dsdb_trust_search_tdo_by_type(sam_ctx,
225 : SEC_CHAN_DNS_DOMAIN,
226 : user, none_attrs,
227 : mem_ctx, &tdo_msg);
228 36 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
229 0 : user_known = false;
230 36 : } else if (NT_STATUS_IS_OK(status)) {
231 36 : TALLOC_FREE(tdo_msg);
232 36 : user_known = true;
233 : } else {
234 0 : DEBUG(2,("Unable to find reference to TDO '%s' - %s\n",
235 : user, nt_errstr(status)));
236 0 : return status;
237 : }
238 1729 : } else if (user[0]) {
239 643 : struct ldb_result *user_res = NULL;
240 :
241 : /* We must exclude disabled accounts, but otherwise do the bitwise match the client asked for */
242 1286 : ret = ldb_search(sam_ctx, mem_ctx, &user_res,
243 643 : dom_res->msgs[0]->dn, LDB_SCOPE_SUBTREE,
244 : none_attrs,
245 : "(&(objectClass=user)(samAccountName=%s)"
246 : "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))"
247 : "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))",
248 : ldb_binary_encode_string(mem_ctx, user),
249 : UF_ACCOUNTDISABLE, uac);
250 643 : if (ret != LDB_SUCCESS) {
251 0 : DEBUG(2,("Unable to find reference to user '%s' with ACB 0x%8x under %s: %s\n",
252 : user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn),
253 : ldb_errstring(sam_ctx)));
254 0 : return NT_STATUS_NO_SUCH_USER;
255 643 : } else if (user_res->count == 1) {
256 48 : user_known = true;
257 : } else {
258 595 : user_known = false;
259 : }
260 643 : TALLOC_FREE(user_res);
261 : } else {
262 1086 : user_known = true;
263 : }
264 :
265 1765 : server_type = DS_SERVER_DS;
266 :
267 1765 : if (samdb_is_pdc(sam_ctx)) {
268 1723 : server_type |= DS_SERVER_PDC;
269 : }
270 :
271 1765 : if (samdb_is_gc(sam_ctx)) {
272 1765 : server_type |= DS_SERVER_GC;
273 : }
274 :
275 1765 : if (str_list_check(services, "ldap")) {
276 1765 : server_type |= DS_SERVER_LDAP;
277 : }
278 :
279 1765 : if (str_list_check(services, "kdc")) {
280 1765 : server_type |= DS_SERVER_KDC;
281 : }
282 :
283 1765 : if (str_list_check(services, "ntp_signd")) {
284 1765 : server_type |= DS_SERVER_TIMESERV | DS_SERVER_GOOD_TIMESERV;
285 : }
286 :
287 1765 : if (samdb_rodc(sam_ctx, &am_rodc) == LDB_SUCCESS && !am_rodc) {
288 1765 : server_type |= DS_SERVER_WRITABLE;
289 : }
290 :
291 1765 : dc_level = dsdb_dc_functional_level(sam_ctx);
292 1765 : if (dc_level >= DS_DOMAIN_FUNCTION_2008) {
293 1698 : if (server_type & DS_SERVER_WRITABLE) {
294 1698 : server_type |= DS_SERVER_FULL_SECRET_DOMAIN_6;
295 : } else {
296 0 : server_type |= DS_SERVER_SELECT_SECRET_DOMAIN_6;
297 : }
298 : }
299 :
300 1765 : if (dc_level >= DS_DOMAIN_FUNCTION_2012) {
301 0 : server_type |= DS_SERVER_DS_8;
302 : }
303 :
304 1765 : if (dc_level >= DS_DOMAIN_FUNCTION_2012_R2) {
305 0 : server_type |= DS_SERVER_DS_9;
306 : }
307 :
308 1765 : if (dc_level >= DS_DOMAIN_FUNCTION_2016) {
309 0 : server_type |= DS_SERVER_DS_10;
310 : }
311 :
312 1765 : if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) {
313 1566 : pdc_name = lpcfg_netbios_name(lp_ctx);
314 : } else {
315 199 : pdc_name = talloc_asprintf(mem_ctx, "\\\\%s",
316 : lpcfg_netbios_name(lp_ctx));
317 199 : NT_STATUS_HAVE_NO_MEMORY(pdc_name);
318 : }
319 1765 : domain_uuid = samdb_result_guid(dom_res->msgs[0], "objectGUID");
320 1765 : dns_domain = lpcfg_dnsdomain(lp_ctx);
321 1765 : forest_domain = samdb_forest_name(sam_ctx, mem_ctx);
322 1765 : NT_STATUS_HAVE_NO_MEMORY(forest_domain);
323 1765 : pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s",
324 : strlower_talloc(mem_ctx,
325 : lpcfg_netbios_name(lp_ctx)),
326 : dns_domain);
327 1765 : NT_STATUS_HAVE_NO_MEMORY(pdc_dns_name);
328 1765 : flatname = lpcfg_workgroup(lp_ctx);
329 :
330 1765 : server_site = samdb_server_site_name(sam_ctx, mem_ctx);
331 1765 : NT_STATUS_HAVE_NO_MEMORY(server_site);
332 1765 : client_site = samdb_client_site_name(sam_ctx, mem_ctx,
333 : src_address, NULL,
334 : true);
335 1765 : NT_STATUS_HAVE_NO_MEMORY(client_site);
336 1765 : if (strcasecmp(server_site, client_site) == 0) {
337 1631 : server_type |= DS_SERVER_CLOSEST;
338 : }
339 :
340 1765 : load_interface_list(mem_ctx, lp_ctx, &ifaces);
341 1765 : if (src_address) {
342 1659 : pdc_ip = iface_list_best_ip(ifaces, src_address);
343 : } else {
344 106 : pdc_ip = iface_list_first_v4(ifaces);
345 : }
346 1765 : if (pdc_ip == NULL || !is_ipaddress_v4(pdc_ip)) {
347 : /* this matches windows behaviour */
348 130 : pdc_ip = "127.0.0.1";
349 : }
350 :
351 1765 : ZERO_STRUCTP(netlogon);
352 :
353 : /* check if either of these bits is present */
354 1765 : if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) {
355 1566 : uint32_t extra_flags = 0;
356 1566 : netlogon->ntver = NETLOGON_NT_VERSION_5EX;
357 :
358 : /* could check if the user exists */
359 1566 : if (user_known) {
360 1164 : netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_RESPONSE_EX;
361 : } else {
362 402 : netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_USER_UNKNOWN_EX;
363 : }
364 1566 : netlogon->data.nt5_ex.pdc_name = pdc_name;
365 1566 : netlogon->data.nt5_ex.user_name = user;
366 1566 : netlogon->data.nt5_ex.domain_name = flatname;
367 1566 : netlogon->data.nt5_ex.domain_uuid = domain_uuid;
368 1566 : netlogon->data.nt5_ex.forest = forest_domain;
369 1566 : netlogon->data.nt5_ex.dns_domain = dns_domain;
370 1566 : netlogon->data.nt5_ex.pdc_dns_name = pdc_dns_name;
371 1566 : netlogon->data.nt5_ex.server_site = server_site;
372 1566 : netlogon->data.nt5_ex.client_site = client_site;
373 1566 : if (version & NETLOGON_NT_VERSION_5EX_WITH_IP) {
374 : /* note that this is always a IPV4 address */
375 460 : extra_flags = NETLOGON_NT_VERSION_5EX_WITH_IP;
376 460 : netlogon->data.nt5_ex.sockaddr.sockaddr_family = 2;
377 460 : netlogon->data.nt5_ex.sockaddr.pdc_ip = pdc_ip;
378 460 : netlogon->data.nt5_ex.sockaddr.remaining = data_blob_talloc_zero(mem_ctx, 8);
379 : }
380 1566 : netlogon->data.nt5_ex.server_type = server_type;
381 1566 : netlogon->data.nt5_ex.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5EX|extra_flags;
382 1566 : netlogon->data.nt5_ex.lmnt_token = 0xFFFF;
383 1566 : netlogon->data.nt5_ex.lm20_token = 0xFFFF;
384 :
385 199 : } else if (version & NETLOGON_NT_VERSION_5) {
386 73 : netlogon->ntver = NETLOGON_NT_VERSION_5;
387 :
388 : /* could check if the user exists */
389 73 : if (user_known) {
390 3 : netlogon->data.nt5.command = LOGON_SAM_LOGON_RESPONSE;
391 : } else {
392 70 : netlogon->data.nt5.command = LOGON_SAM_LOGON_USER_UNKNOWN;
393 : }
394 73 : netlogon->data.nt5.pdc_name = pdc_name;
395 73 : netlogon->data.nt5.user_name = user;
396 73 : netlogon->data.nt5.domain_name = flatname;
397 73 : netlogon->data.nt5.domain_uuid = domain_uuid;
398 73 : netlogon->data.nt5.forest = forest_domain;
399 73 : netlogon->data.nt5.dns_domain = dns_domain;
400 73 : netlogon->data.nt5.pdc_dns_name = pdc_dns_name;
401 73 : netlogon->data.nt5.pdc_ip = pdc_ip;
402 73 : netlogon->data.nt5.server_type = server_type;
403 73 : netlogon->data.nt5.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5;
404 73 : netlogon->data.nt5.lmnt_token = 0xFFFF;
405 73 : netlogon->data.nt5.lm20_token = 0xFFFF;
406 :
407 : } else /* (version & NETLOGON_NT_VERSION_1) and all other cases */ {
408 126 : netlogon->ntver = NETLOGON_NT_VERSION_1;
409 : /* could check if the user exists */
410 126 : if (user_known) {
411 3 : netlogon->data.nt4.command = LOGON_SAM_LOGON_RESPONSE;
412 : } else {
413 123 : netlogon->data.nt4.command = LOGON_SAM_LOGON_USER_UNKNOWN;
414 : }
415 126 : netlogon->data.nt4.pdc_name = pdc_name;
416 126 : netlogon->data.nt4.user_name = user;
417 126 : netlogon->data.nt4.domain_name = flatname;
418 126 : netlogon->data.nt4.nt_version = NETLOGON_NT_VERSION_1;
419 126 : netlogon->data.nt4.lmnt_token = 0xFFFF;
420 126 : netlogon->data.nt4.lm20_token = 0xFFFF;
421 : }
422 :
423 1765 : return NT_STATUS_OK;
424 : }
425 :
426 1569 : NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree,
427 : struct loadparm_context *lp_ctx,
428 : TALLOC_CTX *tmp_ctx,
429 : const char **domain,
430 : const char **host,
431 : const char **user,
432 : const char **domain_guid,
433 : struct dom_sid **domain_sid,
434 : int *acct_control,
435 : int *version)
436 : {
437 : unsigned int i;
438 :
439 1569 : *domain = NULL;
440 1569 : *host = NULL;
441 1569 : *user = NULL;
442 1569 : *domain_guid = NULL;
443 1569 : *domain_sid = NULL;
444 1569 : *acct_control = -1;
445 1569 : *version = NETLOGON_NT_VERSION_5;
446 :
447 1569 : if (tree->operation != LDB_OP_AND) goto failed;
448 :
449 : /* extract the query elements */
450 5992 : for (i=0;i<tree->u.list.num_elements;i++) {
451 4429 : struct ldb_parse_tree *t = tree->u.list.elements[i];
452 4429 : if (t->operation != LDB_OP_EQUALITY) goto failed;
453 4427 : if (strcasecmp(t->u.equality.attr, "DnsDomain") == 0) {
454 2069 : *domain = talloc_strndup(tmp_ctx,
455 1121 : (const char *)t->u.equality.value.data,
456 : t->u.equality.value.length);
457 : }
458 4427 : if (strcasecmp(t->u.equality.attr, "Host") == 0) {
459 1208 : *host = talloc_strndup(tmp_ctx,
460 606 : (const char *)t->u.equality.value.data,
461 : t->u.equality.value.length);
462 : }
463 4427 : if (strcasecmp(t->u.equality.attr, "DomainGuid") == 0) {
464 : NTSTATUS enc_status;
465 : struct GUID guid;
466 20 : enc_status = ldap_decode_ndr_GUID(tmp_ctx,
467 : t->u.equality.value, &guid);
468 20 : if (NT_STATUS_IS_OK(enc_status)) {
469 20 : *domain_guid = GUID_string(tmp_ctx, &guid);
470 : }
471 : }
472 4427 : if (strcasecmp(t->u.equality.attr, "DomainSid") == 0) {
473 : enum ndr_err_code ndr_err;
474 :
475 0 : *domain_sid = talloc(tmp_ctx, struct dom_sid);
476 0 : if (*domain_sid == NULL) {
477 0 : goto failed;
478 : }
479 0 : ndr_err = ndr_pull_struct_blob(&t->u.equality.value,
480 : *domain_sid, *domain_sid,
481 : (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
482 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
483 0 : talloc_free(*domain_sid);
484 0 : goto failed;
485 : }
486 : }
487 4427 : if (strcasecmp(t->u.equality.attr, "User") == 0) {
488 1328 : *user = talloc_strndup(tmp_ctx,
489 664 : (const char *)t->u.equality.value.data,
490 : t->u.equality.value.length);
491 : }
492 5801 : if (strcasecmp(t->u.equality.attr, "NtVer") == 0 &&
493 1564 : t->u.equality.value.length == 4) {
494 1564 : *version = IVAL(t->u.equality.value.data, 0);
495 : }
496 4712 : if (strcasecmp(t->u.equality.attr, "AAC") == 0 &&
497 448 : t->u.equality.value.length == 4) {
498 448 : *acct_control = IVAL(t->u.equality.value.data, 0);
499 : }
500 : }
501 :
502 1563 : if ((*domain == NULL) && (*domain_guid == NULL) && (*domain_sid == NULL)) {
503 438 : *domain = lpcfg_dnsdomain(lp_ctx);
504 : }
505 :
506 1563 : return NT_STATUS_OK;
507 :
508 6 : failed:
509 6 : return NT_STATUS_UNSUCCESSFUL;
510 : }
|