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)
6 Copyright (C) 2008 Guenther Deschner (gd@samba.org)
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 3 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, see <http://www.gnu.org/licenses/>.
25 do a cldap netlogon query
27 static int send_cldap_netlogon(int sock
, const char *domain
,
28 const char *hostname
, unsigned ntversion
)
32 #ifdef CLDAP_USER_QUERY
35 SIVAL(aac
, 0, 0x00000180);
37 SIVAL(ntver
, 0, ntversion
);
39 memset(&data
, 0, sizeof(data
));
41 asn1_push_tag(&data
,ASN1_SEQUENCE(0));
42 asn1_write_Integer(&data
, 4);
43 asn1_push_tag(&data
, ASN1_APPLICATION(3));
44 asn1_write_OctetString(&data
, NULL
, 0);
45 asn1_write_enumerated(&data
, 0);
46 asn1_write_enumerated(&data
, 0);
47 asn1_write_Integer(&data
, 0);
48 asn1_write_Integer(&data
, 0);
49 asn1_write_BOOLEAN2(&data
, False
);
50 asn1_push_tag(&data
, ASN1_CONTEXT(0));
53 asn1_push_tag(&data
, ASN1_CONTEXT(3));
54 asn1_write_OctetString(&data
, "DnsDomain", 9);
55 asn1_write_OctetString(&data
, domain
, strlen(domain
));
59 asn1_push_tag(&data
, ASN1_CONTEXT(3));
60 asn1_write_OctetString(&data
, "Host", 4);
61 asn1_write_OctetString(&data
, hostname
, strlen(hostname
));
64 #ifdef CLDAP_USER_QUERY
65 asn1_push_tag(&data
, ASN1_CONTEXT(3));
66 asn1_write_OctetString(&data
, "User", 4);
67 asn1_write_OctetString(&data
, "SAMBA$", 6);
70 asn1_push_tag(&data
, ASN1_CONTEXT(3));
71 asn1_write_OctetString(&data
, "AAC", 4);
72 asn1_write_OctetString(&data
, aac
, 4);
76 asn1_push_tag(&data
, ASN1_CONTEXT(3));
77 asn1_write_OctetString(&data
, "NtVer", 5);
78 asn1_write_OctetString(&data
, ntver
, 4);
83 asn1_push_tag(&data
,ASN1_SEQUENCE(0));
84 asn1_write_OctetString(&data
, "NetLogon", 8);
90 DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data
.ofs
));
95 if (write(sock
, data
.data
, data
.length
) != (ssize_t
)data
.length
) {
96 DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno
)));
106 static SIG_ATOMIC_T gotalarm
;
108 /***************************************************************
109 Signal function to tell us we timed out.
110 ****************************************************************/
112 static void gotalarm_sig(void)
118 receive a cldap netlogon reply
120 static int recv_cldap_netlogon(TALLOC_CTX
*mem_ctx
,
122 uint32_t *nt_version
,
123 union nbt_cldap_netlogon
**reply
)
127 DATA_BLOB blob
= data_blob_null
;
128 DATA_BLOB os1
= data_blob_null
;
129 DATA_BLOB os2
= data_blob_null
;
130 DATA_BLOB os3
= data_blob_null
;
132 /* half the time of a regular ldap timeout, not less than 3 seconds. */
133 unsigned int al_secs
= MAX(3,lp_ldap_timeout()/2);
134 union nbt_cldap_netlogon
*r
= NULL
;
136 blob
= data_blob(NULL
, 8192);
137 if (blob
.data
== NULL
) {
138 DEBUG(1, ("data_blob failed\n"));
145 CatchSignal(SIGALRM
, SIGNAL_CAST gotalarm_sig
);
147 /* End setup timeout. */
149 ret
= read(sock
, blob
.data
, blob
.length
);
151 /* Teardown timeout. */
152 CatchSignal(SIGALRM
, SIGNAL_CAST SIG_IGN
);
156 DEBUG(1,("no reply received to cldap netlogon\n"));
157 data_blob_free(&blob
);
162 asn1_load(&data
, blob
);
163 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
164 asn1_read_Integer(&data
, &i1
);
165 asn1_start_tag(&data
, ASN1_APPLICATION(4));
166 asn1_read_OctetString(&data
, &os1
);
167 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
168 asn1_start_tag(&data
, ASN1_SEQUENCE(0));
169 asn1_read_OctetString(&data
, &os2
);
170 asn1_start_tag(&data
, ASN1_SET
);
171 asn1_read_OctetString(&data
, &os3
);
178 if (data
.has_error
) {
179 data_blob_free(&blob
);
180 data_blob_free(&os1
);
181 data_blob_free(&os2
);
182 data_blob_free(&os3
);
184 DEBUG(1,("Failed to parse cldap reply\n"));
188 r
= TALLOC_ZERO_P(mem_ctx
, union nbt_cldap_netlogon
);
191 data_blob_free(&os1
);
192 data_blob_free(&os2
);
193 data_blob_free(&os3
);
194 data_blob_free(&blob
);
198 if (!pull_mailslot_cldap_reply(mem_ctx
, &os3
, r
, nt_version
)) {
199 data_blob_free(&os1
);
200 data_blob_free(&os2
);
201 data_blob_free(&os3
);
202 data_blob_free(&blob
);
207 data_blob_free(&os1
);
208 data_blob_free(&os2
);
209 data_blob_free(&os3
);
210 data_blob_free(&blob
);
223 /*******************************************************************
224 do a cldap netlogon query. Always 389/udp
225 *******************************************************************/
227 bool ads_cldap_netlogon(TALLOC_CTX
*mem_ctx
,
230 uint32_t *nt_version
,
231 union nbt_cldap_netlogon
**reply
)
236 sock
= open_udp_socket(server
, LDAP_PORT
);
238 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n",
243 ret
= send_cldap_netlogon(sock
, realm
, global_myname(), *nt_version
);
248 ret
= recv_cldap_netlogon(mem_ctx
, sock
, nt_version
, reply
);
258 /*******************************************************************
259 do a cldap netlogon query. Always 389/udp
260 *******************************************************************/
262 bool ads_cldap_netlogon_5(TALLOC_CTX
*mem_ctx
,
265 struct nbt_cldap_netlogon_5
*reply5
)
267 uint32_t nt_version
= NETLOGON_VERSION_5
| NETLOGON_VERSION_5EX
;
268 union nbt_cldap_netlogon
*reply
= NULL
;
271 ret
= ads_cldap_netlogon(mem_ctx
, server
, realm
, &nt_version
, &reply
);
276 if (nt_version
!= (NETLOGON_VERSION_5
| NETLOGON_VERSION_5EX
)) {
280 *reply5
= reply
->logon5
;
285 /****************************************************************
286 ****************************************************************/
288 bool pull_mailslot_cldap_reply(TALLOC_CTX
*mem_ctx
,
289 const DATA_BLOB
*blob
,
290 union nbt_cldap_netlogon
*r
,
291 uint32_t *nt_version
)
293 enum ndr_err_code ndr_err
;
294 uint32_t nt_version_query
= ((*nt_version
) & 0x0000001f);
295 uint16_t command
= 0;
297 ndr_err
= ndr_pull_struct_blob(blob
, mem_ctx
, &command
,
298 (ndr_pull_flags_fn_t
)ndr_pull_uint16
);
299 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
310 DEBUG(1,("got unexpected command: %d (0x%08x)\n",
315 ndr_err
= ndr_pull_union_blob_all(blob
, mem_ctx
, r
, nt_version_query
,
316 (ndr_pull_flags_fn_t
)ndr_pull_nbt_cldap_netlogon
);
317 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
321 /* when the caller requested just those nt_version bits that the server
322 * was able to reply to, we are fine and all done. otherwise we need to
323 * assume downgraded replies which are painfully parsed here - gd */
325 if (nt_version_query
& NETLOGON_VERSION_WITH_CLOSEST_SITE
) {
326 nt_version_query
&= ~NETLOGON_VERSION_WITH_CLOSEST_SITE
;
328 ndr_err
= ndr_pull_union_blob_all(blob
, mem_ctx
, r
, nt_version_query
,
329 (ndr_pull_flags_fn_t
)ndr_pull_nbt_cldap_netlogon
);
330 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
333 if (nt_version_query
& NETLOGON_VERSION_5EX_WITH_IP
) {
334 nt_version_query
&= ~NETLOGON_VERSION_5EX_WITH_IP
;
336 ndr_err
= ndr_pull_union_blob_all(blob
, mem_ctx
, r
, nt_version_query
,
337 (ndr_pull_flags_fn_t
)ndr_pull_nbt_cldap_netlogon
);
338 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
341 if (nt_version_query
& NETLOGON_VERSION_5EX
) {
342 nt_version_query
&= ~NETLOGON_VERSION_5EX
;
344 ndr_err
= ndr_pull_union_blob_all(blob
, mem_ctx
, r
, nt_version_query
,
345 (ndr_pull_flags_fn_t
)ndr_pull_nbt_cldap_netlogon
);
346 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
349 if (nt_version_query
& NETLOGON_VERSION_5
) {
350 nt_version_query
&= ~NETLOGON_VERSION_5
;
352 ndr_err
= ndr_pull_union_blob_all(blob
, mem_ctx
, r
, nt_version_query
,
353 (ndr_pull_flags_fn_t
)ndr_pull_nbt_cldap_netlogon
);
354 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
361 if (DEBUGLEVEL
>= 10) {
362 NDR_PRINT_UNION_DEBUG(nbt_cldap_netlogon
, nt_version_query
, r
);
365 *nt_version
= nt_version_query
;