/src/samba/source4/dsdb/samdb/ldb_modules/netlogon.c
Line | Count | Source |
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 | | 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 | 0 | { |
61 | 0 | const char *dom_attrs[] = {"objectGUID", NULL}; |
62 | 0 | const char *none_attrs[] = {NULL}; |
63 | 0 | struct ldb_result *dom_res = NULL; |
64 | 0 | int ret; |
65 | 0 | const char **services = lpcfg_server_services(lp_ctx); |
66 | 0 | uint32_t server_type; |
67 | 0 | const char *pdc_name; |
68 | 0 | struct GUID domain_uuid; |
69 | 0 | const char *dns_domain; |
70 | 0 | const char *forest_domain; |
71 | 0 | const char *pdc_dns_name; |
72 | 0 | const char *flatname; |
73 | 0 | const char *server_site; |
74 | 0 | const char *client_site; |
75 | 0 | const char *pdc_ip; |
76 | 0 | struct ldb_dn *domain_dn = NULL; |
77 | 0 | struct interface *ifaces; |
78 | 0 | bool user_known = false, am_rodc = false; |
79 | 0 | uint32_t uac = 0; |
80 | 0 | int dc_level; |
81 | 0 | NTSTATUS status; |
82 | | |
83 | | /* the domain parameter could have an optional trailing "." */ |
84 | 0 | 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 | 0 | } |
88 | | |
89 | | /* Lookup using long or short domainname */ |
90 | 0 | if (domain && (strcasecmp_m(domain, lpcfg_dnsdomain(lp_ctx)) == 0)) { |
91 | 0 | domain_dn = ldb_get_default_basedn(sam_ctx); |
92 | 0 | } |
93 | 0 | if (netbios_domain && (strcasecmp_m(netbios_domain, lpcfg_sam_name(lp_ctx)) == 0)) { |
94 | 0 | domain_dn = ldb_get_default_basedn(sam_ctx); |
95 | 0 | } |
96 | 0 | if (domain_dn) { |
97 | 0 | const char *domain_identifier = domain != NULL ? domain |
98 | 0 | : netbios_domain; |
99 | 0 | ret = ldb_search(sam_ctx, mem_ctx, &dom_res, |
100 | 0 | domain_dn, LDB_SCOPE_BASE, dom_attrs, |
101 | 0 | "objectClass=domain"); |
102 | 0 | if (ret != LDB_SUCCESS) { |
103 | 0 | DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", |
104 | 0 | domain_identifier, |
105 | 0 | ldb_dn_get_linearized(domain_dn), |
106 | 0 | ldb_errstring(sam_ctx))); |
107 | 0 | return NT_STATUS_NO_SUCH_DOMAIN; |
108 | 0 | } |
109 | 0 | if (dom_res->count != 1) { |
110 | 0 | DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", |
111 | 0 | domain_identifier, |
112 | 0 | ldb_dn_get_linearized(domain_dn))); |
113 | 0 | return NT_STATUS_NO_SUCH_DOMAIN; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | /* Lookup using GUID or SID */ |
118 | 0 | if ((dom_res == NULL) && (domain_guid || domain_sid)) { |
119 | 0 | if (domain_guid) { |
120 | 0 | struct GUID binary_guid; |
121 | 0 | struct ldb_val guid_val; |
122 | | |
123 | | /* By this means, we ensure we don't have funny stuff in the GUID */ |
124 | |
|
125 | 0 | status = GUID_from_string(domain_guid, &binary_guid); |
126 | 0 | if (!NT_STATUS_IS_OK(status)) { |
127 | 0 | return status; |
128 | 0 | } |
129 | | |
130 | | /* And this gets the result into the binary format we want anyway */ |
131 | 0 | status = GUID_to_ndr_blob(&binary_guid, mem_ctx, &guid_val); |
132 | 0 | if (!NT_STATUS_IS_OK(status)) { |
133 | 0 | return status; |
134 | 0 | } |
135 | 0 | ret = ldb_search(sam_ctx, mem_ctx, &dom_res, |
136 | 0 | NULL, LDB_SCOPE_SUBTREE, |
137 | 0 | dom_attrs, |
138 | 0 | "(&(objectCategory=DomainDNS)(objectGUID=%s))", |
139 | 0 | ldb_binary_encode(mem_ctx, guid_val)); |
140 | 0 | } else { /* domain_sid case */ |
141 | 0 | ret = ldb_search(sam_ctx, mem_ctx, &dom_res, |
142 | 0 | NULL, LDB_SCOPE_SUBTREE, |
143 | 0 | dom_attrs, |
144 | 0 | "(&(objectCategory=DomainDNS)(objectSid=%s))", |
145 | 0 | dom_sid_string(mem_ctx, domain_sid)); |
146 | 0 | } |
147 | | |
148 | 0 | 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 | 0 | domain_guid, dom_sid_string(mem_ctx, domain_sid), |
151 | 0 | ldb_errstring(sam_ctx))); |
152 | 0 | return NT_STATUS_NO_SUCH_DOMAIN; |
153 | 0 | } else if (dom_res->count == 1) { |
154 | | /* Ok, now just check it is our domain */ |
155 | 0 | if (ldb_dn_compare(ldb_get_default_basedn(sam_ctx), |
156 | 0 | dom_res->msgs[0]->dn) != 0) { |
157 | 0 | DEBUG(2,("The GUID '%s' or SID '%s' doesn't identify our domain\n", |
158 | 0 | domain_guid, |
159 | 0 | dom_sid_string(mem_ctx, domain_sid))); |
160 | 0 | return NT_STATUS_NO_SUCH_DOMAIN; |
161 | 0 | } |
162 | 0 | } else { |
163 | 0 | DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam\n", |
164 | 0 | domain_guid, dom_sid_string(mem_ctx, domain_sid))); |
165 | 0 | return NT_STATUS_NO_SUCH_DOMAIN; |
166 | 0 | } |
167 | 0 | } |
168 | | |
169 | 0 | 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 | 0 | domain_dn = ldb_get_default_basedn(sam_ctx); |
173 | 0 | ret = ldb_search(sam_ctx, mem_ctx, &dom_res, |
174 | 0 | domain_dn, LDB_SCOPE_BASE, dom_attrs, |
175 | 0 | "objectClass=domain"); |
176 | 0 | if (ret != LDB_SUCCESS) { |
177 | 0 | DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", |
178 | 0 | lpcfg_dnsdomain(lp_ctx), |
179 | 0 | ldb_dn_get_linearized(domain_dn), |
180 | 0 | ldb_errstring(sam_ctx))); |
181 | 0 | return NT_STATUS_NO_SUCH_DOMAIN; |
182 | 0 | } |
183 | 0 | } |
184 | | |
185 | 0 | if (dom_res == NULL) { |
186 | 0 | DEBUG(2,(__location__ ": Unable to get domain information with no inputs\n")); |
187 | 0 | return NT_STATUS_NO_SUCH_DOMAIN; |
188 | 0 | } |
189 | | |
190 | | /* work around different inputs for not-specified users */ |
191 | 0 | if (!user) { |
192 | 0 | user = ""; |
193 | 0 | } |
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 | 0 | if (user[0]) { |
199 | | /* Only allow some bits to be enquired: [MS-ATDS] 7.3.3.2 */ |
200 | 0 | if (acct_control == (uint32_t)-1) { |
201 | 0 | acct_control = 0; |
202 | 0 | } |
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 | 0 | if (acct_control != ACB_AUTOLOCK) { |
210 | 0 | acct_control &= (ACB_TEMPDUP | ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); |
211 | 0 | } |
212 | 0 | uac = ds_acb2uf(acct_control); |
213 | 0 | } |
214 | |
|
215 | 0 | if (uac == UF_LOCKOUT) { |
216 | 0 | 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 | 0 | status = dsdb_trust_search_tdo_by_type(sam_ctx, |
225 | 0 | SEC_CHAN_DNS_DOMAIN, |
226 | 0 | user, none_attrs, |
227 | 0 | mem_ctx, &tdo_msg); |
228 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { |
229 | 0 | user_known = false; |
230 | 0 | } else if (NT_STATUS_IS_OK(status)) { |
231 | 0 | TALLOC_FREE(tdo_msg); |
232 | 0 | user_known = true; |
233 | 0 | } else { |
234 | 0 | DEBUG(2,("Unable to find reference to TDO '%s' - %s\n", |
235 | 0 | user, nt_errstr(status))); |
236 | 0 | return status; |
237 | 0 | } |
238 | 0 | } else if (user[0]) { |
239 | 0 | struct ldb_result *user_res = NULL; |
240 | 0 | const char *user_encoded = NULL; |
241 | |
|
242 | 0 | user_encoded = ldb_binary_encode_string(mem_ctx, user); |
243 | 0 | if (user_encoded == NULL) { |
244 | 0 | return NT_STATUS_NO_MEMORY; |
245 | 0 | } |
246 | | |
247 | | /* We must exclude disabled accounts, but otherwise do the bitwise match the client asked for */ |
248 | 0 | ret = ldb_search(sam_ctx, mem_ctx, &user_res, |
249 | 0 | dom_res->msgs[0]->dn, LDB_SCOPE_SUBTREE, |
250 | 0 | none_attrs, |
251 | 0 | "(&(objectClass=user)(samAccountName=%s)" |
252 | 0 | "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))" |
253 | 0 | "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))", |
254 | 0 | user_encoded, |
255 | 0 | UF_ACCOUNTDISABLE, uac); |
256 | 0 | if (ret != LDB_SUCCESS) { |
257 | 0 | DEBUG(2,("Unable to find reference to user '%s' with ACB 0x%8x under %s: %s\n", |
258 | 0 | user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn), |
259 | 0 | ldb_errstring(sam_ctx))); |
260 | 0 | return NT_STATUS_NO_SUCH_USER; |
261 | 0 | } else if (user_res->count == 1) { |
262 | 0 | user_known = true; |
263 | 0 | } else { |
264 | 0 | user_known = false; |
265 | 0 | } |
266 | 0 | TALLOC_FREE(user_res); |
267 | 0 | } else { |
268 | 0 | user_known = true; |
269 | 0 | } |
270 | | |
271 | 0 | server_type = DS_SERVER_DS; |
272 | |
|
273 | 0 | if (samdb_is_pdc(sam_ctx)) { |
274 | 0 | server_type |= DS_SERVER_PDC; |
275 | 0 | } |
276 | |
|
277 | 0 | if (samdb_is_gc(sam_ctx)) { |
278 | 0 | server_type |= DS_SERVER_GC; |
279 | 0 | } |
280 | |
|
281 | 0 | if (str_list_check(services, "ldap")) { |
282 | 0 | server_type |= DS_SERVER_LDAP; |
283 | 0 | } |
284 | |
|
285 | 0 | if (str_list_check(services, "kdc")) { |
286 | 0 | server_type |= DS_SERVER_KDC; |
287 | 0 | } |
288 | |
|
289 | 0 | if (str_list_check(services, "ntp_signd")) { |
290 | 0 | server_type |= DS_SERVER_TIMESERV | DS_SERVER_GOOD_TIMESERV; |
291 | 0 | } |
292 | |
|
293 | 0 | if (samdb_rodc(sam_ctx, &am_rodc) == LDB_SUCCESS && !am_rodc) { |
294 | 0 | server_type |= DS_SERVER_WRITABLE; |
295 | 0 | } |
296 | |
|
297 | 0 | dc_level = dsdb_dc_functional_level(sam_ctx); |
298 | 0 | if (dc_level >= DS_DOMAIN_FUNCTION_2008) { |
299 | 0 | if (server_type & DS_SERVER_WRITABLE) { |
300 | 0 | server_type |= DS_SERVER_FULL_SECRET_DOMAIN_6; |
301 | 0 | } else { |
302 | 0 | server_type |= DS_SERVER_SELECT_SECRET_DOMAIN_6; |
303 | 0 | } |
304 | 0 | } |
305 | |
|
306 | 0 | if (dc_level >= DS_DOMAIN_FUNCTION_2012) { |
307 | 0 | server_type |= DS_SERVER_DS_8; |
308 | 0 | } |
309 | |
|
310 | 0 | if (dc_level >= DS_DOMAIN_FUNCTION_2012_R2) { |
311 | 0 | server_type |= DS_SERVER_DS_9; |
312 | 0 | } |
313 | |
|
314 | 0 | if (dc_level >= DS_DOMAIN_FUNCTION_2016) { |
315 | 0 | server_type |= DS_SERVER_DS_10; |
316 | 0 | } |
317 | |
|
318 | 0 | if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { |
319 | 0 | pdc_name = lpcfg_netbios_name(lp_ctx); |
320 | 0 | } else { |
321 | 0 | pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", |
322 | 0 | lpcfg_netbios_name(lp_ctx)); |
323 | 0 | NT_STATUS_HAVE_NO_MEMORY(pdc_name); |
324 | 0 | } |
325 | 0 | domain_uuid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); |
326 | 0 | dns_domain = lpcfg_dnsdomain(lp_ctx); |
327 | 0 | forest_domain = samdb_forest_name(sam_ctx, mem_ctx); |
328 | 0 | NT_STATUS_HAVE_NO_MEMORY(forest_domain); |
329 | 0 | pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s", |
330 | 0 | strlower_talloc(mem_ctx, |
331 | 0 | lpcfg_netbios_name(lp_ctx)), |
332 | 0 | dns_domain); |
333 | 0 | NT_STATUS_HAVE_NO_MEMORY(pdc_dns_name); |
334 | 0 | flatname = lpcfg_workgroup(lp_ctx); |
335 | |
|
336 | 0 | server_site = samdb_server_site_name(sam_ctx, mem_ctx); |
337 | 0 | NT_STATUS_HAVE_NO_MEMORY(server_site); |
338 | 0 | client_site = samdb_client_site_name(sam_ctx, mem_ctx, |
339 | 0 | src_address, NULL, |
340 | 0 | true); |
341 | 0 | NT_STATUS_HAVE_NO_MEMORY(client_site); |
342 | 0 | if (strcasecmp(server_site, client_site) == 0) { |
343 | 0 | server_type |= DS_SERVER_CLOSEST; |
344 | 0 | } |
345 | |
|
346 | 0 | load_interface_list(mem_ctx, lp_ctx, &ifaces); |
347 | 0 | if (src_address) { |
348 | 0 | pdc_ip = iface_list_best_ip(ifaces, src_address); |
349 | 0 | } else { |
350 | 0 | pdc_ip = iface_list_first_v4(ifaces); |
351 | 0 | } |
352 | 0 | if (pdc_ip == NULL || !is_ipaddress_v4(pdc_ip)) { |
353 | | /* this matches windows behaviour */ |
354 | 0 | pdc_ip = "127.0.0.1"; |
355 | 0 | } |
356 | |
|
357 | 0 | ZERO_STRUCTP(netlogon); |
358 | | |
359 | | /* check if either of these bits is present */ |
360 | 0 | if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { |
361 | 0 | uint32_t extra_flags = 0; |
362 | 0 | netlogon->ntver = NETLOGON_NT_VERSION_5EX; |
363 | | |
364 | | /* could check if the user exists */ |
365 | 0 | if (user_known) { |
366 | 0 | netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_RESPONSE_EX; |
367 | 0 | } else { |
368 | 0 | netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_USER_UNKNOWN_EX; |
369 | 0 | } |
370 | 0 | netlogon->data.nt5_ex.pdc_name = pdc_name; |
371 | 0 | netlogon->data.nt5_ex.user_name = user; |
372 | 0 | netlogon->data.nt5_ex.domain_name = flatname; |
373 | 0 | netlogon->data.nt5_ex.domain_uuid = domain_uuid; |
374 | 0 | netlogon->data.nt5_ex.forest = forest_domain; |
375 | 0 | netlogon->data.nt5_ex.dns_domain = dns_domain; |
376 | 0 | netlogon->data.nt5_ex.pdc_dns_name = pdc_dns_name; |
377 | 0 | netlogon->data.nt5_ex.server_site = server_site; |
378 | 0 | netlogon->data.nt5_ex.client_site = client_site; |
379 | 0 | if (version & NETLOGON_NT_VERSION_5EX_WITH_IP) { |
380 | | /* note that this is always a IPV4 address */ |
381 | 0 | extra_flags = NETLOGON_NT_VERSION_5EX_WITH_IP; |
382 | 0 | netlogon->data.nt5_ex.sockaddr.sockaddr_family = 2; |
383 | 0 | netlogon->data.nt5_ex.sockaddr.pdc_ip = pdc_ip; |
384 | 0 | netlogon->data.nt5_ex.sockaddr.remaining = data_blob_talloc_zero(mem_ctx, 8); |
385 | 0 | } |
386 | 0 | netlogon->data.nt5_ex.server_type = server_type; |
387 | 0 | netlogon->data.nt5_ex.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5EX|extra_flags; |
388 | 0 | netlogon->data.nt5_ex.lmnt_token = 0xFFFF; |
389 | 0 | netlogon->data.nt5_ex.lm20_token = 0xFFFF; |
390 | |
|
391 | 0 | } else if (version & NETLOGON_NT_VERSION_5) { |
392 | 0 | netlogon->ntver = NETLOGON_NT_VERSION_5; |
393 | | |
394 | | /* could check if the user exists */ |
395 | 0 | if (user_known) { |
396 | 0 | netlogon->data.nt5.command = LOGON_SAM_LOGON_RESPONSE; |
397 | 0 | } else { |
398 | 0 | netlogon->data.nt5.command = LOGON_SAM_LOGON_USER_UNKNOWN; |
399 | 0 | } |
400 | 0 | netlogon->data.nt5.pdc_name = pdc_name; |
401 | 0 | netlogon->data.nt5.user_name = user; |
402 | 0 | netlogon->data.nt5.domain_name = flatname; |
403 | 0 | netlogon->data.nt5.domain_uuid = domain_uuid; |
404 | 0 | netlogon->data.nt5.forest = forest_domain; |
405 | 0 | netlogon->data.nt5.dns_domain = dns_domain; |
406 | 0 | netlogon->data.nt5.pdc_dns_name = pdc_dns_name; |
407 | 0 | netlogon->data.nt5.pdc_ip = pdc_ip; |
408 | 0 | netlogon->data.nt5.server_type = server_type; |
409 | 0 | netlogon->data.nt5.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5; |
410 | 0 | netlogon->data.nt5.lmnt_token = 0xFFFF; |
411 | 0 | netlogon->data.nt5.lm20_token = 0xFFFF; |
412 | |
|
413 | 0 | } else /* (version & NETLOGON_NT_VERSION_1) and all other cases */ { |
414 | 0 | netlogon->ntver = NETLOGON_NT_VERSION_1; |
415 | | /* could check if the user exists */ |
416 | 0 | if (user_known) { |
417 | 0 | netlogon->data.nt4.command = LOGON_SAM_LOGON_RESPONSE; |
418 | 0 | } else { |
419 | 0 | netlogon->data.nt4.command = LOGON_SAM_LOGON_USER_UNKNOWN; |
420 | 0 | } |
421 | 0 | netlogon->data.nt4.pdc_name = pdc_name; |
422 | 0 | netlogon->data.nt4.user_name = user; |
423 | 0 | netlogon->data.nt4.domain_name = flatname; |
424 | 0 | netlogon->data.nt4.nt_version = NETLOGON_NT_VERSION_1; |
425 | 0 | netlogon->data.nt4.lmnt_token = 0xFFFF; |
426 | 0 | netlogon->data.nt4.lm20_token = 0xFFFF; |
427 | 0 | } |
428 | |
|
429 | 0 | return NT_STATUS_OK; |
430 | 0 | } |
431 | | |
432 | | NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, |
433 | | struct loadparm_context *lp_ctx, |
434 | | TALLOC_CTX *tmp_ctx, |
435 | | const char **domain, |
436 | | const char **host, |
437 | | const char **user, |
438 | | const char **domain_guid, |
439 | | struct dom_sid **domain_sid, |
440 | | int *acct_control, |
441 | | int *version) |
442 | 0 | { |
443 | 0 | unsigned int i; |
444 | |
|
445 | 0 | *domain = NULL; |
446 | 0 | *host = NULL; |
447 | 0 | *user = NULL; |
448 | 0 | *domain_guid = NULL; |
449 | 0 | *domain_sid = NULL; |
450 | 0 | *acct_control = -1; |
451 | 0 | *version = NETLOGON_NT_VERSION_5; |
452 | |
|
453 | 0 | if (tree->operation != LDB_OP_AND) goto failed; |
454 | | |
455 | | /* extract the query elements */ |
456 | 0 | for (i=0;i<tree->u.list.num_elements;i++) { |
457 | 0 | struct ldb_parse_tree *t = tree->u.list.elements[i]; |
458 | 0 | if (t->operation != LDB_OP_EQUALITY) goto failed; |
459 | 0 | if (strcasecmp(t->u.equality.attr, "DnsDomain") == 0) { |
460 | 0 | *domain = talloc_strndup(tmp_ctx, |
461 | 0 | (const char *)t->u.equality.value.data, |
462 | 0 | t->u.equality.value.length); |
463 | 0 | } |
464 | 0 | if (strcasecmp(t->u.equality.attr, "Host") == 0) { |
465 | 0 | *host = talloc_strndup(tmp_ctx, |
466 | 0 | (const char *)t->u.equality.value.data, |
467 | 0 | t->u.equality.value.length); |
468 | 0 | } |
469 | 0 | if (strcasecmp(t->u.equality.attr, "DomainGuid") == 0) { |
470 | 0 | NTSTATUS enc_status; |
471 | 0 | struct GUID guid; |
472 | 0 | enc_status = ldap_decode_ndr_GUID(tmp_ctx, |
473 | 0 | t->u.equality.value, &guid); |
474 | 0 | if (NT_STATUS_IS_OK(enc_status)) { |
475 | 0 | *domain_guid = GUID_string(tmp_ctx, &guid); |
476 | 0 | } |
477 | 0 | } |
478 | 0 | if (strcasecmp(t->u.equality.attr, "DomainSid") == 0) { |
479 | 0 | enum ndr_err_code ndr_err; |
480 | |
|
481 | 0 | *domain_sid = talloc(tmp_ctx, struct dom_sid); |
482 | 0 | if (*domain_sid == NULL) { |
483 | 0 | goto failed; |
484 | 0 | } |
485 | 0 | ndr_err = ndr_pull_struct_blob(&t->u.equality.value, |
486 | 0 | *domain_sid, *domain_sid, |
487 | 0 | (ndr_pull_flags_fn_t)ndr_pull_dom_sid); |
488 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { |
489 | 0 | talloc_free(*domain_sid); |
490 | 0 | goto failed; |
491 | 0 | } |
492 | 0 | } |
493 | 0 | if (strcasecmp(t->u.equality.attr, "User") == 0) { |
494 | 0 | *user = talloc_strndup(tmp_ctx, |
495 | 0 | (const char *)t->u.equality.value.data, |
496 | 0 | t->u.equality.value.length); |
497 | 0 | } |
498 | 0 | if (strcasecmp(t->u.equality.attr, "NtVer") == 0 && |
499 | 0 | t->u.equality.value.length == 4) { |
500 | 0 | *version = IVAL(t->u.equality.value.data, 0); |
501 | 0 | } |
502 | 0 | if (strcasecmp(t->u.equality.attr, "AAC") == 0 && |
503 | 0 | t->u.equality.value.length == 4) { |
504 | 0 | *acct_control = IVAL(t->u.equality.value.data, 0); |
505 | 0 | } |
506 | 0 | } |
507 | | |
508 | 0 | if ((*domain == NULL) && (*domain_guid == NULL) && (*domain_sid == NULL)) { |
509 | 0 | *domain = lpcfg_dnsdomain(lp_ctx); |
510 | 0 | } |
511 | |
|
512 | 0 | return NT_STATUS_OK; |
513 | | |
514 | 0 | failed: |
515 | 0 | return NT_STATUS_UNSUCCESSFUL; |
516 | 0 | } |