r16465: merge a few miniro SAMBA_3_0 fixes
[Samba.git] / source / libads / cldap.c
blob11c083a56a7e012d81848a94e3810a059191afa0
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)
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 2 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
25 These seem to be strings as described in RFC1035 4.1.4 and can be:
27 - a sequence of labels ending in a zero octet
28 - a pointer
29 - a sequence of labels ending with a pointer
31 A label is a byte where the first two bits must be zero and the remaining
32 bits represent the length of the label followed by the label itself.
33 Therefore, the length of a label is at max 64 bytes. Under RFC1035, a
34 sequence of labels cannot exceed 255 bytes.
36 A pointer consists of a 14 bit offset from the beginning of the data.
38 struct ptr {
39 unsigned ident:2; // must be 11
40 unsigned offset:14; // from the beginning of data
43 This is used as a method to compress the packet by eliminated duplicate
44 domain components. Since a UDP packet should probably be < 512 bytes and a
45 DNS name can be up to 255 bytes, this actually makes a lot of sense.
47 static unsigned pull_netlogon_string(char *ret, const char *ptr,
48 const char *data)
50 char *pret = ret;
51 int followed_ptr = 0;
52 unsigned ret_len = 0;
54 memset(pret, 0, MAX_DNS_LABEL);
55 do {
56 if ((*ptr & 0xc0) == 0xc0) {
57 uint16 len;
59 if (!followed_ptr) {
60 ret_len += 2;
61 followed_ptr = 1;
63 len = ((ptr[0] & 0x3f) << 8) | ptr[1];
64 ptr = data + len;
65 } else if (*ptr) {
66 uint8 len = (uint8)*(ptr++);
68 if ((pret - ret + len + 1) >= MAX_DNS_LABEL) {
69 DEBUG(1,("DC returning too long DNS name\n"));
70 return 0;
73 if (pret != ret) {
74 *pret = '.';
75 pret++;
77 memcpy(pret, ptr, len);
78 pret += len;
79 ptr += len;
81 if (!followed_ptr) {
82 ret_len += (len + 1);
85 } while (*ptr);
87 return followed_ptr ? ret_len : ret_len + 1;
91 do a cldap netlogon query
93 static int send_cldap_netlogon(int sock, const char *domain,
94 const char *hostname, unsigned ntversion)
96 ASN1_DATA data;
97 char ntver[4];
98 #ifdef CLDAP_USER_QUERY
99 char aac[4];
101 SIVAL(aac, 0, 0x00000180);
102 #endif
103 SIVAL(ntver, 0, ntversion);
105 memset(&data, 0, sizeof(data));
107 asn1_push_tag(&data,ASN1_SEQUENCE(0));
108 asn1_write_Integer(&data, 4);
109 asn1_push_tag(&data, ASN1_APPLICATION(3));
110 asn1_write_OctetString(&data, NULL, 0);
111 asn1_write_enumerated(&data, 0);
112 asn1_write_enumerated(&data, 0);
113 asn1_write_Integer(&data, 0);
114 asn1_write_Integer(&data, 0);
115 asn1_write_BOOLEAN2(&data, False);
116 asn1_push_tag(&data, ASN1_CONTEXT(0));
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);
123 asn1_push_tag(&data, ASN1_CONTEXT(3));
124 asn1_write_OctetString(&data, "Host", 4);
125 asn1_write_OctetString(&data, hostname, strlen(hostname));
126 asn1_pop_tag(&data);
128 #ifdef CLDAP_USER_QUERY
129 asn1_push_tag(&data, ASN1_CONTEXT(3));
130 asn1_write_OctetString(&data, "User", 4);
131 asn1_write_OctetString(&data, "SAMBA$", 6);
132 asn1_pop_tag(&data);
134 asn1_push_tag(&data, ASN1_CONTEXT(3));
135 asn1_write_OctetString(&data, "AAC", 4);
136 asn1_write_OctetString(&data, aac, 4);
137 asn1_pop_tag(&data);
138 #endif
140 asn1_push_tag(&data, ASN1_CONTEXT(3));
141 asn1_write_OctetString(&data, "NtVer", 5);
142 asn1_write_OctetString(&data, ntver, 4);
143 asn1_pop_tag(&data);
145 asn1_pop_tag(&data);
147 asn1_push_tag(&data,ASN1_SEQUENCE(0));
148 asn1_write_OctetString(&data, "NetLogon", 8);
149 asn1_pop_tag(&data);
150 asn1_pop_tag(&data);
151 asn1_pop_tag(&data);
153 if (data.has_error) {
154 DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data.ofs));
155 asn1_free(&data);
156 return -1;
159 if (write(sock, data.data, data.length) != (ssize_t)data.length) {
160 DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno)));
163 asn1_free(&data);
165 return 0;
168 static SIG_ATOMIC_T gotalarm;
170 /***************************************************************
171 Signal function to tell us we timed out.
172 ****************************************************************/
174 static void gotalarm_sig(void)
176 gotalarm = 1;
180 receive a cldap netlogon reply
182 static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
184 int ret;
185 ASN1_DATA data;
186 DATA_BLOB blob;
187 DATA_BLOB os1, os2, os3;
188 int i1;
189 char *p;
191 blob = data_blob(NULL, 8192);
193 /* Setup timeout */
194 gotalarm = 0;
195 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
196 alarm(lp_ldap_timeout());
197 /* End setup timeout. */
199 ret = read(sock, blob.data, blob.length);
201 /* Teardown timeout. */
202 CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
203 alarm(0);
205 if (ret <= 0) {
206 DEBUG(1,("no reply received to cldap netlogon\n"));
207 return -1;
209 blob.length = ret;
211 asn1_load(&data, blob);
212 asn1_start_tag(&data, ASN1_SEQUENCE(0));
213 asn1_read_Integer(&data, &i1);
214 asn1_start_tag(&data, ASN1_APPLICATION(4));
215 asn1_read_OctetString(&data, &os1);
216 asn1_start_tag(&data, ASN1_SEQUENCE(0));
217 asn1_start_tag(&data, ASN1_SEQUENCE(0));
218 asn1_read_OctetString(&data, &os2);
219 asn1_start_tag(&data, ASN1_SET);
220 asn1_read_OctetString(&data, &os3);
221 asn1_end_tag(&data);
222 asn1_end_tag(&data);
223 asn1_end_tag(&data);
224 asn1_end_tag(&data);
225 asn1_end_tag(&data);
227 if (data.has_error) {
228 asn1_free(&data);
229 DEBUG(1,("Failed to parse cldap reply\n"));
230 return -1;
233 p = (char *)os3.data;
235 reply->type = IVAL(p, 0); p += 4;
236 reply->flags = IVAL(p, 0); p += 4;
238 memcpy(&reply->guid.info, p, UUID_FLAT_SIZE);
239 p += UUID_FLAT_SIZE;
241 p += pull_netlogon_string(reply->forest, p, (const char *)os3.data);
242 p += pull_netlogon_string(reply->domain, p, (const char *)os3.data);
243 p += pull_netlogon_string(reply->hostname, p, (const char *)os3.data);
244 p += pull_netlogon_string(reply->netbios_domain, p, (const char *)os3.data);
245 p += pull_netlogon_string(reply->netbios_hostname, p, (const char *)os3.data);
246 p += pull_netlogon_string(reply->unk, p, (const char *)os3.data);
248 if (reply->type == SAMLOGON_AD_R) {
249 p += pull_netlogon_string(reply->user_name, p, (const char *)os3.data);
250 } else {
251 *reply->user_name = 0;
254 p += pull_netlogon_string(reply->site_name, p, (const char *)os3.data);
255 p += pull_netlogon_string(reply->site_name_2, p, (const char *)os3.data);
257 reply->version = IVAL(p, 0);
258 reply->lmnt_token = SVAL(p, 4);
259 reply->lm20_token = SVAL(p, 6);
261 data_blob_free(&os1);
262 data_blob_free(&os2);
263 data_blob_free(&os3);
264 data_blob_free(&blob);
266 asn1_free(&data);
268 return 0;
271 /*******************************************************************
272 do a cldap netlogon query. Always 389/udp
273 *******************************************************************/
275 BOOL ads_cldap_netlogon(const char *server, const char *realm, struct cldap_netlogon_reply *reply)
277 int sock;
278 int ret;
280 sock = open_udp_socket(server, LDAP_PORT );
281 if (sock == -1) {
282 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s\n",
283 server));
284 return False;
287 ret = send_cldap_netlogon(sock, realm, global_myname(), 6);
288 if (ret != 0) {
289 return False;
291 ret = recv_cldap_netlogon(sock, reply);
292 close(sock);
294 if (ret == -1) {
295 return False;
298 return True;