2 Unix SMB/CIFS implementation.
4 CLDAP server - netlogon handling
6 Copyright (C) Andrew Tridgell 2005
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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libcli/ldap/ldap.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "lib/ldb/include/ldb_errors.h"
27 #include "lib/events/events.h"
28 #include "lib/socket/socket.h"
29 #include "smbd/service_task.h"
30 #include "cldap_server/cldap_server.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32 #include "dsdb/samdb/samdb.h"
33 #include "auth/auth.h"
35 #include "system/network.h"
36 #include "lib/socket/netif.h"
39 fill in the cldap netlogon union for a given version
41 static NTSTATUS
cldapd_netlogon_fill(struct cldapd_server
*cldapd
,
44 const char *domain_guid
,
46 const char *src_address
,
48 union nbt_cldap_netlogon
*netlogon
)
50 const char *ref_attrs
[] = {"nETBIOSName", "dnsRoot", "ncName", NULL
};
51 const char *dom_attrs
[] = {"objectGUID", NULL
};
52 struct ldb_message
**ref_res
, **dom_res
;
54 const char **services
= lp_server_services();
57 struct GUID domain_uuid
;
59 const char *dns_domain
;
60 const char *pdc_dns_name
;
62 const char *server_site
;
63 const char *client_site
;
65 const struct ldb_dn
*partitions_basedn
;
67 if (cldapd
->samctx
== NULL
) {
68 cldapd
->samctx
= samdb_connect(cldapd
, anonymous_session(cldapd
));
69 if (cldapd
->samctx
== NULL
) {
70 DEBUG(2,("Unable to open sam in cldap netlogon reply\n"));
71 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
75 partitions_basedn
= samdb_partitions_dn(cldapd
->samctx
, mem_ctx
);
77 /* the domain has an optional trailing . */
78 if (domain
&& domain
[strlen(domain
)-1] == '.') {
79 domain
= talloc_strndup(mem_ctx
, domain
, strlen(domain
)-1);
83 struct ldb_result
*dom_ldb_result
;
84 struct ldb_dn
*dom_dn
;
85 /* try and find the domain */
86 count
= gendb_search(cldapd
->samctx
, mem_ctx
, partitions_basedn
, &ref_res
, ref_attrs
,
87 "(&(&(objectClass=crossRef)(dnsRoot=%s))(nETBIOSName=*))",
90 dom_dn
= samdb_result_dn(mem_ctx
, ref_res
[0], "ncName", NULL
);
92 return NT_STATUS_NO_SUCH_DOMAIN
;
94 ret
= ldb_search(cldapd
->samctx
, dom_dn
,
95 LDB_SCOPE_BASE
, "objectClass=domain",
96 dom_attrs
, &dom_ldb_result
);
97 if (ret
!= LDB_SUCCESS
) {
98 DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", domain
, ldb_dn_linearize(mem_ctx
, dom_dn
), ldb_errstring(cldapd
->samctx
)));
99 return NT_STATUS_NO_SUCH_DOMAIN
;
101 talloc_steal(mem_ctx
, dom_ldb_result
);
102 if (dom_ldb_result
->count
!= 1) {
103 DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", domain
, ldb_dn_linearize(mem_ctx
, dom_dn
)));
104 return NT_STATUS_NO_SUCH_DOMAIN
;
106 dom_res
= dom_ldb_result
->msgs
;
110 if (count
== 0 && domain_guid
) {
111 /* OK, so no dice with the name, try and find the domain with the GUID */
112 count
= gendb_search(cldapd
->samctx
, mem_ctx
, NULL
, &dom_res
, dom_attrs
,
113 "(&(objectClass=domainDNS)(objectGUID=%s))",
116 /* try and find the domain */
117 ret
= gendb_search(cldapd
->samctx
, mem_ctx
, partitions_basedn
, &ref_res
, ref_attrs
,
118 "(&(objectClass=crossRef)(ncName=%s))",
119 ldb_dn_linearize(mem_ctx
, dom_res
[0]->dn
));
121 DEBUG(2,("Unable to find referece to '%s' in sam\n",
122 ldb_dn_linearize(mem_ctx
, dom_res
[0]->dn
)));
123 return NT_STATUS_NO_SUCH_DOMAIN
;
129 DEBUG(2,("Unable to find domain with name %s or GUID {%s}\n", domain
, domain_guid
));
130 return NT_STATUS_NO_SUCH_DOMAIN
;
134 NBT_SERVER_PDC
| NBT_SERVER_GC
|
135 NBT_SERVER_DS
| NBT_SERVER_TIMESERV
|
136 NBT_SERVER_CLOSEST
| NBT_SERVER_WRITABLE
|
137 NBT_SERVER_GOOD_TIMESERV
;
139 if (str_list_check(services
, "ldap")) {
140 server_type
|= NBT_SERVER_LDAP
;
143 if (str_list_check(services
, "kdc")) {
144 server_type
|= NBT_SERVER_KDC
;
147 pdc_name
= talloc_asprintf(mem_ctx
, "\\\\%s", lp_netbios_name());
148 domain_uuid
= samdb_result_guid(dom_res
[0], "objectGUID");
149 realm
= samdb_result_string(ref_res
[0], "dnsRoot", lp_realm());
150 dns_domain
= samdb_result_string(ref_res
[0], "dnsRoot", lp_realm());
151 pdc_dns_name
= talloc_asprintf(mem_ctx
, "%s.%s",
152 strlower_talloc(mem_ctx
, lp_netbios_name()),
155 flatname
= samdb_result_string(ref_res
[0], "nETBIOSName", lp_workgroup());
156 server_site
= "Default-First-Site-Name";
157 client_site
= "Default-First-Site-Name";
158 pdc_ip
= iface_best_ip(src_address
);
160 ZERO_STRUCTP(netlogon
);
162 switch (version
& 0xF) {
165 netlogon
->logon1
.type
= (user
?19+2:19);
166 netlogon
->logon1
.pdc_name
= pdc_name
;
167 netlogon
->logon1
.user_name
= user
;
168 netlogon
->logon1
.domain_name
= flatname
;
169 netlogon
->logon1
.nt_version
= 1;
170 netlogon
->logon1
.lmnt_token
= 0xFFFF;
171 netlogon
->logon1
.lm20_token
= 0xFFFF;
175 netlogon
->logon3
.type
= (user
?19+2:19);
176 netlogon
->logon3
.pdc_name
= pdc_name
;
177 netlogon
->logon3
.user_name
= user
;
178 netlogon
->logon3
.domain_name
= flatname
;
179 netlogon
->logon3
.domain_uuid
= domain_uuid
;
180 netlogon
->logon3
.forest
= realm
;
181 netlogon
->logon3
.dns_domain
= dns_domain
;
182 netlogon
->logon3
.pdc_dns_name
= pdc_dns_name
;
183 netlogon
->logon3
.pdc_ip
= pdc_ip
;
184 netlogon
->logon3
.server_type
= server_type
;
185 netlogon
->logon3
.lmnt_token
= 0xFFFF;
186 netlogon
->logon3
.lm20_token
= 0xFFFF;
192 netlogon
->logon5
.type
= (user
?23+2:23);
193 netlogon
->logon5
.server_type
= server_type
;
194 netlogon
->logon5
.domain_uuid
= domain_uuid
;
195 netlogon
->logon5
.forest
= realm
;
196 netlogon
->logon5
.dns_domain
= dns_domain
;
197 netlogon
->logon5
.pdc_dns_name
= pdc_dns_name
;
198 netlogon
->logon5
.domain
= flatname
;
199 netlogon
->logon5
.pdc_name
= lp_netbios_name();
200 netlogon
->logon5
.user_name
= user
;
201 netlogon
->logon5
.server_site
= server_site
;
202 netlogon
->logon5
.client_site
= client_site
;
203 netlogon
->logon5
.lmnt_token
= 0xFFFF;
204 netlogon
->logon5
.lm20_token
= 0xFFFF;
207 netlogon
->logon13
.type
= (user
?23+2:23);
208 netlogon
->logon13
.server_type
= server_type
;
209 netlogon
->logon13
.domain_uuid
= domain_uuid
;
210 netlogon
->logon13
.forest
= realm
;
211 netlogon
->logon13
.dns_domain
= dns_domain
;
212 netlogon
->logon13
.pdc_dns_name
= pdc_dns_name
;
213 netlogon
->logon13
.domain
= flatname
;
214 netlogon
->logon13
.pdc_name
= lp_netbios_name();
215 netlogon
->logon13
.user_name
= user
;
216 netlogon
->logon13
.server_site
= server_site
;
217 netlogon
->logon13
.client_site
= client_site
;
218 netlogon
->logon13
.unknown
= 10;
219 netlogon
->logon13
.unknown2
= 2;
220 netlogon
->logon13
.pdc_ip
= pdc_ip
;
221 netlogon
->logon13
.lmnt_token
= 0xFFFF;
222 netlogon
->logon13
.lm20_token
= 0xFFFF;
231 handle incoming cldap requests
233 void cldapd_netlogon_request(struct cldap_socket
*cldap
,
235 struct ldb_parse_tree
*tree
,
236 struct socket_address
*src
)
238 struct cldapd_server
*cldapd
= talloc_get_type(cldap
->incoming
.private, struct cldapd_server
);
240 const char *domain
= NULL
;
241 const char *host
= NULL
;
242 const char *user
= NULL
;
243 const char *domain_guid
= NULL
;
244 const char *domain_sid
= NULL
;
245 int acct_control
= -1;
247 union nbt_cldap_netlogon netlogon
;
248 NTSTATUS status
= NT_STATUS_INVALID_PARAMETER
;
250 TALLOC_CTX
*tmp_ctx
= talloc_new(cldap
);
252 if (tree
->operation
!= LDB_OP_AND
) goto failed
;
254 /* extract the query elements */
255 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
256 struct ldb_parse_tree
*t
= tree
->u
.list
.elements
[i
];
257 if (t
->operation
!= LDB_OP_EQUALITY
) goto failed
;
258 if (strcasecmp(t
->u
.equality
.attr
, "DnsDomain") == 0) {
259 domain
= talloc_strndup(tmp_ctx
,
260 (const char *)t
->u
.equality
.value
.data
,
261 t
->u
.equality
.value
.length
);
263 if (strcasecmp(t
->u
.equality
.attr
, "Host") == 0) {
264 host
= talloc_strndup(tmp_ctx
,
265 (const char *)t
->u
.equality
.value
.data
,
266 t
->u
.equality
.value
.length
);
268 if (strcasecmp(t
->u
.equality
.attr
, "DomainGuid") == 0) {
271 enc_status
= ldap_decode_ndr_GUID(tmp_ctx
,
272 t
->u
.equality
.value
, &guid
);
273 if (NT_STATUS_IS_OK(enc_status
)) {
274 domain_guid
= GUID_string(tmp_ctx
, &guid
);
277 if (strcasecmp(t
->u
.equality
.attr
, "DomainSid") == 0) {
278 domain_sid
= talloc_strndup(tmp_ctx
,
279 (const char *)t
->u
.equality
.value
.data
,
280 t
->u
.equality
.value
.length
);
282 if (strcasecmp(t
->u
.equality
.attr
, "User") == 0) {
283 user
= talloc_strndup(tmp_ctx
,
284 (const char *)t
->u
.equality
.value
.data
,
285 t
->u
.equality
.value
.length
);
287 if (strcasecmp(t
->u
.equality
.attr
, "NtVer") == 0 &&
288 t
->u
.equality
.value
.length
== 4) {
289 version
= IVAL(t
->u
.equality
.value
.data
, 0);
291 if (strcasecmp(t
->u
.equality
.attr
, "AAC") == 0 &&
292 t
->u
.equality
.value
.length
== 4) {
293 acct_control
= IVAL(t
->u
.equality
.value
.data
, 0);
297 if (domain_guid
== NULL
&& domain
== NULL
) {
305 DEBUG(5,("cldap netlogon query domain=%s host=%s user=%s version=%d guid=%s\n",
306 domain
, host
, user
, version
, domain_guid
));
308 status
= cldapd_netlogon_fill(cldapd
, tmp_ctx
, domain
, domain_guid
,
311 if (!NT_STATUS_IS_OK(status
)) {
315 status
= cldap_netlogon_reply(cldap
, message_id
, src
, version
,
317 if (!NT_STATUS_IS_OK(status
)) {
321 talloc_free(tmp_ctx
);
325 DEBUG(2,("cldap netlogon query failed domain=%s host=%s version=%d - %s\n",
326 domain
, host
, version
, nt_errstr(status
)));
327 talloc_free(tmp_ctx
);
328 cldap_empty_reply(cldap
, message_id
, src
);