cldap: add talloc context to ads_cldap_netlogon().
[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
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  
19 */
20
21 #include "includes.h"
22
23 /*
24   do a cldap netlogon query
25 */
26 static int send_cldap_netlogon(int sock, const char *domain, 
27                                const char *hostname, unsigned ntversion)
28 {
29         ASN1_DATA data;
30         char ntver[4];
31 #ifdef CLDAP_USER_QUERY
32         char aac[4];
33
34         SIVAL(aac, 0, 0x00000180);
35 #endif
36         SIVAL(ntver, 0, ntversion);
37
38         memset(&data, 0, sizeof(data));
39
40         asn1_push_tag(&data,ASN1_SEQUENCE(0));
41         asn1_write_Integer(&data, 4);
42         asn1_push_tag(&data, ASN1_APPLICATION(3));
43         asn1_write_OctetString(&data, NULL, 0);
44         asn1_write_enumerated(&data, 0);
45         asn1_write_enumerated(&data, 0);
46         asn1_write_Integer(&data, 0);
47         asn1_write_Integer(&data, 0);
48         asn1_write_BOOLEAN2(&data, False);
49         asn1_push_tag(&data, ASN1_CONTEXT(0));
50
51         if (domain) {
52                 asn1_push_tag(&data, ASN1_CONTEXT(3));
53                 asn1_write_OctetString(&data, "DnsDomain", 9);
54                 asn1_write_OctetString(&data, domain, strlen(domain));
55                 asn1_pop_tag(&data);
56         }
57
58         asn1_push_tag(&data, ASN1_CONTEXT(3));
59         asn1_write_OctetString(&data, "Host", 4);
60         asn1_write_OctetString(&data, hostname, strlen(hostname));
61         asn1_pop_tag(&data);
62
63 #ifdef CLDAP_USER_QUERY
64         asn1_push_tag(&data, ASN1_CONTEXT(3));
65         asn1_write_OctetString(&data, "User", 4);
66         asn1_write_OctetString(&data, "SAMBA$", 6);
67         asn1_pop_tag(&data);
68
69         asn1_push_tag(&data, ASN1_CONTEXT(3));
70         asn1_write_OctetString(&data, "AAC", 4);
71         asn1_write_OctetString(&data, aac, 4);
72         asn1_pop_tag(&data);
73 #endif
74
75         asn1_push_tag(&data, ASN1_CONTEXT(3));
76         asn1_write_OctetString(&data, "NtVer", 5);
77         asn1_write_OctetString(&data, ntver, 4);
78         asn1_pop_tag(&data);
79
80         asn1_pop_tag(&data);
81
82         asn1_push_tag(&data,ASN1_SEQUENCE(0));
83         asn1_write_OctetString(&data, "NetLogon", 8);
84         asn1_pop_tag(&data);
85         asn1_pop_tag(&data);
86         asn1_pop_tag(&data);
87
88         if (data.has_error) {
89                 DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data.ofs));
90                 asn1_free(&data);
91                 return -1;
92         }
93
94         if (write(sock, data.data, data.length) != (ssize_t)data.length) {
95                 DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno)));
96                 asn1_free(&data);
97                 return -1;
98         }
99
100         asn1_free(&data);
101
102         return 0;
103 }
104
105 static SIG_ATOMIC_T gotalarm;
106                                                                                                                    
107 /***************************************************************
108  Signal function to tell us we timed out.
109 ****************************************************************/
110                                                                                                                    
111 static void gotalarm_sig(void)
112 {
113         gotalarm = 1;
114 }
115                                                                                                                    
116 /*
117   receive a cldap netlogon reply
118 */
119 static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
120                                int sock,
121                                struct nbt_cldap_netlogon_5 *reply)
122 {
123         int ret;
124         ASN1_DATA data;
125         DATA_BLOB blob = data_blob_null;
126         DATA_BLOB os1 = data_blob_null;
127         DATA_BLOB os2 = data_blob_null;
128         DATA_BLOB os3 = data_blob_null;
129         int i1;
130         /* half the time of a regular ldap timeout, not less than 3 seconds. */
131         unsigned int al_secs = MAX(3,lp_ldap_timeout()/2);
132         union nbt_cldap_netlogon p;
133         enum ndr_err_code ndr_err;
134
135         blob = data_blob(NULL, 8192);
136         if (blob.data == NULL) {
137                 DEBUG(1, ("data_blob failed\n"));
138                 errno = ENOMEM;
139                 return -1;
140         }
141
142         /* Setup timeout */
143         gotalarm = 0;
144         CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
145         alarm(al_secs);
146         /* End setup timeout. */
147  
148         ret = read(sock, blob.data, blob.length);
149
150         /* Teardown timeout. */
151         CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
152         alarm(0);
153
154         if (ret <= 0) {
155                 DEBUG(1,("no reply received to cldap netlogon\n"));
156                 data_blob_free(&blob);
157                 return -1;
158         }
159         blob.length = ret;
160
161         asn1_load(&data, blob);
162         asn1_start_tag(&data, ASN1_SEQUENCE(0));
163         asn1_read_Integer(&data, &i1);
164         asn1_start_tag(&data, ASN1_APPLICATION(4));
165         asn1_read_OctetString(&data, &os1);
166         asn1_start_tag(&data, ASN1_SEQUENCE(0));
167         asn1_start_tag(&data, ASN1_SEQUENCE(0));
168         asn1_read_OctetString(&data, &os2);
169         asn1_start_tag(&data, ASN1_SET);
170         asn1_read_OctetString(&data, &os3);
171         asn1_end_tag(&data);
172         asn1_end_tag(&data);
173         asn1_end_tag(&data);
174         asn1_end_tag(&data);
175         asn1_end_tag(&data);
176
177         if (data.has_error) {
178                 data_blob_free(&blob);
179                 data_blob_free(&os1);
180                 data_blob_free(&os2);
181                 data_blob_free(&os3);
182                 asn1_free(&data);
183                 DEBUG(1,("Failed to parse cldap reply\n"));
184                 return -1;
185         }
186
187         ndr_err = ndr_pull_union_blob_all(&os3, mem_ctx, &p, 5,
188                        (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
189         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
190                 return -1;
191         }
192
193         *reply = p.logon5;
194
195         if (DEBUGLEVEL >= 10) {
196                 NDR_PRINT_UNION_DEBUG(nbt_cldap_netlogon, 5, &p);
197         }
198
199         data_blob_free(&os1);
200         data_blob_free(&os2);
201         data_blob_free(&os3);
202         data_blob_free(&blob);
203         
204         asn1_free(&data);
205
206         return 0;
207 }
208
209 /*******************************************************************
210   do a cldap netlogon query.  Always 389/udp
211 *******************************************************************/
212
213 bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
214                         const char *server,
215                         const char *realm,
216                         struct nbt_cldap_netlogon_5 *reply)
217 {
218         int sock;
219         int ret;
220
221         sock = open_udp_socket(server, LDAP_PORT );
222         if (sock == -1) {
223                 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n", 
224                          server));
225                 return False;
226         }
227
228         ret = send_cldap_netlogon(sock, realm, global_myname(), 6);
229         if (ret != 0) {
230                 close(sock);
231                 return False;
232         }
233         ret = recv_cldap_netlogon(mem_ctx, sock, reply);
234         close(sock);
235
236         if (ret == -1) {
237                 return False;
238         }
239
240         return True;
241 }