objectclass -> objectClass
[Samba/gebeck_regimport.git] / source3 / libads / cldap.c
blob39e736f28ae0da954e4f2e8198b13cd0c0af7028
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 3 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, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
24 These seem to be strings as described in RFC1035 4.1.4 and can be:
26 - a sequence of labels ending in a zero octet
27 - a pointer
28 - a sequence of labels ending with a pointer
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.
35 A pointer consists of a 14 bit offset from the beginning of the data.
37 struct ptr {
38 unsigned ident:2; // must be 11
39 unsigned offset:14; // from the beginning of data
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.
46 static unsigned pull_netlogon_string(char *ret, const char *ptr,
47 const char *data)
49 char *pret = ret;
50 int followed_ptr = 0;
51 unsigned ret_len = 0;
53 memset(pret, 0, MAX_DNS_LABEL);
54 do {
55 if ((*ptr & 0xc0) == 0xc0) {
56 uint16 len;
58 if (!followed_ptr) {
59 ret_len += 2;
60 followed_ptr = 1;
62 len = ((ptr[0] & 0x3f) << 8) | ptr[1];
63 ptr = data + len;
64 } else if (*ptr) {
65 uint8 len = (uint8)*(ptr++);
67 if ((pret - ret + len + 1) >= MAX_DNS_LABEL) {
68 DEBUG(1,("DC returning too long DNS name\n"));
69 return 0;
72 if (pret != ret) {
73 *pret = '.';
74 pret++;
76 memcpy(pret, ptr, len);
77 pret += len;
78 ptr += len;
80 if (!followed_ptr) {
81 ret_len += (len + 1);
84 } while (*ptr);
86 return followed_ptr ? ret_len : ret_len + 1;
90 do a cldap netlogon query
92 static int send_cldap_netlogon(int sock, const char *domain,
93 const char *hostname, unsigned ntversion)
95 ASN1_DATA data;
96 char ntver[4];
97 #ifdef CLDAP_USER_QUERY
98 char aac[4];
100 SIVAL(aac, 0, 0x00000180);
101 #endif
102 SIVAL(ntver, 0, ntversion);
104 memset(&data, 0, sizeof(data));
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));
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);
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);
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);
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
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);
146 asn1_pop_tag(&data);
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);
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;
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;
166 asn1_free(&data);
168 return 0;
171 static SIG_ATOMIC_T gotalarm;
173 /***************************************************************
174 Signal function to tell us we timed out.
175 ****************************************************************/
177 static void gotalarm_sig(void)
179 gotalarm = 1;
183 receive a cldap netlogon reply
185 static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
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;
198 blob = data_blob(NULL, 8192);
199 if (blob.data == NULL) {
200 DEBUG(1, ("data_blob failed\n"));
201 errno = ENOMEM;
202 return -1;
205 /* Setup timeout */
206 gotalarm = 0;
207 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
208 alarm(al_secs);
209 /* End setup timeout. */
211 ret = read(sock, blob.data, blob.length);
213 /* Teardown timeout. */
214 CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
215 alarm(0);
217 if (ret <= 0) {
218 DEBUG(1,("no reply received to cldap netlogon\n"));
219 data_blob_free(&blob);
220 return -1;
222 blob.length = ret;
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);
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;
250 p = (char *)os3.data;
252 reply->type = IVAL(p, 0); p += 4;
253 reply->flags = IVAL(p, 0); p += 4;
255 memcpy(&reply->guid.info, p, UUID_FLAT_SIZE);
256 p += UUID_FLAT_SIZE;
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);
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;
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);
274 reply->version = IVAL(p, 0);
275 reply->lmnt_token = SVAL(p, 4);
276 reply->lm20_token = SVAL(p, 6);
278 data_blob_free(&os1);
279 data_blob_free(&os2);
280 data_blob_free(&os3);
281 data_blob_free(&blob);
283 asn1_free(&data);
285 return 0;
288 /*******************************************************************
289 do a cldap netlogon query. Always 389/udp
290 *******************************************************************/
292 bool ads_cldap_netlogon(const char *server, const char *realm, struct cldap_netlogon_reply *reply)
294 int sock;
295 int ret;
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;
304 ret = send_cldap_netlogon(sock, realm, global_myname(), 6);
305 if (ret != 0) {
306 close(sock);
307 return False;
309 ret = recv_cldap_netlogon(sock, reply);
310 close(sock);
312 if (ret == -1) {
313 return False;
316 return True;