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 #define MAX_DNS_LABEL 255 + 1
29 struct cldap_netlogon_reply
{
34 char forest
[MAX_DNS_LABEL
];
35 char domain
[MAX_DNS_LABEL
];
36 char hostname
[MAX_DNS_LABEL
];
38 char netbios_domain
[MAX_DNS_LABEL
];
39 char netbios_hostname
[MAX_DNS_LABEL
];
41 char unk
[MAX_DNS_LABEL
];
42 char user_name
[MAX_DNS_LABEL
];
43 char site_name
[MAX_DNS_LABEL
];
44 char site_name_2
[MAX_DNS_LABEL
];
52 These seem to be strings as described in RFC1035 4.1.4 and can be:
54 - a sequence of labels ending in a zero octet
56 - a sequence of labels ending with a pointer
58 A label is a byte where the first two bits must be zero and the remaining
59 bits represent the length of the label followed by the label itself.
60 Therefore, the length of a label is at max 64 bytes. Under RFC1035, a
61 sequence of labels cannot exceed 255 bytes.
63 A pointer consists of a 14 bit offset from the beginning of the data.
66 unsigned ident:2; // must be 11
67 unsigned offset:14; // from the beginning of data
70 This is used as a method to compress the packet by eliminated duplicate
71 domain components. Since a UDP packet should probably be < 512 bytes and a
72 DNS name can be up to 255 bytes, this actually makes a lot of sense.
74 static unsigned pull_netlogon_string(char *ret
, const char *ptr
,
81 memset(pret
, 0, MAX_DNS_LABEL
);
83 if ((*ptr
& 0xc0) == 0xc0) {
90 len
= ((ptr
[0] & 0x3f) << 8) | ptr
[1];
93 uint8 len
= (uint8
)*(ptr
++);
95 if ((pret
- ret
+ len
+ 1) >= MAX_DNS_LABEL
) {
96 d_fprintf(stderr
, "DC returning too long DNS name\n");
104 memcpy(pret
, ptr
, len
);
109 ret_len
+= (len
+ 1);
114 return followed_ptr
? ret_len
: ret_len
+ 1;
118 do a cldap netlogon query
120 static int send_cldap_netlogon(int sock
, const char *domain
,
121 const char *hostname
, unsigned ntversion
)
125 #ifdef CLDAP_USER_QUERY
128 SIVAL(aac
, 0, 0x00000180);
130 SIVAL(ntver
, 0, ntversion
);
132 memset(&data
, 0, sizeof(data
));
134 asn1_push_tag(&data
,ASN1_SEQUENCE(0));
135 asn1_write_Integer(&data
, 4);
136 asn1_push_tag(&data
, ASN1_APPLICATION(3));
137 asn1_write_OctetString(&data
, NULL
, 0);
138 asn1_write_enumerated(&data
, 0);
139 asn1_write_enumerated(&data
, 0);
140 asn1_write_Integer(&data
, 0);
141 asn1_write_Integer(&data
, 0);
142 asn1_write_BOOLEAN2(&data
, False
);
143 asn1_push_tag(&data
, ASN1_CONTEXT(0));
145 asn1_push_tag(&data
, ASN1_CONTEXT(3));
146 asn1_write_OctetString(&data
, "DnsDomain", 9);
147 asn1_write_OctetString(&data
, domain
, strlen(domain
));
150 asn1_push_tag(&data
, ASN1_CONTEXT(3));
151 asn1_write_OctetString(&data
, "Host", 4);
152 asn1_write_OctetString(&data
, hostname
, strlen(hostname
));
155 #ifdef CLDAP_USER_QUERY
156 asn1_push_tag(&data
, ASN1_CONTEXT(3));
157 asn1_write_OctetString(&data
, "User", 4);
158 asn1_write_OctetString(&data
, "SAMBA$", 6);
161 asn1_push_tag(&data
, ASN1_CONTEXT(3));
162 asn1_write_OctetString(&data
, "AAC", 4);
163 asn1_write_OctetString(&data
, aac
, 4);
167 asn1_push_tag(&data
, ASN1_CONTEXT(3));
168 asn1_write_OctetString(&data
, "NtVer", 5);
169 asn1_write_OctetString(&data
, ntver
, 4);
174 asn1_push_tag(&data
,ASN1_SEQUENCE(0));
175 asn1_write_OctetString(&data
, "NetLogon", 8);
180 if (data
.has_error
) {
181 d_fprintf(stderr
, "Failed to build cldap netlogon at offset %d\n", (int)data
.ofs
);
186 if (write(sock
, data
.data
, data
.length
) != (ssize_t
)data
.length
) {
187 d_fprintf(stderr
, "failed to send cldap query (%s)\n", strerror(errno
));
197 receive a cldap netlogon reply
199 static int recv_cldap_netlogon(int sock
, struct cldap_netlogon_reply
*reply
)
204 DATA_BLOB os1
, os2
, os3
;
208 blob
= data_blob(NULL
, 8192);
210 ret
= read(sock
, blob
.data
, blob
.length
);
213 d_fprintf(stderr
, "no reply received to cldap netlogon\n");
218 asn1_load(&data
, blob
);
219 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
220 asn1_read_Integer(&data
, &i1
);
221 asn1_start_tag(&data
, ASN1_APPLICATION(4));
222 asn1_read_OctetString(&data
, &os1
);
223 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
224 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
225 asn1_read_OctetString(&data
, &os2
);
226 asn1_start_tag(&data
, ASN1_SET
);
227 asn1_read_OctetString(&data
, &os3
);
234 if (data
.has_error
) {
235 d_fprintf(stderr
, "Failed to parse cldap reply\n");
239 p
= (char *)os3
.data
;
241 reply
->type
= IVAL(p
, 0); p
+= 4;
242 reply
->flags
= IVAL(p
, 0); p
+= 4;
244 memcpy(&reply
->guid
.info
, p
, UUID_FLAT_SIZE
);
247 p
+= pull_netlogon_string(reply
->forest
, p
, (const char *)os3
.data
);
248 p
+= pull_netlogon_string(reply
->domain
, p
, (const char *)os3
.data
);
249 p
+= pull_netlogon_string(reply
->hostname
, p
, (const char *)os3
.data
);
250 p
+= pull_netlogon_string(reply
->netbios_domain
, p
, (const char *)os3
.data
);
251 p
+= pull_netlogon_string(reply
->netbios_hostname
, p
, (const char *)os3
.data
);
252 p
+= pull_netlogon_string(reply
->unk
, p
, (const char *)os3
.data
);
254 if (reply
->type
== SAMLOGON_AD_R
) {
255 p
+= pull_netlogon_string(reply
->user_name
, p
, (const char *)os3
.data
);
257 *reply
->user_name
= 0;
260 p
+= pull_netlogon_string(reply
->site_name
, p
, (const char *)os3
.data
);
261 p
+= pull_netlogon_string(reply
->site_name_2
, p
, (const char *)os3
.data
);
263 reply
->version
= IVAL(p
, 0);
264 reply
->lmnt_token
= SVAL(p
, 4);
265 reply
->lm20_token
= SVAL(p
, 6);
267 data_blob_free(&os1
);
268 data_blob_free(&os2
);
269 data_blob_free(&os3
);
270 data_blob_free(&blob
);
276 do a cldap netlogon query
278 int ads_cldap_netlogon(ADS_STRUCT
*ads
)
282 struct cldap_netlogon_reply reply
;
283 const char *target
= opt_host
? opt_host
: inet_ntoa(ads
->ldap_ip
);
285 sock
= open_udp_socket(target
, ads
->ldap_port
);
287 d_fprintf(stderr
, "Failed to open udp socket to %s:%u\n",
288 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: ");
309 switch (reply
.type
) {
310 case SAMLOGON_AD_UNK_R
:
311 d_printf("SAMLOGON\n");
314 d_printf("SAMLOGON_USER\n");
317 d_printf("0x%x\n", reply
.type
);
320 d_printf("GUID: %s\n",
321 smb_uuid_string_static(smb_uuid_unpack_static(reply
.guid
)));
324 "\tIs a GC of the forest: %s\n"
325 "\tIs an LDAP server: %s\n"
326 "\tSupports DS: %s\n"
327 "\tIs running a KDC: %s\n"
328 "\tIs running time services: %s\n"
329 "\tIs the closest DC: %s\n"
330 "\tIs writable: %s\n"
331 "\tHas a hardware clock: %s\n"
332 "\tIs a non-domain NC serviced by LDAP server: %s\n",
333 (reply
.flags
& ADS_PDC
) ? "yes" : "no",
334 (reply
.flags
& ADS_GC
) ? "yes" : "no",
335 (reply
.flags
& ADS_LDAP
) ? "yes" : "no",
336 (reply
.flags
& ADS_DS
) ? "yes" : "no",
337 (reply
.flags
& ADS_KDC
) ? "yes" : "no",
338 (reply
.flags
& ADS_TIMESERV
) ? "yes" : "no",
339 (reply
.flags
& ADS_CLOSEST
) ? "yes" : "no",
340 (reply
.flags
& ADS_WRITABLE
) ? "yes" : "no",
341 (reply
.flags
& ADS_GOOD_TIMESERV
) ? "yes" : "no",
342 (reply
.flags
& ADS_NDNC
) ? "yes" : "no");
344 printf("Forest:\t\t\t%s\n", reply
.forest
);
345 printf("Domain:\t\t\t%s\n", reply
.domain
);
346 printf("Domain Controller:\t%s\n", reply
.hostname
);
348 printf("Pre-Win2k Domain:\t%s\n", reply
.netbios_domain
);
349 printf("Pre-Win2k Hostname:\t%s\n", reply
.netbios_hostname
);
351 if (*reply
.unk
) printf("Unk:\t\t\t%s\n", reply
.unk
);
352 if (*reply
.user_name
) printf("User name:\t%s\n", reply
.user_name
);
354 printf("Site Name:\t\t%s\n", reply
.site_name
);
355 printf("Site Name (2):\t\t%s\n", reply
.site_name_2
);
357 d_printf("NT Version: %d\n", reply
.version
);
358 d_printf("LMNT Token: %.2x\n", reply
.lmnt_token
);
359 d_printf("LM20 Token: %.2x\n", reply
.lm20_token
);