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.
25 These seem to be strings as described in RFC1035 4.1.4 and can be:
27 - a sequence of labels ending in a zero octet
29 - a sequence of labels ending with a pointer
31 A label is a byte where the first two bits must be zero and the remaining
32 bits represent the length of the label followed by the label itself.
33 Therefore, the length of a label is at max 64 bytes. Under RFC1035, a
34 sequence of labels cannot exceed 255 bytes.
36 A pointer consists of a 14 bit offset from the beginning of the data.
39 unsigned ident:2; // must be 11
40 unsigned offset:14; // from the beginning of data
43 This is used as a method to compress the packet by eliminated duplicate
44 domain components. Since a UDP packet should probably be < 512 bytes and a
45 DNS name can be up to 255 bytes, this actually makes a lot of sense.
47 static unsigned pull_netlogon_string(char *ret
, const char *ptr
,
54 memset(pret
, 0, MAX_DNS_LABEL
);
56 if ((*ptr
& 0xc0) == 0xc0) {
63 len
= ((ptr
[0] & 0x3f) << 8) | ptr
[1];
66 uint8 len
= (uint8
)*(ptr
++);
68 if ((pret
- ret
+ len
+ 1) >= MAX_DNS_LABEL
) {
69 DEBUG(1,("DC returning too long DNS name\n"));
77 memcpy(pret
, ptr
, len
);
87 return followed_ptr
? ret_len
: ret_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
)
98 #ifdef CLDAP_USER_QUERY
101 SIVAL(aac
, 0, 0x00000180);
103 SIVAL(ntver
, 0, ntversion
);
105 memset(&data
, 0, sizeof(data
));
107 asn1_push_tag(&data
,ASN1_SEQUENCE(0));
108 asn1_write_Integer(&data
, 4);
109 asn1_push_tag(&data
, ASN1_APPLICATION(3));
110 asn1_write_OctetString(&data
, NULL
, 0);
111 asn1_write_enumerated(&data
, 0);
112 asn1_write_enumerated(&data
, 0);
113 asn1_write_Integer(&data
, 0);
114 asn1_write_Integer(&data
, 0);
115 asn1_write_BOOLEAN2(&data
, False
);
116 asn1_push_tag(&data
, ASN1_CONTEXT(0));
118 asn1_push_tag(&data
, ASN1_CONTEXT(3));
119 asn1_write_OctetString(&data
, "DnsDomain", 9);
120 asn1_write_OctetString(&data
, domain
, strlen(domain
));
123 asn1_push_tag(&data
, ASN1_CONTEXT(3));
124 asn1_write_OctetString(&data
, "Host", 4);
125 asn1_write_OctetString(&data
, hostname
, strlen(hostname
));
128 #ifdef CLDAP_USER_QUERY
129 asn1_push_tag(&data
, ASN1_CONTEXT(3));
130 asn1_write_OctetString(&data
, "User", 4);
131 asn1_write_OctetString(&data
, "SAMBA$", 6);
134 asn1_push_tag(&data
, ASN1_CONTEXT(3));
135 asn1_write_OctetString(&data
, "AAC", 4);
136 asn1_write_OctetString(&data
, aac
, 4);
140 asn1_push_tag(&data
, ASN1_CONTEXT(3));
141 asn1_write_OctetString(&data
, "NtVer", 5);
142 asn1_write_OctetString(&data
, ntver
, 4);
147 asn1_push_tag(&data
,ASN1_SEQUENCE(0));
148 asn1_write_OctetString(&data
, "NetLogon", 8);
153 if (data
.has_error
) {
154 DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data
.ofs
));
159 if (write(sock
, data
.data
, data
.length
) != (ssize_t
)data
.length
) {
160 DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno
)));
168 static SIG_ATOMIC_T gotalarm
;
170 /***************************************************************
171 Signal function to tell us we timed out.
172 ****************************************************************/
174 static void gotalarm_sig(void)
180 receive a cldap netlogon reply
182 static int recv_cldap_netlogon(int sock
, struct cldap_netlogon_reply
*reply
)
187 DATA_BLOB os1
, os2
, os3
;
191 blob
= data_blob(NULL
, 8192);
195 CatchSignal(SIGALRM
, SIGNAL_CAST gotalarm_sig
);
196 alarm(lp_ldap_timeout());
197 /* End setup timeout. */
199 ret
= read(sock
, blob
.data
, blob
.length
);
201 /* Teardown timeout. */
202 CatchSignal(SIGALRM
, SIGNAL_CAST SIG_IGN
);
206 DEBUG(1,("no reply received to cldap netlogon\n"));
211 asn1_load(&data
, blob
);
212 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
213 asn1_read_Integer(&data
, &i1
);
214 asn1_start_tag(&data
, ASN1_APPLICATION(4));
215 asn1_read_OctetString(&data
, &os1
);
216 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
217 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
218 asn1_read_OctetString(&data
, &os2
);
219 asn1_start_tag(&data
, ASN1_SET
);
220 asn1_read_OctetString(&data
, &os3
);
227 if (data
.has_error
) {
229 DEBUG(1,("Failed to parse cldap reply\n"));
233 p
= (char *)os3
.data
;
235 reply
->type
= IVAL(p
, 0); p
+= 4;
236 reply
->flags
= IVAL(p
, 0); p
+= 4;
238 memcpy(&reply
->guid
.info
, p
, UUID_FLAT_SIZE
);
241 p
+= pull_netlogon_string(reply
->forest
, p
, (const char *)os3
.data
);
242 p
+= pull_netlogon_string(reply
->domain
, p
, (const char *)os3
.data
);
243 p
+= pull_netlogon_string(reply
->hostname
, p
, (const char *)os3
.data
);
244 p
+= pull_netlogon_string(reply
->netbios_domain
, p
, (const char *)os3
.data
);
245 p
+= pull_netlogon_string(reply
->netbios_hostname
, p
, (const char *)os3
.data
);
246 p
+= pull_netlogon_string(reply
->unk
, p
, (const char *)os3
.data
);
248 if (reply
->type
== SAMLOGON_AD_R
) {
249 p
+= pull_netlogon_string(reply
->user_name
, p
, (const char *)os3
.data
);
251 *reply
->user_name
= 0;
254 p
+= pull_netlogon_string(reply
->site_name
, p
, (const char *)os3
.data
);
255 p
+= pull_netlogon_string(reply
->site_name_2
, p
, (const char *)os3
.data
);
257 reply
->version
= IVAL(p
, 0);
258 reply
->lmnt_token
= SVAL(p
, 4);
259 reply
->lm20_token
= SVAL(p
, 6);
261 data_blob_free(&os1
);
262 data_blob_free(&os2
);
263 data_blob_free(&os3
);
264 data_blob_free(&blob
);
271 /*******************************************************************
272 do a cldap netlogon query. Always 389/udp
273 *******************************************************************/
275 BOOL
ads_cldap_netlogon(const char *server
, const char *realm
, struct cldap_netlogon_reply
*reply
)
280 sock
= open_udp_socket(server
, LDAP_PORT
);
282 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n",
287 ret
= send_cldap_netlogon(sock
, realm
, global_myname(), 6);
291 ret
= recv_cldap_netlogon(sock
, reply
);