Samba3 smbd now passes test BATCH23 (with the fix for bug #5979), only BATCH22 left...
[Samba.git] / source3 / libads / cldap.c
blob8f9a8ff2137fd62ce74161a9ee389cfb2620428e
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(TALLOC_CTX *mem_ctx, 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 data = asn1_init(mem_ctx);
40 if (data == NULL) {
41 return -1;
44 asn1_push_tag(data,ASN1_SEQUENCE(0));
45 asn1_write_Integer(data, 4);
46 asn1_push_tag(data, ASN1_APPLICATION(3));
47 asn1_write_OctetString(data, NULL, 0);
48 asn1_write_enumerated(data, 0);
49 asn1_write_enumerated(data, 0);
50 asn1_write_Integer(data, 0);
51 asn1_write_Integer(data, 0);
52 asn1_write_BOOLEAN(data, False);
53 asn1_push_tag(data, ASN1_CONTEXT(0));
55 if (domain) {
56 asn1_push_tag(data, ASN1_CONTEXT(3));
57 asn1_write_OctetString(data, "DnsDomain", 9);
58 asn1_write_OctetString(data, domain, strlen(domain));
59 asn1_pop_tag(data);
62 asn1_push_tag(data, ASN1_CONTEXT(3));
63 asn1_write_OctetString(data, "Host", 4);
64 asn1_write_OctetString(data, hostname, strlen(hostname));
65 asn1_pop_tag(data);
67 #ifdef CLDAP_USER_QUERY
68 asn1_push_tag(data, ASN1_CONTEXT(3));
69 asn1_write_OctetString(data, "User", 4);
70 asn1_write_OctetString(data, "SAMBA$", 6);
71 asn1_pop_tag(data);
73 asn1_push_tag(data, ASN1_CONTEXT(3));
74 asn1_write_OctetString(data, "AAC", 4);
75 asn1_write_OctetString(data, aac, 4);
76 asn1_pop_tag(data);
77 #endif
79 asn1_push_tag(data, ASN1_CONTEXT(3));
80 asn1_write_OctetString(data, "NtVer", 5);
81 asn1_write_OctetString(data, ntver, 4);
82 asn1_pop_tag(data);
84 asn1_pop_tag(data);
86 asn1_push_tag(data,ASN1_SEQUENCE(0));
87 asn1_write_OctetString(data, "NetLogon", 8);
88 asn1_pop_tag(data);
89 asn1_pop_tag(data);
90 asn1_pop_tag(data);
92 if (data->has_error) {
93 DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data->ofs));
94 asn1_free(data);
95 return -1;
98 if (write(sock, data->data, data->length) != (ssize_t)data->length) {
99 DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno)));
100 asn1_free(data);
101 return -1;
104 asn1_free(data);
106 return 0;
109 static SIG_ATOMIC_T gotalarm;
111 /***************************************************************
112 Signal function to tell us we timed out.
113 ****************************************************************/
115 static void gotalarm_sig(void)
117 gotalarm = 1;
121 receive a cldap netlogon reply
123 static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
124 int sock,
125 uint32_t nt_version,
126 struct netlogon_samlogon_response **reply)
128 int ret;
129 ASN1_DATA *data;
130 DATA_BLOB blob = data_blob_null;
131 DATA_BLOB os1 = data_blob_null;
132 DATA_BLOB os2 = data_blob_null;
133 DATA_BLOB os3 = data_blob_null;
134 int i1;
135 /* half the time of a regular ldap timeout, not less than 3 seconds. */
136 unsigned int al_secs = MAX(3,lp_ldap_timeout()/2);
137 struct netlogon_samlogon_response *r = NULL;
138 NTSTATUS status;
140 blob = data_blob(NULL, 8192);
141 if (blob.data == NULL) {
142 DEBUG(1, ("data_blob failed\n"));
143 errno = ENOMEM;
144 return -1;
147 /* Setup timeout */
148 gotalarm = 0;
149 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
150 alarm(al_secs);
151 /* End setup timeout. */
153 ret = read(sock, blob.data, blob.length);
155 /* Teardown timeout. */
156 CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
157 alarm(0);
159 if (ret <= 0) {
160 DEBUG(1,("no reply received to cldap netlogon\n"));
161 data_blob_free(&blob);
162 return -1;
164 blob.length = ret;
166 data = asn1_init(mem_ctx);
167 if (data == NULL) {
168 data_blob_free(&blob);
169 return -1;
172 asn1_load(data, blob);
173 asn1_start_tag(data, ASN1_SEQUENCE(0));
174 asn1_read_Integer(data, &i1);
175 asn1_start_tag(data, ASN1_APPLICATION(4));
176 asn1_read_OctetString(data, NULL, &os1);
177 asn1_start_tag(data, ASN1_SEQUENCE(0));
178 asn1_start_tag(data, ASN1_SEQUENCE(0));
179 asn1_read_OctetString(data, NULL, &os2);
180 asn1_start_tag(data, ASN1_SET);
181 asn1_read_OctetString(data, NULL, &os3);
182 asn1_end_tag(data);
183 asn1_end_tag(data);
184 asn1_end_tag(data);
185 asn1_end_tag(data);
186 asn1_end_tag(data);
188 if (data->has_error) {
189 data_blob_free(&blob);
190 data_blob_free(&os1);
191 data_blob_free(&os2);
192 data_blob_free(&os3);
193 asn1_free(data);
194 DEBUG(1,("Failed to parse cldap reply\n"));
195 return -1;
198 r = TALLOC_ZERO_P(mem_ctx, struct netlogon_samlogon_response);
199 if (!r) {
200 errno = ENOMEM;
201 data_blob_free(&os1);
202 data_blob_free(&os2);
203 data_blob_free(&os3);
204 data_blob_free(&blob);
205 asn1_free(data);
206 return -1;
209 status = pull_netlogon_samlogon_response(&os3, mem_ctx, NULL, r);
210 if (!NT_STATUS_IS_OK(status)) {
211 data_blob_free(&os1);
212 data_blob_free(&os2);
213 data_blob_free(&os3);
214 data_blob_free(&blob);
215 asn1_free(data);
216 TALLOC_FREE(r);
217 return -1;
220 map_netlogon_samlogon_response(r);
222 data_blob_free(&os1);
223 data_blob_free(&os2);
224 data_blob_free(&os3);
225 data_blob_free(&blob);
227 asn1_free(data);
229 if (reply) {
230 *reply = r;
231 } else {
232 TALLOC_FREE(r);
235 return 0;
238 /*******************************************************************
239 do a cldap netlogon query. Always 389/udp
240 *******************************************************************/
242 bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
243 const char *server,
244 const char *realm,
245 uint32_t nt_version,
246 struct netlogon_samlogon_response **reply)
248 int sock;
249 int ret;
251 sock = open_udp_socket(server, LDAP_PORT );
252 if (sock == -1) {
253 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n",
254 server));
255 return False;
258 ret = send_cldap_netlogon(mem_ctx, sock, realm, global_myname(), nt_version);
259 if (ret != 0) {
260 close(sock);
261 return False;
263 ret = recv_cldap_netlogon(mem_ctx, sock, nt_version, reply);
264 close(sock);
266 if (ret == -1) {
267 return False;
270 return True;
273 /*******************************************************************
274 do a cldap netlogon query. Always 389/udp
275 *******************************************************************/
277 bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
278 const char *server,
279 const char *realm,
280 struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply5)
282 uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
283 struct netlogon_samlogon_response *reply = NULL;
284 bool ret;
286 ret = ads_cldap_netlogon(mem_ctx, server, realm, nt_version, &reply);
287 if (!ret) {
288 return false;
291 if (reply->ntver != NETLOGON_NT_VERSION_5EX) {
292 DEBUG(0,("ads_cldap_netlogon_5: nt_version mismatch: 0x%08x\n",
293 reply->ntver));
294 return false;
297 *reply5 = reply->data.nt5_ex;
299 return true;