Add context for libcli_resolve.
[samba-svnmirror.git] / source / torture / nbt / dgram.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NBT dgram testing
5
6    Copyright (C) Andrew Tridgell 2005
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 #include "libcli/dgram/libdgram.h"
24 #include "librpc/gen_ndr/samr.h"
25 #include "librpc/gen_ndr/ndr_nbt.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
27 #include "lib/socket/socket.h"
28 #include "lib/events/events.h"
29 #include "torture/rpc/rpc.h"
30 #include "libcli/resolve/resolve.h"
31 #include "system/network.h"
32 #include "lib/socket/netif.h"
33 #include "param/param.h"
34
35 #define TEST_NAME "TORTURE_TEST"
36
37 /*
38   reply handler for netlogon request
39 */
40 static void netlogon_handler(struct dgram_mailslot_handler *dgmslot, 
41                              struct nbt_dgram_packet *packet, 
42                              struct socket_address *src)
43 {
44         NTSTATUS status;
45         struct nbt_netlogon_packet netlogon;
46         int *replies = (int *)dgmslot->private;
47
48         printf("netlogon reply from %s:%d\n", src->addr, src->port);
49
50         status = dgram_mailslot_netlogon_parse(dgmslot, dgmslot, packet, &netlogon);
51         if (!NT_STATUS_IS_OK(status)) {
52                 printf("Failed to parse netlogon packet from %s:%d\n",
53                        src->addr, src->port);
54                 return;
55         }
56
57         NDR_PRINT_DEBUG(nbt_netlogon_packet, &netlogon);
58
59         (*replies)++;
60 }
61
62
63 /* test UDP/138 netlogon requests */
64 static bool nbt_test_netlogon(struct torture_context *tctx)
65 {
66         struct dgram_mailslot_handler *dgmslot;
67         struct nbt_dgram_socket *dgmsock = nbt_dgram_socket_init(tctx, NULL);
68         struct socket_address *dest;
69         const char *myaddress;
70         struct nbt_netlogon_packet logon;
71         struct nbt_name myname;
72         NTSTATUS status;
73         struct timeval tv = timeval_current();
74         int replies = 0;
75
76         struct socket_address *socket_address;
77
78         const char *address;
79         struct nbt_name name;
80         
81         name.name = lp_workgroup(tctx->lp_ctx);
82         name.type = NBT_NAME_LOGON;
83         name.scope = NULL;
84
85         /* do an initial name resolution to find its IP */
86         torture_assert_ntstatus_ok(tctx, 
87                                    resolve_name(lp_resolve_context(tctx->lp_ctx), &name, tctx, &address, event_context_find(tctx)),
88                                    talloc_asprintf(tctx, "Failed to resolve %s", name.name));
89
90         myaddress = talloc_strdup(dgmsock, iface_best_ip(tctx->lp_ctx, address));
91
92
93         socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
94                                                      myaddress, lp_dgram_port(tctx->lp_ctx));
95         torture_assert(tctx, socket_address != NULL, "Error getting address");
96
97         /* try receiving replies on port 138 first, which will only
98            work if we are root and smbd/nmbd are not running - fall
99            back to listening on any port, which means replies from
100            some windows versions won't be seen */
101         status = socket_listen(dgmsock->sock, socket_address, 0, 0);
102         if (!NT_STATUS_IS_OK(status)) {
103                 talloc_free(socket_address);
104                 socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
105                                                              myaddress, 0);
106                 torture_assert(tctx, socket_address != NULL, "Error getting address");
107
108                 socket_listen(dgmsock->sock, socket_address, 0, 0);
109         }
110
111         /* setup a temporary mailslot listener for replies */
112         dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
113                                       netlogon_handler, &replies);
114
115         ZERO_STRUCT(logon);
116         logon.command = NETLOGON_QUERY_FOR_PDC;
117         logon.req.pdc.computer_name = TEST_NAME;
118         logon.req.pdc.mailslot_name = dgmslot->mailslot_name;
119         logon.req.pdc.unicode_name  = TEST_NAME;
120         logon.req.pdc.nt_version    = 1;
121         logon.req.pdc.lmnt_token    = 0xFFFF;
122         logon.req.pdc.lm20_token    = 0xFFFF;
123
124         make_nbt_name_client(&myname, TEST_NAME);
125
126         dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name, 
127                                            address, lp_dgram_port(tctx->lp_ctx));
128         torture_assert(tctx, dest != NULL, "Error getting address");
129
130         status = dgram_mailslot_netlogon_send(dgmsock, &name, dest,
131                                               &myname, &logon);
132         torture_assert_ntstatus_ok(tctx, status, "Failed to send netlogon request");
133
134         while (timeval_elapsed(&tv) < 5 && replies == 0) {
135                 event_loop_once(dgmsock->event_ctx);
136         }
137
138         return true;
139 }
140
141
142 /* test UDP/138 netlogon requests */
143 static bool nbt_test_netlogon2(struct torture_context *tctx)
144 {
145         struct dgram_mailslot_handler *dgmslot;
146         struct nbt_dgram_socket *dgmsock = nbt_dgram_socket_init(tctx, NULL);
147         struct socket_address *dest;
148         const char *myaddress;
149         struct nbt_netlogon_packet logon;
150         struct nbt_name myname;
151         NTSTATUS status;
152         struct timeval tv = timeval_current();
153         int replies = 0;
154
155         struct socket_address *socket_address;
156
157         const char *address;
158         struct nbt_name name;
159         
160         name.name = lp_workgroup(tctx->lp_ctx);
161         name.type = NBT_NAME_LOGON;
162         name.scope = NULL;
163
164         /* do an initial name resolution to find its IP */
165         torture_assert_ntstatus_ok(tctx, 
166                                    resolve_name(lp_resolve_context(tctx->lp_ctx), &name, tctx, &address, event_context_find(tctx)),
167                                    talloc_asprintf(tctx, "Failed to resolve %s", name.name));
168
169         myaddress = talloc_strdup(dgmsock, iface_best_ip(tctx->lp_ctx, address));
170
171         socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
172                                                      myaddress, lp_dgram_port(tctx->lp_ctx));
173         torture_assert(tctx, socket_address != NULL, "Error getting address");
174
175         /* try receiving replies on port 138 first, which will only
176            work if we are root and smbd/nmbd are not running - fall
177            back to listening on any port, which means replies from
178            some windows versions won't be seen */
179         status = socket_listen(dgmsock->sock, socket_address, 0, 0);
180         if (!NT_STATUS_IS_OK(status)) {
181                 talloc_free(socket_address);
182                 socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
183                                                              myaddress, 0);
184                 torture_assert(tctx, socket_address != NULL, "Error getting address");
185
186                 socket_listen(dgmsock->sock, socket_address, 0, 0);
187         }
188
189         /* setup a temporary mailslot listener for replies */
190         dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
191                                       netlogon_handler, &replies);
192         
193
194         ZERO_STRUCT(logon);
195         logon.command = NETLOGON_QUERY_FOR_PDC2;
196         logon.req.pdc2.request_count = 0;
197         logon.req.pdc2.computer_name = TEST_NAME;
198         logon.req.pdc2.user_name     = "";
199         logon.req.pdc2.mailslot_name = dgmslot->mailslot_name;
200         logon.req.pdc2.nt_version    = 11;
201         logon.req.pdc2.lmnt_token    = 0xFFFF;
202         logon.req.pdc2.lm20_token    = 0xFFFF;
203
204         make_nbt_name_client(&myname, TEST_NAME);
205
206         dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name, 
207                                            address, lp_dgram_port(tctx->lp_ctx));
208
209         torture_assert(tctx, dest != NULL, "Error getting address");
210         status = dgram_mailslot_netlogon_send(dgmsock, &name, dest,
211                                               &myname, &logon);
212         torture_assert_ntstatus_ok(tctx, status, "Failed to send netlogon request");
213
214         while (timeval_elapsed(&tv) < 5 && replies == 0) {
215                 event_loop_once(dgmsock->event_ctx);
216         }
217
218         return true;
219 }
220
221
222 /*
223   reply handler for ntlogon request
224 */
225 static void ntlogon_handler(struct dgram_mailslot_handler *dgmslot, 
226                              struct nbt_dgram_packet *packet, 
227                              struct socket_address *src)
228 {
229         NTSTATUS status;
230         struct nbt_ntlogon_packet ntlogon;
231         int *replies = (int *)dgmslot->private;
232
233         printf("ntlogon reply from %s:%d\n", src->addr, src->port);
234
235         status = dgram_mailslot_ntlogon_parse(dgmslot, dgmslot, packet, &ntlogon);
236         if (!NT_STATUS_IS_OK(status)) {
237                 printf("Failed to parse ntlogon packet from %s:%d\n",
238                        src->addr, src->port);
239                 return;
240         }
241
242         NDR_PRINT_DEBUG(nbt_ntlogon_packet, &ntlogon);
243
244         (*replies)++;
245 }
246
247
248 /* test UDP/138 ntlogon requests */
249 static bool nbt_test_ntlogon(struct torture_context *tctx)
250 {
251         struct dgram_mailslot_handler *dgmslot;
252         struct nbt_dgram_socket *dgmsock = nbt_dgram_socket_init(tctx, NULL);
253         struct socket_address *dest;
254         struct test_join *join_ctx;
255         struct cli_credentials *machine_credentials;
256         const struct dom_sid *dom_sid;
257
258         const char *myaddress;
259         struct nbt_ntlogon_packet logon;
260         struct nbt_name myname;
261         NTSTATUS status;
262         struct timeval tv = timeval_current();
263         int replies = 0;
264
265         struct socket_address *socket_address;
266         const char *address;
267         struct nbt_name name;
268         
269         name.name = lp_workgroup(tctx->lp_ctx);
270         name.type = NBT_NAME_LOGON;
271         name.scope = NULL;
272
273         /* do an initial name resolution to find its IP */
274         torture_assert_ntstatus_ok(tctx, 
275                                    resolve_name(lp_resolve_context(tctx->lp_ctx), &name, tctx, &address, event_context_find(tctx)), 
276                                    talloc_asprintf(tctx, "Failed to resolve %s", name.name));
277
278         myaddress = talloc_strdup(dgmsock, iface_best_ip(tctx->lp_ctx, address));
279
280         socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
281                                                      myaddress, lp_dgram_port(tctx->lp_ctx));
282         torture_assert(tctx, socket_address != NULL, "Error getting address");
283
284         /* try receiving replies on port 138 first, which will only
285            work if we are root and smbd/nmbd are not running - fall
286            back to listening on any port, which means replies from
287            some windows versions won't be seen */
288         status = socket_listen(dgmsock->sock, socket_address, 0, 0);
289         if (!NT_STATUS_IS_OK(status)) {
290                 talloc_free(socket_address);
291                 socket_address = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name,
292                                                              myaddress, 0);
293                 torture_assert(tctx, socket_address != NULL, "Error getting address");
294
295                 socket_listen(dgmsock->sock, socket_address, 0, 0);
296         }
297
298         join_ctx = torture_join_domain(tctx, TEST_NAME, 
299                                        ACB_WSTRUST, &machine_credentials);
300         torture_assert(tctx, join_ctx != NULL,
301                        talloc_asprintf(tctx, "Failed to join domain %s as %s\n",
302                                        lp_workgroup(tctx->lp_ctx), TEST_NAME));
303
304         dom_sid = torture_join_sid(join_ctx);
305
306         /* setup a temporary mailslot listener for replies */
307         dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC,
308                                       ntlogon_handler, &replies);
309         
310
311         ZERO_STRUCT(logon);
312         logon.command = NTLOGON_SAM_LOGON;
313         logon.req.logon.request_count = 0;
314         logon.req.logon.computer_name = TEST_NAME;
315         logon.req.logon.user_name     = TEST_NAME"$";
316         logon.req.logon.mailslot_name = dgmslot->mailslot_name;
317         logon.req.logon.acct_control  = ACB_WSTRUST;
318         logon.req.logon.sid           = *dom_sid;
319         logon.req.logon.nt_version    = 1;
320         logon.req.logon.lmnt_token    = 0xFFFF;
321         logon.req.logon.lm20_token    = 0xFFFF;
322
323         make_nbt_name_client(&myname, TEST_NAME);
324
325         dest = socket_address_from_strings(dgmsock, dgmsock->sock->backend_name, 
326                                            address, lp_dgram_port(tctx->lp_ctx));
327         torture_assert(tctx, dest != NULL, "Error getting address");
328         status = dgram_mailslot_ntlogon_send(dgmsock, DGRAM_DIRECT_UNIQUE,
329                                              &name, dest, &myname, &logon);
330         torture_assert_ntstatus_ok(tctx, status, "Failed to send ntlogon request");
331
332         while (timeval_elapsed(&tv) < 5 && replies == 0) {
333                 event_loop_once(dgmsock->event_ctx);
334         }
335
336         torture_leave_domain(join_ctx);
337         return true;
338 }
339
340
341 /*
342   test nbt dgram operations
343 */
344 struct torture_suite *torture_nbt_dgram(TALLOC_CTX *mem_ctx)
345 {
346         struct torture_suite *suite = torture_suite_create(mem_ctx, "DGRAM");
347
348         torture_suite_add_simple_test(suite, "netlogon", nbt_test_netlogon);
349         torture_suite_add_simple_test(suite, "netlogon2", nbt_test_netlogon2);
350         torture_suite_add_simple_test(suite, "ntlogon", nbt_test_ntlogon);
351
352         return suite;
353 }