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