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