Move 'weird' character set into new 'developer' module
[sfrench/samba-autobuild/.git] / source3 / utils / net_ads_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
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
19 */
20
21 #include "includes.h"
22 #include "../utils/net.h"
23
24 #ifdef HAVE_ADS
25
26 struct cldap_netlogon_reply {
27         uint32 version;
28         uint32 flags;
29         GUID guid;
30         char *domain;
31         char *server_name;
32         char *domain_flatname;
33         char *server_flatname;
34         char *dns_name;
35         uint32 unknown2[2];
36 };
37
38
39 /*
40   pull a length prefixed string from a packet
41   return number of bytes consumed
42 */
43 static unsigned pull_len_string(char **ret, const char *p)
44 {
45         unsigned len = *p;
46         (*ret) = NULL;
47         if (len == 0) return 1;
48         (*ret) = smb_xstrndup(p+1, len);
49         return len+1;
50 }
51
52 /*
53   pull a dotted string from a packet
54   return number of bytes consumed
55 */
56 static unsigned pull_dotted_string(char **ret, const char *p)
57 {
58         char *s;
59         unsigned len, total_len=0;
60
61         (*ret) = NULL;
62
63         while ((len = pull_len_string(&s, p)) > 1) {
64                 if (total_len) {
65                         char *s2;
66                         asprintf(&s2, "%s.%s", *ret, s);
67                         SAFE_FREE(*ret);
68                         (*ret) = s2;
69                 } else {
70                         (*ret) = s;
71                 }
72                 total_len += len;
73                 p += len;
74         }
75
76         return total_len + 1;
77 }
78
79
80 /*
81   do a cldap netlogon query
82 */
83 static int send_cldap_netlogon(int sock, const char *domain, 
84                                const char *hostname, unsigned ntversion)
85 {
86         ASN1_DATA data;
87         char ntver[4];
88
89         SIVAL(ntver, 0, ntversion);
90
91         memset(&data, 0, sizeof(data));
92
93         asn1_push_tag(&data,ASN1_SEQUENCE(0));
94         asn1_write_Integer(&data, 4);
95         asn1_push_tag(&data, ASN1_APPLICATION(3));
96         asn1_write_OctetString(&data, NULL, 0);
97         asn1_write_enumerated(&data, 0);
98         asn1_write_enumerated(&data, 0);
99         asn1_write_Integer(&data, 0);
100         asn1_write_Integer(&data, 0);
101         asn1_write_BOOLEAN2(&data, False);
102         asn1_push_tag(&data, ASN1_CONTEXT(0));
103
104         asn1_push_tag(&data, ASN1_CONTEXT(3));
105         asn1_write_OctetString(&data, "DnsDomain", 9);
106         asn1_write_OctetString(&data, domain, strlen(domain));
107         asn1_pop_tag(&data);
108
109         asn1_push_tag(&data, ASN1_CONTEXT(3));
110         asn1_write_OctetString(&data, "Host", 4);
111         asn1_write_OctetString(&data, hostname, strlen(hostname));
112         asn1_pop_tag(&data);
113
114         asn1_push_tag(&data, ASN1_CONTEXT(3));
115         asn1_write_OctetString(&data, "NtVer", 5);
116         asn1_write_OctetString(&data, ntver, 4);
117         asn1_pop_tag(&data);
118
119         asn1_pop_tag(&data);
120
121         asn1_push_tag(&data,ASN1_SEQUENCE(0));
122         asn1_write_OctetString(&data, "NetLogon", 8);
123         asn1_pop_tag(&data);
124         asn1_pop_tag(&data);
125         asn1_pop_tag(&data);
126
127         if (data.has_error) {
128                 d_printf("Failed to build cldap netlogon at offset %d\n", (int)data.ofs);
129                 asn1_free(&data);
130                 return -1;
131         }
132
133         if (write(sock, data.data, data.length) != data.length) {
134                 d_printf("failed to send cldap query (%s)\n", strerror(errno));
135         }
136
137         file_save("cldap_query.dat", data.data, data.length);
138         asn1_free(&data);
139
140         return 0;
141 }
142
143
144 /*
145   receive a cldap netlogon reply
146 */
147 static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
148 {
149         int ret;
150         ASN1_DATA data;
151         DATA_BLOB blob;
152         DATA_BLOB os1, os2, os3;
153         uint32 i1;
154         char *p;
155
156         blob = data_blob(NULL, 8192);
157
158         ret = read(sock, blob.data, blob.length);
159
160         if (ret <= 0) {
161                 d_printf("no reply received to cldap netlogon\n");
162                 return -1;
163         }
164         blob.length = ret;
165
166         file_save("cldap_reply.dat", blob.data, blob.length);
167
168         asn1_load(&data, blob);
169         asn1_start_tag(&data, ASN1_SEQUENCE(0));
170         asn1_read_Integer(&data, &i1);
171         asn1_start_tag(&data, ASN1_APPLICATION(4));
172         asn1_read_OctetString(&data, &os1);
173         asn1_start_tag(&data, ASN1_SEQUENCE(0));
174         asn1_start_tag(&data, ASN1_SEQUENCE(0));
175         asn1_read_OctetString(&data, &os2);
176         asn1_start_tag(&data, ASN1_SET);
177         asn1_read_OctetString(&data, &os3);
178         asn1_end_tag(&data);
179         asn1_end_tag(&data);
180         asn1_end_tag(&data);
181         asn1_end_tag(&data);
182         asn1_end_tag(&data);
183
184         if (data.has_error) {
185                 d_printf("Failed to parse cldap reply\n");
186                 return -1;
187         }
188
189         file_save("cldap_reply_core.dat", os3.data, os3.length);
190
191         p = os3.data;
192
193         reply->version = IVAL(p, 0); p += 4;
194         reply->flags = IVAL(p, 0); p += 4;
195         memcpy(&reply->guid.info, p, GUID_SIZE);
196         p += GUID_SIZE;
197         p += pull_dotted_string(&reply->domain, p);
198         p += 2; /* 0xc018 - whats this? */
199         p += pull_len_string(&reply->server_name, p);
200         p += 2; /* 0xc018 - whats this? */
201         p += pull_len_string(&reply->domain_flatname, p);
202         p += 1;
203         p += pull_len_string(&reply->server_flatname, p);
204         p += 2;
205         p += pull_len_string(&reply->dns_name, p);
206
207         data_blob_free(&os1);
208         data_blob_free(&os2);
209         data_blob_free(&os3);
210         data_blob_free(&blob);
211         
212         return 0;
213 }
214
215
216 /*
217   free a cldap reply packet
218 */
219 static void cldap_reply_free(struct cldap_netlogon_reply *reply)
220 {
221         SAFE_FREE(reply->domain);
222         SAFE_FREE(reply->server_name);
223         SAFE_FREE(reply->domain_flatname);
224         SAFE_FREE(reply->server_flatname);
225         SAFE_FREE(reply->dns_name);
226 }
227
228 /*
229   do a cldap netlogon query
230 */
231 int ads_cldap_netlogon(ADS_STRUCT *ads)
232 {
233         int sock;
234         int ret;
235         struct cldap_netlogon_reply reply;
236
237         sock = open_udp_socket(inet_ntoa(ads->ldap_ip), ads->ldap_port);
238         if (sock == -1) {
239                 d_printf("Failed to open udp socket to %s:%u\n", 
240                          inet_ntoa(ads->ldap_ip), 
241                          ads->ldap_port);
242                 return -1;
243         }
244
245         ret = send_cldap_netlogon(sock, ads->config.realm, global_myname(), 6);
246         if (ret != 0) {
247                 return ret;
248         }
249
250         ret = recv_cldap_netlogon(sock, &reply);
251         close(sock);
252
253         if (ret == -1) {
254                 return -1;
255         }
256
257         d_printf("Version: 0x%x\n", reply.version);
258         d_printf("GUID: "); 
259         print_guid(&reply.guid);
260         d_printf("Flags:   0x%x\n", reply.flags);
261         d_printf("Domain: %s\n", reply.domain);
262         d_printf("Server Name: %s\n", reply.server_name);
263         d_printf("Flatname: %s\n", reply.domain_flatname);
264         d_printf("Server Name2: %s\n", reply.server_flatname);
265         d_printf("DNS Name: %s\n", reply.dns_name);
266
267         cldap_reply_free(&reply);
268         
269         return ret;
270 }
271
272
273 #endif