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