Merge commit 'master/master'
[samba.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(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         memset(&data, 0, sizeof(data));
40
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));
51
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);
57         }
58
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);
63
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);
69
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
75
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);
80
81         asn1_pop_tag(&data);
82
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);
88
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;
93         }
94
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;
99         }
100
101         asn1_free(&data);
102
103         return 0;
104 }
105
106 static SIG_ATOMIC_T gotalarm;
107                                                                                                                    
108 /***************************************************************
109  Signal function to tell us we timed out.
110 ****************************************************************/
111                                                                                                                    
112 static void gotalarm_sig(void)
113 {
114         gotalarm = 1;
115 }
116                                                                                                                    
117 /*
118   receive a cldap netlogon reply
119 */
120 static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
121                                int sock,
122                                uint32_t nt_version,
123                                struct netlogon_samlogon_response **reply)
124 {
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         struct netlogon_samlogon_response *r = NULL;
135         NTSTATUS status;
136
137         blob = data_blob(NULL, 8192);
138         if (blob.data == NULL) {
139                 DEBUG(1, ("data_blob failed\n"));
140                 errno = ENOMEM;
141                 return -1;
142         }
143
144         /* Setup timeout */
145         gotalarm = 0;
146         CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
147         alarm(al_secs);
148         /* End setup timeout. */
149  
150         ret = read(sock, blob.data, blob.length);
151
152         /* Teardown timeout. */
153         CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
154         alarm(0);
155
156         if (ret <= 0) {
157                 DEBUG(1,("no reply received to cldap netlogon\n"));
158                 data_blob_free(&blob);
159                 return -1;
160         }
161         blob.length = ret;
162
163         asn1_load(&data, blob);
164         asn1_start_tag(&data, ASN1_SEQUENCE(0));
165         asn1_read_Integer(&data, &i1);
166         asn1_start_tag(&data, ASN1_APPLICATION(4));
167         asn1_read_OctetString(&data, &os1);
168         asn1_start_tag(&data, ASN1_SEQUENCE(0));
169         asn1_start_tag(&data, ASN1_SEQUENCE(0));
170         asn1_read_OctetString(&data, &os2);
171         asn1_start_tag(&data, ASN1_SET);
172         asn1_read_OctetString(&data, &os3);
173         asn1_end_tag(&data);
174         asn1_end_tag(&data);
175         asn1_end_tag(&data);
176         asn1_end_tag(&data);
177         asn1_end_tag(&data);
178
179         if (data.has_error) {
180                 data_blob_free(&blob);
181                 data_blob_free(&os1);
182                 data_blob_free(&os2);
183                 data_blob_free(&os3);
184                 asn1_free(&data);
185                 DEBUG(1,("Failed to parse cldap reply\n"));
186                 return -1;
187         }
188
189         r = TALLOC_ZERO_P(mem_ctx, struct netlogon_samlogon_response);
190         if (!r) {
191                 errno = ENOMEM;
192                 data_blob_free(&os1);
193                 data_blob_free(&os2);
194                 data_blob_free(&os3);
195                 data_blob_free(&blob);
196                 return -1;
197         }
198
199         status = pull_netlogon_samlogon_response(&os3, mem_ctx, NULL, r);
200         if (!NT_STATUS_IS_OK(status)) {
201                 data_blob_free(&os1);
202                 data_blob_free(&os2);
203                 data_blob_free(&os3);
204                 data_blob_free(&blob);
205                 TALLOC_FREE(r);
206                 return -1;
207         }
208
209         map_netlogon_samlogon_response(r);
210
211         data_blob_free(&os1);
212         data_blob_free(&os2);
213         data_blob_free(&os3);
214         data_blob_free(&blob);
215         
216         asn1_free(&data);
217
218         if (reply) {
219                 *reply = r;
220         } else {
221                 TALLOC_FREE(r);
222         }
223
224         return 0;
225 }
226
227 /*******************************************************************
228   do a cldap netlogon query.  Always 389/udp
229 *******************************************************************/
230
231 bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
232                         const char *server,
233                         const char *realm,
234                         uint32_t nt_version,
235                         struct netlogon_samlogon_response **reply)
236 {
237         int sock;
238         int ret;
239
240         sock = open_udp_socket(server, LDAP_PORT );
241         if (sock == -1) {
242                 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n", 
243                          server));
244                 return False;
245         }
246
247         ret = send_cldap_netlogon(sock, realm, global_myname(), nt_version);
248         if (ret != 0) {
249                 close(sock);
250                 return False;
251         }
252         ret = recv_cldap_netlogon(mem_ctx, sock, nt_version, reply);
253         close(sock);
254
255         if (ret == -1) {
256                 return False;
257         }
258
259         return True;
260 }
261
262 /*******************************************************************
263   do a cldap netlogon query.  Always 389/udp
264 *******************************************************************/
265
266 bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
267                           const char *server,
268                           const char *realm,
269                           struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply5)
270 {
271         uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
272         struct netlogon_samlogon_response *reply = NULL;
273         bool ret;
274
275         ret = ads_cldap_netlogon(mem_ctx, server, realm, nt_version, &reply);
276         if (!ret) {
277                 return false;
278         }
279
280         if (reply->ntver != NETLOGON_NT_VERSION_5EX) {
281                 DEBUG(0,("ads_cldap_netlogon_5: nt_version mismatch: 0x%08x\n",
282                         reply->ntver));
283                 return false;
284         }
285
286         *reply5 = reply->data.nt5_ex;
287
288         return true;
289 }