s3:torture: support SMB_CONF_PATH envvar in smbtorture
[metze/samba/wip.git] / source3 / libads / cldap.c
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)
7
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.
12
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.
17
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/>.  
20 */
21
22 #include "includes.h"
23
24 /*
25   do a cldap netlogon query
26 */
27 static int send_cldap_netlogon(TALLOC_CTX *mem_ctx, int sock, const char *domain,
28                                const char *hostname, unsigned ntversion)
29 {
30         ASN1_DATA *data;
31         char ntver[4];
32 #ifdef CLDAP_USER_QUERY
33         char aac[4];
34
35         SIVAL(aac, 0, 0x00000180);
36 #endif
37         SIVAL(ntver, 0, ntversion);
38
39         data = asn1_init(mem_ctx);
40         if (data == NULL) {
41                 return -1;
42         }
43
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));
54
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);
60         }
61
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);
66
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);
72
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
78
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);
83
84         asn1_pop_tag(data);
85
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);
91
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;
96         }
97
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;
102         }
103
104         asn1_free(data);
105
106         return 0;
107 }
108
109 /*
110   receive a cldap netlogon reply
111 */
112 static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
113                                int sock,
114                                uint32_t nt_version,
115                                struct netlogon_samlogon_response **reply)
116 {
117         int ret;
118         ASN1_DATA *data;
119         DATA_BLOB blob = data_blob_null;
120         DATA_BLOB os1 = data_blob_null;
121         DATA_BLOB os2 = data_blob_null;
122         DATA_BLOB os3 = data_blob_null;
123         int i1;
124         struct netlogon_samlogon_response *r = NULL;
125         NTSTATUS status;
126
127         fd_set r_fds;
128         struct timeval timeout;
129
130         blob = data_blob(NULL, 8192);
131         if (blob.data == NULL) {
132                 DEBUG(1, ("data_blob failed\n"));
133                 errno = ENOMEM;
134                 return -1;
135         }
136
137         FD_ZERO(&r_fds);
138         FD_SET(sock, &r_fds);
139
140         /*
141          * half the time of a regular ldap timeout, not less than 3 seconds.
142          */
143         timeout.tv_sec = MAX(3,lp_ldap_timeout()/2);
144         timeout.tv_usec = 0;
145
146         ret = sys_select(sock+1, &r_fds, NULL, NULL, &timeout);
147         if (ret == -1) {
148                 DEBUG(10, ("select failed: %s\n", strerror(errno)));
149                 data_blob_free(&blob);
150                 return -1;
151         }
152
153         if (ret == 0) {
154                 DEBUG(1,("no reply received to cldap netlogon\n"));
155                 data_blob_free(&blob);
156                 return -1;
157         }
158
159         ret = read(sock, blob.data, blob.length);
160         if (ret <= 0) {
161                 DEBUG(1,("no reply received to cldap netlogon\n"));
162                 data_blob_free(&blob);
163                 return -1;
164         }
165         blob.length = ret;
166
167         data = asn1_init(mem_ctx);
168         if (data == NULL) {
169                 data_blob_free(&blob);
170                 return -1;
171         }
172
173         asn1_load(data, blob);
174         asn1_start_tag(data, ASN1_SEQUENCE(0));
175         asn1_read_Integer(data, &i1);
176         asn1_start_tag(data, ASN1_APPLICATION(4));
177         asn1_read_OctetString(data, NULL, &os1);
178         asn1_start_tag(data, ASN1_SEQUENCE(0));
179         asn1_start_tag(data, ASN1_SEQUENCE(0));
180         asn1_read_OctetString(data, NULL, &os2);
181         asn1_start_tag(data, ASN1_SET);
182         asn1_read_OctetString(data, NULL, &os3);
183         asn1_end_tag(data);
184         asn1_end_tag(data);
185         asn1_end_tag(data);
186         asn1_end_tag(data);
187         asn1_end_tag(data);
188
189         if (data->has_error) {
190                 data_blob_free(&blob);
191                 data_blob_free(&os1);
192                 data_blob_free(&os2);
193                 data_blob_free(&os3);
194                 asn1_free(data);
195                 DEBUG(1,("Failed to parse cldap reply\n"));
196                 return -1;
197         }
198
199         r = TALLOC_ZERO_P(mem_ctx, struct netlogon_samlogon_response);
200         if (!r) {
201                 errno = ENOMEM;
202                 data_blob_free(&os1);
203                 data_blob_free(&os2);
204                 data_blob_free(&os3);
205                 data_blob_free(&blob);
206                 asn1_free(data);
207                 return -1;
208         }
209
210         status = pull_netlogon_samlogon_response(&os3, mem_ctx, NULL, r);
211         if (!NT_STATUS_IS_OK(status)) {
212                 data_blob_free(&os1);
213                 data_blob_free(&os2);
214                 data_blob_free(&os3);
215                 data_blob_free(&blob);
216                 asn1_free(data);
217                 TALLOC_FREE(r);
218                 return -1;
219         }
220
221         map_netlogon_samlogon_response(r);
222
223         data_blob_free(&os1);
224         data_blob_free(&os2);
225         data_blob_free(&os3);
226         data_blob_free(&blob);
227
228         asn1_free(data);
229
230         if (reply) {
231                 *reply = r;
232         } else {
233                 TALLOC_FREE(r);
234         }
235
236         return 0;
237 }
238
239 /*******************************************************************
240   do a cldap netlogon query.  Always 389/udp
241 *******************************************************************/
242
243 bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
244                         const char *server,
245                         const char *realm,
246                         uint32_t nt_version,
247                         struct netlogon_samlogon_response **reply)
248 {
249         int sock;
250         int ret;
251
252         sock = open_udp_socket(server, LDAP_PORT );
253         if (sock == -1) {
254                 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n", 
255                          server));
256                 return False;
257         }
258
259         ret = send_cldap_netlogon(mem_ctx, sock, realm, global_myname(), nt_version);
260         if (ret != 0) {
261                 close(sock);
262                 return False;
263         }
264         ret = recv_cldap_netlogon(mem_ctx, sock, nt_version, reply);
265         close(sock);
266
267         if (ret == -1) {
268                 return False;
269         }
270
271         return True;
272 }
273
274 /*******************************************************************
275   do a cldap netlogon query.  Always 389/udp
276 *******************************************************************/
277
278 bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
279                           const char *server,
280                           const char *realm,
281                           struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply5)
282 {
283         uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
284         struct netlogon_samlogon_response *reply = NULL;
285         bool ret;
286
287         ret = ads_cldap_netlogon(mem_ctx, server, realm, nt_version, &reply);
288         if (!ret) {
289                 return false;
290         }
291
292         if (reply->ntver != NETLOGON_NT_VERSION_5EX) {
293                 DEBUG(0,("ads_cldap_netlogon_5: nt_version mismatch: 0x%08x\n",
294                         reply->ntver));
295                 return false;
296         }
297
298         *reply5 = reply->data.nt5_ex;
299
300         return true;
301 }