RIP BOOL. Convert BOOL -> bool. I found a few interesting
[bbaumbach/samba-autobuild/.git] / source / 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   These seem to be strings as described in RFC1035 4.1.4 and can be:
25
26    - a sequence of labels ending in a zero octet
27    - a pointer
28    - a sequence of labels ending with a pointer
29
30   A label is a byte where the first two bits must be zero and the remaining
31   bits represent the length of the label followed by the label itself.
32   Therefore, the length of a label is at max 64 bytes.  Under RFC1035, a
33   sequence of labels cannot exceed 255 bytes.
34
35   A pointer consists of a 14 bit offset from the beginning of the data.
36
37   struct ptr {
38     unsigned ident:2; // must be 11
39     unsigned offset:14; // from the beginning of data
40   };
41
42   This is used as a method to compress the packet by eliminated duplicate
43   domain components.  Since a UDP packet should probably be < 512 bytes and a
44   DNS name can be up to 255 bytes, this actually makes a lot of sense.
45 */
46 static unsigned pull_netlogon_string(char *ret, const char *ptr,
47                                      const char *data)
48 {
49         char *pret = ret;
50         int followed_ptr = 0;
51         unsigned ret_len = 0;
52
53         memset(pret, 0, MAX_DNS_LABEL);
54         do {
55                 if ((*ptr & 0xc0) == 0xc0) {
56                         uint16 len;
57
58                         if (!followed_ptr) {
59                                 ret_len += 2;
60                                 followed_ptr = 1;
61                         }
62                         len = ((ptr[0] & 0x3f) << 8) | ptr[1];
63                         ptr = data + len;
64                 } else if (*ptr) {
65                         uint8 len = (uint8)*(ptr++);
66
67                         if ((pret - ret + len + 1) >= MAX_DNS_LABEL) {
68                                 DEBUG(1,("DC returning too long DNS name\n"));
69                                 return 0;
70                         }
71
72                         if (pret != ret) {
73                                 *pret = '.';
74                                 pret++;
75                         }
76                         memcpy(pret, ptr, len);
77                         pret += len;
78                         ptr += len;
79
80                         if (!followed_ptr) {
81                                 ret_len += (len + 1);
82                         }
83                 }
84         } while (*ptr);
85
86         return followed_ptr ? ret_len : ret_len + 1;
87 }
88
89 /*
90   do a cldap netlogon query
91 */
92 static int send_cldap_netlogon(int sock, const char *domain, 
93                                const char *hostname, unsigned ntversion)
94 {
95         ASN1_DATA data;
96         char ntver[4];
97 #ifdef CLDAP_USER_QUERY
98         char aac[4];
99
100         SIVAL(aac, 0, 0x00000180);
101 #endif
102         SIVAL(ntver, 0, ntversion);
103
104         memset(&data, 0, sizeof(data));
105
106         asn1_push_tag(&data,ASN1_SEQUENCE(0));
107         asn1_write_Integer(&data, 4);
108         asn1_push_tag(&data, ASN1_APPLICATION(3));
109         asn1_write_OctetString(&data, NULL, 0);
110         asn1_write_enumerated(&data, 0);
111         asn1_write_enumerated(&data, 0);
112         asn1_write_Integer(&data, 0);
113         asn1_write_Integer(&data, 0);
114         asn1_write_BOOLEAN2(&data, False);
115         asn1_push_tag(&data, ASN1_CONTEXT(0));
116
117         if (domain) {
118                 asn1_push_tag(&data, ASN1_CONTEXT(3));
119                 asn1_write_OctetString(&data, "DnsDomain", 9);
120                 asn1_write_OctetString(&data, domain, strlen(domain));
121                 asn1_pop_tag(&data);
122         }
123
124         asn1_push_tag(&data, ASN1_CONTEXT(3));
125         asn1_write_OctetString(&data, "Host", 4);
126         asn1_write_OctetString(&data, hostname, strlen(hostname));
127         asn1_pop_tag(&data);
128
129 #ifdef CLDAP_USER_QUERY
130         asn1_push_tag(&data, ASN1_CONTEXT(3));
131         asn1_write_OctetString(&data, "User", 4);
132         asn1_write_OctetString(&data, "SAMBA$", 6);
133         asn1_pop_tag(&data);
134
135         asn1_push_tag(&data, ASN1_CONTEXT(3));
136         asn1_write_OctetString(&data, "AAC", 4);
137         asn1_write_OctetString(&data, aac, 4);
138         asn1_pop_tag(&data);
139 #endif
140
141         asn1_push_tag(&data, ASN1_CONTEXT(3));
142         asn1_write_OctetString(&data, "NtVer", 5);
143         asn1_write_OctetString(&data, ntver, 4);
144         asn1_pop_tag(&data);
145
146         asn1_pop_tag(&data);
147
148         asn1_push_tag(&data,ASN1_SEQUENCE(0));
149         asn1_write_OctetString(&data, "NetLogon", 8);
150         asn1_pop_tag(&data);
151         asn1_pop_tag(&data);
152         asn1_pop_tag(&data);
153
154         if (data.has_error) {
155                 DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data.ofs));
156                 asn1_free(&data);
157                 return -1;
158         }
159
160         if (write(sock, data.data, data.length) != (ssize_t)data.length) {
161                 DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno)));
162                 asn1_free(&data);
163                 return -1;
164         }
165
166         asn1_free(&data);
167
168         return 0;
169 }
170
171 static SIG_ATOMIC_T gotalarm;
172                                                                                                                    
173 /***************************************************************
174  Signal function to tell us we timed out.
175 ****************************************************************/
176                                                                                                                    
177 static void gotalarm_sig(void)
178 {
179         gotalarm = 1;
180 }
181                                                                                                                    
182 /*
183   receive a cldap netlogon reply
184 */
185 static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
186 {
187         int ret;
188         ASN1_DATA data;
189         DATA_BLOB blob = data_blob_null;
190         DATA_BLOB os1 = data_blob_null;
191         DATA_BLOB os2 = data_blob_null;
192         DATA_BLOB os3 = data_blob_null;
193         int i1;
194         /* half the time of a regular ldap timeout, not less than 3 seconds. */
195         unsigned int al_secs = MAX(3,lp_ldap_timeout()/2);
196         char *p;
197
198         blob = data_blob(NULL, 8192);
199         if (blob.data == NULL) {
200                 DEBUG(1, ("data_blob failed\n"));
201                 errno = ENOMEM;
202                 return -1;
203         }
204
205         /* Setup timeout */
206         gotalarm = 0;
207         CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
208         alarm(al_secs);
209         /* End setup timeout. */
210  
211         ret = read(sock, blob.data, blob.length);
212
213         /* Teardown timeout. */
214         CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
215         alarm(0);
216
217         if (ret <= 0) {
218                 DEBUG(1,("no reply received to cldap netlogon\n"));
219                 data_blob_free(&blob);
220                 return -1;
221         }
222         blob.length = ret;
223
224         asn1_load(&data, blob);
225         asn1_start_tag(&data, ASN1_SEQUENCE(0));
226         asn1_read_Integer(&data, &i1);
227         asn1_start_tag(&data, ASN1_APPLICATION(4));
228         asn1_read_OctetString(&data, &os1);
229         asn1_start_tag(&data, ASN1_SEQUENCE(0));
230         asn1_start_tag(&data, ASN1_SEQUENCE(0));
231         asn1_read_OctetString(&data, &os2);
232         asn1_start_tag(&data, ASN1_SET);
233         asn1_read_OctetString(&data, &os3);
234         asn1_end_tag(&data);
235         asn1_end_tag(&data);
236         asn1_end_tag(&data);
237         asn1_end_tag(&data);
238         asn1_end_tag(&data);
239
240         if (data.has_error) {
241                 data_blob_free(&blob);
242                 data_blob_free(&os1);
243                 data_blob_free(&os2);
244                 data_blob_free(&os3);
245                 asn1_free(&data);
246                 DEBUG(1,("Failed to parse cldap reply\n"));
247                 return -1;
248         }
249
250         p = (char *)os3.data;
251
252         reply->type = IVAL(p, 0); p += 4;
253         reply->flags = IVAL(p, 0); p += 4;
254
255         memcpy(&reply->guid.info, p, UUID_FLAT_SIZE);
256         p += UUID_FLAT_SIZE;
257
258         p += pull_netlogon_string(reply->forest, p, (const char *)os3.data);
259         p += pull_netlogon_string(reply->domain, p, (const char *)os3.data);
260         p += pull_netlogon_string(reply->hostname, p, (const char *)os3.data);
261         p += pull_netlogon_string(reply->netbios_domain, p, (const char *)os3.data);
262         p += pull_netlogon_string(reply->netbios_hostname, p, (const char *)os3.data);
263         p += pull_netlogon_string(reply->unk, p, (const char *)os3.data);
264
265         if (reply->type == SAMLOGON_AD_R) {
266                 p += pull_netlogon_string(reply->user_name, p, (const char *)os3.data);
267         } else {
268                 *reply->user_name = 0;
269         }
270
271         p += pull_netlogon_string(reply->server_site_name, p, (const char *)os3.data);
272         p += pull_netlogon_string(reply->client_site_name, p, (const char *)os3.data);
273
274         reply->version = IVAL(p, 0);
275         reply->lmnt_token = SVAL(p, 4);
276         reply->lm20_token = SVAL(p, 6);
277
278         data_blob_free(&os1);
279         data_blob_free(&os2);
280         data_blob_free(&os3);
281         data_blob_free(&blob);
282         
283         asn1_free(&data);
284
285         return 0;
286 }
287
288 /*******************************************************************
289   do a cldap netlogon query.  Always 389/udp
290 *******************************************************************/
291
292 bool ads_cldap_netlogon(const char *server, const char *realm,  struct cldap_netlogon_reply *reply)
293 {
294         int sock;
295         int ret;
296
297         sock = open_udp_socket(server, LDAP_PORT );
298         if (sock == -1) {
299                 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n", 
300                          server));
301                 return False;
302         }
303
304         ret = send_cldap_netlogon(sock, realm, global_myname(), 6);
305         if (ret != 0) {
306                 close(sock);
307                 return False;
308         }
309         ret = recv_cldap_netlogon(sock, reply);
310         close(sock);
311
312         if (ret == -1) {
313                 return False;
314         }
315
316         return True;
317 }