s3/libsmb: Fix typo in error message.
[Samba.git] / source / libads / cldap.c
blob11565065af955886f1242d457a424a8e3a084ee8
1 /*
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/>.
22 #include "includes.h"
25 do a cldap netlogon query
27 static int send_cldap_netlogon(int sock, const char *domain,
28 const char *hostname, unsigned ntversion)
30 ASN1_DATA data;
31 char ntver[4];
32 #ifdef CLDAP_USER_QUERY
33 char aac[4];
35 SIVAL(aac, 0, 0x00000180);
36 #endif
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));
52 if (domain) {
53 asn1_push_tag(&data, ASN1_CONTEXT(3));
54 asn1_write_OctetString(&data, "DnsDomain", 9);
55 asn1_write_OctetString(&data, domain, strlen(domain));
56 asn1_pop_tag(&data);
59 asn1_push_tag(&data, ASN1_CONTEXT(3));
60 asn1_write_OctetString(&data, "Host", 4);
61 asn1_write_OctetString(&data, hostname, strlen(hostname));
62 asn1_pop_tag(&data);
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);
68 asn1_pop_tag(&data);
70 asn1_push_tag(&data, ASN1_CONTEXT(3));
71 asn1_write_OctetString(&data, "AAC", 4);
72 asn1_write_OctetString(&data, aac, 4);
73 asn1_pop_tag(&data);
74 #endif
76 asn1_push_tag(&data, ASN1_CONTEXT(3));
77 asn1_write_OctetString(&data, "NtVer", 5);
78 asn1_write_OctetString(&data, ntver, 4);
79 asn1_pop_tag(&data);
81 asn1_pop_tag(&data);
83 asn1_push_tag(&data,ASN1_SEQUENCE(0));
84 asn1_write_OctetString(&data, "NetLogon", 8);
85 asn1_pop_tag(&data);
86 asn1_pop_tag(&data);
87 asn1_pop_tag(&data);
89 if (data.has_error) {
90 DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data.ofs));
91 asn1_free(&data);
92 return -1;
95 if (write(sock, data.data, data.length) != (ssize_t)data.length) {
96 DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno)));
97 asn1_free(&data);
98 return -1;
101 asn1_free(&data);
103 return 0;
106 static SIG_ATOMIC_T gotalarm;
108 /***************************************************************
109 Signal function to tell us we timed out.
110 ****************************************************************/
112 static void gotalarm_sig(void)
114 gotalarm = 1;
118 receive a cldap netlogon reply
120 static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
121 int sock,
122 uint32_t *nt_version,
123 union nbt_cldap_netlogon **reply)
125 int ret;
126 ASN1_DATA data;
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;
131 int i1;
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"));
139 errno = ENOMEM;
140 return -1;
143 /* Setup timeout */
144 gotalarm = 0;
145 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
146 alarm(al_secs);
147 /* End setup timeout. */
149 ret = read(sock, blob.data, blob.length);
151 /* Teardown timeout. */
152 CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
153 alarm(0);
155 if (ret <= 0) {
156 DEBUG(1,("no reply received to cldap netlogon\n"));
157 data_blob_free(&blob);
158 return -1;
160 blob.length = ret;
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);
172 asn1_end_tag(&data);
173 asn1_end_tag(&data);
174 asn1_end_tag(&data);
175 asn1_end_tag(&data);
176 asn1_end_tag(&data);
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);
183 asn1_free(&data);
184 DEBUG(1,("Failed to parse cldap reply\n"));
185 return -1;
188 r = TALLOC_ZERO_P(mem_ctx, union nbt_cldap_netlogon);
189 if (!r) {
190 errno = ENOMEM;
191 data_blob_free(&os1);
192 data_blob_free(&os2);
193 data_blob_free(&os3);
194 data_blob_free(&blob);
195 return -1;
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);
203 TALLOC_FREE(r);
204 return -1;
207 data_blob_free(&os1);
208 data_blob_free(&os2);
209 data_blob_free(&os3);
210 data_blob_free(&blob);
212 asn1_free(&data);
214 if (reply) {
215 *reply = r;
216 } else {
217 TALLOC_FREE(r);
220 return 0;
223 /*******************************************************************
224 do a cldap netlogon query. Always 389/udp
225 *******************************************************************/
227 bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
228 const char *server,
229 const char *realm,
230 uint32_t *nt_version,
231 union nbt_cldap_netlogon **reply)
233 int sock;
234 int ret;
236 sock = open_udp_socket(server, LDAP_PORT );
237 if (sock == -1) {
238 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n",
239 server));
240 return False;
243 ret = send_cldap_netlogon(sock, realm, global_myname(), *nt_version);
244 if (ret != 0) {
245 close(sock);
246 return False;
248 ret = recv_cldap_netlogon(mem_ctx, sock, nt_version, reply);
249 close(sock);
251 if (ret == -1) {
252 return False;
255 return True;
258 /*******************************************************************
259 do a cldap netlogon query. Always 389/udp
260 *******************************************************************/
262 bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
263 const char *server,
264 const char *realm,
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;
269 bool ret;
271 ret = ads_cldap_netlogon(mem_ctx, server, realm, &nt_version, &reply);
272 if (!ret) {
273 return false;
276 if (nt_version != (NETLOGON_VERSION_5 | NETLOGON_VERSION_5EX)) {
277 return false;
280 *reply5 = reply->logon5;
282 return true;
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)) {
300 return false;
303 switch (command) {
304 case 0x13: /* 19 */
305 case 0x15: /* 21 */
306 case 0x17: /* 23 */
307 case 0x19: /* 25 */
308 break;
309 default:
310 DEBUG(1,("got unexpected command: %d (0x%08x)\n",
311 command, command));
312 return false;
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)) {
318 goto done;
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)) {
331 goto done;
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)) {
339 goto done;
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)) {
347 goto done;
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)) {
355 goto done;
358 return false;
360 done:
361 if (DEBUGLEVEL >= 10) {
362 NDR_PRINT_UNION_DEBUG(nbt_cldap_netlogon, nt_version_query, r);
365 *nt_version = nt_version_query;
367 return true;