2 Samba Unix/Linux SMB client library
3 net ads cldap functions
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "../utils/net.h"
27 struct netlogon_string
{
33 struct cldap_netlogon_reply
{
38 struct netlogon_string forest
;
39 struct netlogon_string domain
;
40 struct netlogon_string hostname
;
42 struct netlogon_string netbios_domain
;
43 struct netlogon_string netbios_hostname
;
45 struct netlogon_string user_name
;
46 struct netlogon_string site_name
;
48 struct netlogon_string unk0
;
56 These strings are rather interesting... They are composed of a series of
57 length encoded strings, terminated by either 1) a zero length string or 2)
58 a 0xc0 byte with what appears to be a one byte flags immediately following.
60 static unsigned pull_netlogon_string(struct netlogon_string
*ret
,const char *d
)
62 const char *p
= (const char *)d
;
67 unsigned len
= (unsigned char)*p
;
70 if (len
> 0 && len
!= 0xc0) {
71 ret
->component
= realloc(ret
->component
,
75 ret
->component
[ret
->comp_len
- 1] =
91 do a cldap netlogon query
93 static int send_cldap_netlogon(int sock
, const char *domain
,
94 const char *hostname
, unsigned ntversion
)
99 SIVAL(ntver
, 0, ntversion
);
101 memset(&data
, 0, sizeof(data
));
103 asn1_push_tag(&data
,ASN1_SEQUENCE(0));
104 asn1_write_Integer(&data
, 4);
105 asn1_push_tag(&data
, ASN1_APPLICATION(3));
106 asn1_write_OctetString(&data
, NULL
, 0);
107 asn1_write_enumerated(&data
, 0);
108 asn1_write_enumerated(&data
, 0);
109 asn1_write_Integer(&data
, 0);
110 asn1_write_Integer(&data
, 0);
111 asn1_write_BOOLEAN2(&data
, False
);
112 asn1_push_tag(&data
, ASN1_CONTEXT(0));
114 asn1_push_tag(&data
, ASN1_CONTEXT(3));
115 asn1_write_OctetString(&data
, "DnsDomain", 9);
116 asn1_write_OctetString(&data
, domain
, strlen(domain
));
119 asn1_push_tag(&data
, ASN1_CONTEXT(3));
120 asn1_write_OctetString(&data
, "Host", 4);
121 asn1_write_OctetString(&data
, hostname
, strlen(hostname
));
124 asn1_push_tag(&data
, ASN1_CONTEXT(3));
125 asn1_write_OctetString(&data
, "NtVer", 5);
126 asn1_write_OctetString(&data
, ntver
, 4);
131 asn1_push_tag(&data
,ASN1_SEQUENCE(0));
132 asn1_write_OctetString(&data
, "NetLogon", 8);
137 if (data
.has_error
) {
138 d_printf("Failed to build cldap netlogon at offset %d\n", (int)data
.ofs
);
143 if (write(sock
, data
.data
, data
.length
) != (ssize_t
)data
.length
) {
144 d_printf("failed to send cldap query (%s)\n", strerror(errno
));
147 file_save("cldap_query.dat", data
.data
, data
.length
);
155 receive a cldap netlogon reply
157 static int recv_cldap_netlogon(int sock
, struct cldap_netlogon_reply
*reply
)
162 DATA_BLOB os1
, os2
, os3
;
166 blob
= data_blob(NULL
, 8192);
168 ret
= read(sock
, blob
.data
, blob
.length
);
171 d_printf("no reply received to cldap netlogon\n");
176 file_save("cldap_reply.dat", blob
.data
, blob
.length
);
178 asn1_load(&data
, blob
);
179 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
180 asn1_read_Integer(&data
, &i1
);
181 asn1_start_tag(&data
, ASN1_APPLICATION(4));
182 asn1_read_OctetString(&data
, &os1
);
183 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
184 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
185 asn1_read_OctetString(&data
, &os2
);
186 asn1_start_tag(&data
, ASN1_SET
);
187 asn1_read_OctetString(&data
, &os3
);
194 if (data
.has_error
) {
195 d_printf("Failed to parse cldap reply\n");
199 file_save("cldap_reply_core.dat", os3
.data
, os3
.length
);
203 reply
->type
= IVAL(p
, 0); p
+= 4;
204 reply
->flags
= IVAL(p
, 0); p
+= 4;
206 memcpy(&reply
->guid
.info
, p
, GUID_SIZE
);
209 p
+= pull_netlogon_string(&reply
->forest
, p
);
210 p
+= pull_netlogon_string(&reply
->domain
, p
);
211 p
+= pull_netlogon_string(&reply
->hostname
, p
);
212 p
+= pull_netlogon_string(&reply
->netbios_domain
, p
);
213 p
+= pull_netlogon_string(&reply
->netbios_hostname
, p
);
214 p
+= pull_netlogon_string(&reply
->user_name
, p
);
215 p
+= pull_netlogon_string(&reply
->site_name
, p
);
217 p
+= pull_netlogon_string(&reply
->unk0
, p
);
219 reply
->version
= IVAL(p
, 0);
220 reply
->lmnt_token
= SVAL(p
, 4);
221 reply
->lm20_token
= SVAL(p
, 6);
223 data_blob_free(&os1
);
224 data_blob_free(&os2
);
225 data_blob_free(&os3
);
226 data_blob_free(&blob
);
232 free a netlogon string
234 static void netlogon_string_free(struct netlogon_string
*str
)
238 for (i
= 0; i
< str
->comp_len
; ++i
) {
239 SAFE_FREE(str
->component
[i
]);
241 SAFE_FREE(str
->component
);
245 free a cldap reply packet
247 static void cldap_reply_free(struct cldap_netlogon_reply
*reply
)
249 netlogon_string_free(&reply
->forest
);
250 netlogon_string_free(&reply
->domain
);
251 netlogon_string_free(&reply
->hostname
);
252 netlogon_string_free(&reply
->netbios_domain
);
253 netlogon_string_free(&reply
->netbios_hostname
);
254 netlogon_string_free(&reply
->user_name
);
255 netlogon_string_free(&reply
->site_name
);
256 netlogon_string_free(&reply
->unk0
);
259 static void d_print_netlogon_string(const char *label
,
260 struct netlogon_string
*str
)
265 d_printf("%s", label
);
266 if (str
->extra_flag
) {
267 d_printf("[%d]", str
->extra_flag
);
270 for (i
= 0; i
< str
->comp_len
; ++i
) {
271 d_printf("%s%s", (i
? "." : ""), str
->component
[i
]);
278 do a cldap netlogon query
280 int ads_cldap_netlogon(ADS_STRUCT
*ads
)
284 struct cldap_netlogon_reply reply
;
286 sock
= open_udp_socket(inet_ntoa(ads
->ldap_ip
), ads
->ldap_port
);
288 d_printf("Failed to open udp socket to %s:%u\n",
289 inet_ntoa(ads
->ldap_ip
),
294 ret
= send_cldap_netlogon(sock
, ads
->config
.realm
, global_myname(), 6);
298 ret
= recv_cldap_netlogon(sock
, &reply
);
305 d_printf("Information for Domain Controller: %s\n\n",
306 ads
->config
.ldap_server_name
);
308 d_printf("Response Type: 0x%x\n", reply
.type
);
310 print_guid(&reply
.guid
);
313 "\tIs a GC of the forest: %s\n"
314 "\tIs an LDAP server: %s\n"
315 "\tSupports DS: %s\n"
316 "\tIs running a KDC: %s\n"
317 "\tIs running time services: %s\n"
318 "\tIs the closest DC: %s\n"
319 "\tIs writable: %s\n"
320 "\tHas a hardware clock: %s\n"
321 "\tIs a non-domain NC serviced by LDAP server: %s\n",
322 (reply
.flags
& ADS_PDC
) ? "yes" : "no",
323 (reply
.flags
& ADS_GC
) ? "yes" : "no",
324 (reply
.flags
& ADS_LDAP
) ? "yes" : "no",
325 (reply
.flags
& ADS_DS
) ? "yes" : "no",
326 (reply
.flags
& ADS_KDC
) ? "yes" : "no",
327 (reply
.flags
& ADS_TIMESERV
) ? "yes" : "no",
328 (reply
.flags
& ADS_CLOSEST
) ? "yes" : "no",
329 (reply
.flags
& ADS_WRITABLE
) ? "yes" : "no",
330 (reply
.flags
& ADS_GOOD_TIMESERV
) ? "yes" : "no",
331 (reply
.flags
& ADS_NDNC
) ? "yes" : "no");
333 d_print_netlogon_string("Forest", &reply
.forest
);
334 d_print_netlogon_string("Domain", &reply
.domain
);
335 d_print_netlogon_string("Hostname", &reply
.hostname
);
337 d_print_netlogon_string("Pre-Win2k Domain", &reply
.netbios_domain
);
338 d_print_netlogon_string("Pre-Win2k Hostname", &reply
.netbios_hostname
);
340 d_print_netlogon_string("User name", &reply
.user_name
);
341 d_print_netlogon_string("Site Name", &reply
.site_name
);
342 d_print_netlogon_string("Unknown Field", &reply
.unk0
);
344 d_printf("NT Version: %d\n", reply
.version
);
345 d_printf("LMNT Token: %.2x\n", reply
.lmnt_token
);
346 d_printf("LM20 Token: %.2x\n", reply
.lm20_token
);
348 cldap_reply_free(&reply
);