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/events/events.h"
26 #include "lib/socket/socket.h"
27 #include "smbd/service_task.h"
28 #include "cldap_server/cldap_server.h"
31 fill in the cldap netlogon union for a given version
33 static NTSTATUS
cldapd_netlogon_fill(struct cldapd_server
*cldapd
,
36 const char *domain_guid
,
38 const char *src_address
,
40 union nbt_cldap_netlogon
*netlogon
)
42 const char *ref_attrs
[] = {"nETBIOSName", NULL
};
43 const char *dom_attrs
[] = {"dnsDomain", "objectGUID", NULL
};
44 struct ldb_message
**ref_res
, **dom_res
;
46 const char **services
= lp_server_services();
49 struct GUID domain_uuid
;
51 const char *dns_domain
;
52 const char *pdc_dns_name
;
54 const char *site_name
;
55 const char *site_name2
;
58 if (cldapd
->samctx
== NULL
) {
59 cldapd
->samctx
= samdb_connect(cldapd
, anonymous_session(cldapd
));
60 if (cldapd
->samctx
== NULL
) {
61 DEBUG(2,("Unable to open sam in cldap netlogon reply\n"));
62 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
66 /* the domain has an optional trailing . */
67 if (domain
&& domain
[strlen(domain
)-1] == '.') {
68 domain
= talloc_strndup(mem_ctx
, domain
, strlen(domain
)-1);
71 /* try and find the domain */
72 ret
= gendb_search(cldapd
->samctx
, mem_ctx
, NULL
, &dom_res
, dom_attrs
,
73 "(&(objectClass=domainDNS)(|(dnsDomain=%s)(objectGUID=%s)))",
75 domain_guid
?domain_guid
:"");
77 DEBUG(2,("Unable to find domain '%s' in sam\n", domain
));
78 return NT_STATUS_NO_SUCH_DOMAIN
;
81 /* try and find the domain */
82 ret
= gendb_search(cldapd
->samctx
, mem_ctx
, NULL
, &ref_res
, ref_attrs
,
83 "(&(objectClass=crossRef)(ncName=%s))",
84 ldb_dn_linearize(mem_ctx
, dom_res
[0]->dn
));
86 DEBUG(2,("Unable to find referece to '%s' in sam\n",
87 ldb_dn_linearize(mem_ctx
, dom_res
[0]->dn
)));
88 return NT_STATUS_NO_SUCH_DOMAIN
;
92 NBT_SERVER_PDC
| NBT_SERVER_GC
|
93 NBT_SERVER_DS
| NBT_SERVER_TIMESERV
|
94 NBT_SERVER_CLOSEST
| NBT_SERVER_WRITABLE
|
95 NBT_SERVER_GOOD_TIMESERV
;
97 if (str_list_check(services
, "ldap")) {
98 server_type
|= NBT_SERVER_LDAP
;
101 if (str_list_check(services
, "kdc")) {
102 server_type
|= NBT_SERVER_KDC
;
105 pdc_name
= talloc_asprintf(mem_ctx
, "\\\\%s", lp_netbios_name());
106 domain_uuid
= samdb_result_guid(dom_res
[0], "objectGUID");
107 realm
= samdb_result_string(dom_res
[0], "dnsDomain", lp_realm());
108 dns_domain
= samdb_result_string(dom_res
[0], "dnsDomain", lp_realm());
109 pdc_dns_name
= talloc_asprintf(mem_ctx
, "%s.%s",
110 strlower_talloc(mem_ctx
, lp_netbios_name()),
113 flatname
= samdb_result_string(ref_res
[0], "nETBIOSName", lp_workgroup());
114 site_name
= "Default-First-Site-Name";
115 site_name2
= "Default-First-Site-Name";
116 pdc_ip
= iface_best_ip(src_address
);
118 ZERO_STRUCTP(netlogon
);
120 switch (version
& 0xF) {
123 netlogon
->logon1
.type
= (user
?19+2:19);
124 netlogon
->logon1
.pdc_name
= pdc_name
;
125 netlogon
->logon1
.user_name
= user
;
126 netlogon
->logon1
.domain_name
= flatname
;
127 netlogon
->logon1
.nt_version
= 1;
128 netlogon
->logon1
.lmnt_token
= 0xFFFF;
129 netlogon
->logon1
.lm20_token
= 0xFFFF;
133 netlogon
->logon3
.type
= (user
?19+2:19);
134 netlogon
->logon3
.pdc_name
= pdc_name
;
135 netlogon
->logon3
.user_name
= user
;
136 netlogon
->logon3
.domain_name
= flatname
;
137 netlogon
->logon3
.domain_uuid
= domain_uuid
;
138 netlogon
->logon3
.forest
= realm
;
139 netlogon
->logon3
.dns_domain
= dns_domain
;
140 netlogon
->logon3
.pdc_dns_name
= pdc_dns_name
;
141 netlogon
->logon3
.pdc_ip
= pdc_ip
;
142 netlogon
->logon3
.server_type
= server_type
;
143 netlogon
->logon3
.lmnt_token
= 0xFFFF;
144 netlogon
->logon3
.lm20_token
= 0xFFFF;
150 netlogon
->logon5
.type
= (user
?23+2:23);
151 netlogon
->logon5
.server_type
= server_type
;
152 netlogon
->logon5
.domain_uuid
= domain_uuid
;
153 netlogon
->logon5
.forest
= realm
;
154 netlogon
->logon5
.dns_domain
= dns_domain
;
155 netlogon
->logon5
.pdc_dns_name
= pdc_dns_name
;
156 netlogon
->logon5
.domain
= flatname
;
157 netlogon
->logon5
.pdc_name
= lp_netbios_name();
158 netlogon
->logon5
.user_name
= user
;
159 netlogon
->logon5
.site_name
= site_name
;
160 netlogon
->logon5
.site_name2
= site_name2
;
161 netlogon
->logon5
.lmnt_token
= 0xFFFF;
162 netlogon
->logon5
.lm20_token
= 0xFFFF;
165 netlogon
->logon13
.type
= (user
?23+2:23);
166 netlogon
->logon13
.server_type
= server_type
;
167 netlogon
->logon13
.domain_uuid
= domain_uuid
;
168 netlogon
->logon13
.forest
= realm
;
169 netlogon
->logon13
.dns_domain
= dns_domain
;
170 netlogon
->logon13
.pdc_dns_name
= pdc_dns_name
;
171 netlogon
->logon13
.domain
= flatname
;
172 netlogon
->logon13
.pdc_name
= lp_netbios_name();
173 netlogon
->logon13
.user_name
= user
;
174 netlogon
->logon13
.site_name
= site_name
;
175 netlogon
->logon13
.site_name2
= site_name2
;
176 netlogon
->logon13
.unknown
= 10;
177 netlogon
->logon13
.unknown2
= 2;
178 netlogon
->logon13
.pdc_ip
= pdc_ip
;
179 netlogon
->logon13
.lmnt_token
= 0xFFFF;
180 netlogon
->logon13
.lm20_token
= 0xFFFF;
189 handle incoming cldap requests
191 void cldapd_netlogon_request(struct cldap_socket
*cldap
,
193 struct ldb_parse_tree
*tree
,
194 const char *src_address
, int src_port
)
196 struct cldapd_server
*cldapd
= talloc_get_type(cldap
->incoming
.private, struct cldapd_server
);
198 const char *domain
= NULL
;
199 const char *host
= NULL
;
200 const char *user
= NULL
;
201 const char *domain_guid
= NULL
;
202 const char *domain_sid
= NULL
;
203 int acct_control
= -1;
205 union nbt_cldap_netlogon netlogon
;
206 NTSTATUS status
= NT_STATUS_INVALID_PARAMETER
;
208 TALLOC_CTX
*tmp_ctx
= talloc_new(cldap
);
210 if (tree
->operation
!= LDB_OP_AND
) goto failed
;
212 /* extract the query elements */
213 for (i
=0;i
<tree
->u
.list
.num_elements
;i
++) {
214 struct ldb_parse_tree
*t
= tree
->u
.list
.elements
[i
];
215 if (t
->operation
!= LDB_OP_EQUALITY
) goto failed
;
216 if (strcasecmp(t
->u
.equality
.attr
, "DnsDomain") == 0) {
217 domain
= talloc_strndup(tmp_ctx
,
218 t
->u
.equality
.value
.data
,
219 t
->u
.equality
.value
.length
);
221 if (strcasecmp(t
->u
.equality
.attr
, "Host") == 0) {
222 host
= talloc_strndup(tmp_ctx
,
223 t
->u
.equality
.value
.data
,
224 t
->u
.equality
.value
.length
);
226 if (strcasecmp(t
->u
.equality
.attr
, "DomainGuid") == 0) {
229 enc_status
= ldap_decode_ndr_GUID(tmp_ctx
,
230 t
->u
.equality
.value
, &guid
);
231 if (NT_STATUS_IS_OK(enc_status
)) {
232 domain_guid
= GUID_string(tmp_ctx
, &guid
);
235 if (strcasecmp(t
->u
.equality
.attr
, "DomainSid") == 0) {
236 domain_sid
= talloc_strndup(tmp_ctx
,
237 t
->u
.equality
.value
.data
,
238 t
->u
.equality
.value
.length
);
240 if (strcasecmp(t
->u
.equality
.attr
, "User") == 0) {
241 user
= talloc_strndup(tmp_ctx
,
242 t
->u
.equality
.value
.data
,
243 t
->u
.equality
.value
.length
);
245 if (strcasecmp(t
->u
.equality
.attr
, "NtVer") == 0 &&
246 t
->u
.equality
.value
.length
== 4) {
247 version
= IVAL(t
->u
.equality
.value
.data
, 0);
249 if (strcasecmp(t
->u
.equality
.attr
, "AAC") == 0 &&
250 t
->u
.equality
.value
.length
== 4) {
251 acct_control
= IVAL(t
->u
.equality
.value
.data
, 0);
255 if (domain_guid
== NULL
&& domain
== NULL
) {
263 DEBUG(5,("cldap netlogon query domain=%s host=%s user=%s version=%d guid=%s\n",
264 domain
, host
, user
, version
, domain_guid
));
266 status
= cldapd_netlogon_fill(cldapd
, tmp_ctx
, domain
, domain_guid
,
269 if (!NT_STATUS_IS_OK(status
)) {
273 status
= cldap_netlogon_reply(cldap
, message_id
, src_address
, src_port
, version
,
275 if (!NT_STATUS_IS_OK(status
)) {
279 talloc_free(tmp_ctx
);
283 DEBUG(2,("cldap netlogon query failed domain=%s host=%s version=%d - %s\n",
284 domain
, host
, version
, nt_errstr(status
)));
285 talloc_free(tmp_ctx
);
286 cldap_empty_reply(cldap
, message_id
, src_address
, src_port
);