/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- send_cldap_netlogon
- recv_cldap_netlogon
- ads_cldap_netlogon
- ads_cldap_netlogon_5
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 Copyright (C) 2008 Guenther Deschner (gd@samba.org)
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23
24 /*
25 do a cldap netlogon query
26 */
27 static int send_cldap_netlogon(TALLOC_CTX *mem_ctx, int sock, const char *domain,
/* [<][>][^][v][top][bottom][index][help] */
28 const char *hostname, unsigned ntversion)
29 {
30 ASN1_DATA *data;
31 char ntver[4];
32 #ifdef CLDAP_USER_QUERY
33 char aac[4];
34
35 SIVAL(aac, 0, 0x00000180);
36 #endif
37 SIVAL(ntver, 0, ntversion);
38
39 data = asn1_init(mem_ctx);
40 if (data == NULL) {
41 return -1;
42 }
43
44 asn1_push_tag(data,ASN1_SEQUENCE(0));
45 asn1_write_Integer(data, 4);
46 asn1_push_tag(data, ASN1_APPLICATION(3));
47 asn1_write_OctetString(data, NULL, 0);
48 asn1_write_enumerated(data, 0);
49 asn1_write_enumerated(data, 0);
50 asn1_write_Integer(data, 0);
51 asn1_write_Integer(data, 0);
52 asn1_write_BOOLEAN(data, False);
53 asn1_push_tag(data, ASN1_CONTEXT(0));
54
55 if (domain) {
56 asn1_push_tag(data, ASN1_CONTEXT(3));
57 asn1_write_OctetString(data, "DnsDomain", 9);
58 asn1_write_OctetString(data, domain, strlen(domain));
59 asn1_pop_tag(data);
60 }
61
62 asn1_push_tag(data, ASN1_CONTEXT(3));
63 asn1_write_OctetString(data, "Host", 4);
64 asn1_write_OctetString(data, hostname, strlen(hostname));
65 asn1_pop_tag(data);
66
67 #ifdef CLDAP_USER_QUERY
68 asn1_push_tag(data, ASN1_CONTEXT(3));
69 asn1_write_OctetString(data, "User", 4);
70 asn1_write_OctetString(data, "SAMBA$", 6);
71 asn1_pop_tag(data);
72
73 asn1_push_tag(data, ASN1_CONTEXT(3));
74 asn1_write_OctetString(data, "AAC", 4);
75 asn1_write_OctetString(data, aac, 4);
76 asn1_pop_tag(data);
77 #endif
78
79 asn1_push_tag(data, ASN1_CONTEXT(3));
80 asn1_write_OctetString(data, "NtVer", 5);
81 asn1_write_OctetString(data, ntver, 4);
82 asn1_pop_tag(data);
83
84 asn1_pop_tag(data);
85
86 asn1_push_tag(data,ASN1_SEQUENCE(0));
87 asn1_write_OctetString(data, "NetLogon", 8);
88 asn1_pop_tag(data);
89 asn1_pop_tag(data);
90 asn1_pop_tag(data);
91
92 if (data->has_error) {
93 DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data->ofs));
94 asn1_free(data);
95 return -1;
96 }
97
98 if (write(sock, data->data, data->length) != (ssize_t)data->length) {
99 DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno)));
100 asn1_free(data);
101 return -1;
102 }
103
104 asn1_free(data);
105
106 return 0;
107 }
108
109 /*
110 receive a cldap netlogon reply
111 */
112 static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
113 int sock,
114 uint32_t nt_version,
115 struct netlogon_samlogon_response **reply)
116 {
117 int ret;
118 ASN1_DATA *data;
119 DATA_BLOB blob = data_blob_null;
120 DATA_BLOB os1 = data_blob_null;
121 DATA_BLOB os2 = data_blob_null;
122 DATA_BLOB os3 = data_blob_null;
123 int i1;
124 struct netlogon_samlogon_response *r = NULL;
125 NTSTATUS status;
126
127 fd_set r_fds;
128 struct timeval timeout;
129
130 blob = data_blob(NULL, 8192);
131 if (blob.data == NULL) {
132 DEBUG(1, ("data_blob failed\n"));
133 errno = ENOMEM;
134 return -1;
135 }
136
137 FD_ZERO(&r_fds);
138 FD_SET(sock, &r_fds);
139
140 /*
141 * half the time of a regular ldap timeout, not less than 3 seconds.
142 */
143 timeout.tv_sec = MAX(3,lp_ldap_timeout()/2);
144 timeout.tv_usec = 0;
145
146 ret = sys_select(sock+1, &r_fds, NULL, NULL, &timeout);
147 if (ret == -1) {
148 DEBUG(10, ("select failed: %s\n", strerror(errno)));
149 data_blob_free(&blob);
150 return -1;
151 }
152
153 if (ret == 0) {
154 DEBUG(1,("no reply received to cldap netlogon "
155 "(select timeout %u sec)\n",
156 (unsigned int)timeout.tv_sec));
157 data_blob_free(&blob);
158 return -1;
159 }
160
161 ret = read(sock, blob.data, blob.length);
162 if (ret <= 0) {
163 DEBUG(1,("no reply received to cldap netlogon "
164 "(ret = %d: Error = %s)\n",
165 ret,
166 ret == -1 ? strerror(errno) : "" ));
167 data_blob_free(&blob);
168 return -1;
169 }
170 blob.length = ret;
171
172 data = asn1_init(mem_ctx);
173 if (data == NULL) {
174 data_blob_free(&blob);
175 return -1;
176 }
177
178 asn1_load(data, blob);
179 asn1_start_tag(data, ASN1_SEQUENCE(0));
180 asn1_read_Integer(data, &i1);
181 asn1_start_tag(data, ASN1_APPLICATION(4));
182 asn1_read_OctetString(data, NULL, &os1);
183 asn1_start_tag(data, ASN1_SEQUENCE(0));
184 asn1_start_tag(data, ASN1_SEQUENCE(0));
185 asn1_read_OctetString(data, NULL, &os2);
186 asn1_start_tag(data, ASN1_SET);
187 asn1_read_OctetString(data, NULL, &os3);
188 asn1_end_tag(data);
189 asn1_end_tag(data);
190 asn1_end_tag(data);
191 asn1_end_tag(data);
192 asn1_end_tag(data);
193
194 if (data->has_error) {
195 data_blob_free(&blob);
196 data_blob_free(&os1);
197 data_blob_free(&os2);
198 data_blob_free(&os3);
199 asn1_free(data);
200 DEBUG(1,("Failed to parse cldap reply\n"));
201 return -1;
202 }
203
204 r = TALLOC_ZERO_P(mem_ctx, struct netlogon_samlogon_response);
205 if (!r) {
206 errno = ENOMEM;
207 data_blob_free(&os1);
208 data_blob_free(&os2);
209 data_blob_free(&os3);
210 data_blob_free(&blob);
211 asn1_free(data);
212 return -1;
213 }
214
215 status = pull_netlogon_samlogon_response(&os3, mem_ctx, NULL, r);
216 if (!NT_STATUS_IS_OK(status)) {
217 data_blob_free(&os1);
218 data_blob_free(&os2);
219 data_blob_free(&os3);
220 data_blob_free(&blob);
221 asn1_free(data);
222 TALLOC_FREE(r);
223 return -1;
224 }
225
226 map_netlogon_samlogon_response(r);
227
228 data_blob_free(&os1);
229 data_blob_free(&os2);
230 data_blob_free(&os3);
231 data_blob_free(&blob);
232
233 asn1_free(data);
234
235 if (reply) {
236 *reply = r;
237 } else {
238 TALLOC_FREE(r);
239 }
240
241 return 0;
242 }
243
244 /*******************************************************************
245 do a cldap netlogon query. Always 389/udp
246 *******************************************************************/
247
248 bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
249 const char *server,
250 const char *realm,
251 uint32_t nt_version,
252 struct netlogon_samlogon_response **reply)
253 {
254 int sock;
255 int ret;
256
257 sock = open_udp_socket(server, LDAP_PORT );
258 if (sock == -1) {
259 DEBUG(2,("ads_cldap_netlogon: Failed to open udp socket to %s. "
260 "Error %s\n",
261 server,
262 strerror(errno) ));
263 return False;
264 }
265
266 ret = send_cldap_netlogon(mem_ctx, sock, realm, global_myname(), nt_version);
267 if (ret != 0) {
268 close(sock);
269 return False;
270 }
271 ret = recv_cldap_netlogon(mem_ctx, sock, nt_version, reply);
272 close(sock);
273
274 if (ret == -1) {
275 return False;
276 }
277
278 return True;
279 }
280
281 /*******************************************************************
282 do a cldap netlogon query. Always 389/udp
283 *******************************************************************/
284
285 bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
/* [<][>][^][v][top][bottom][index][help] */
286 const char *server,
287 const char *realm,
288 struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply5)
289 {
290 uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
291 struct netlogon_samlogon_response *reply = NULL;
292 bool ret;
293
294 ret = ads_cldap_netlogon(mem_ctx, server, realm, nt_version, &reply);
295 if (!ret) {
296 return false;
297 }
298
299 if (reply->ntver != NETLOGON_NT_VERSION_5EX) {
300 DEBUG(0,("ads_cldap_netlogon_5: nt_version mismatch: 0x%08x\n",
301 reply->ntver));
302 return false;
303 }
304
305 *reply5 = reply->data.nt5_ex;
306
307 return true;
308 }