r19339: Merge my 4.0-unittest branch. This adds an API for more fine-grained
[bbaumbach/samba-autobuild/.git] / source4 / torture / nbt / wins.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NBT WINS server 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 "lib/socket/socket.h"
25 #include "libcli/resolve/resolve.h"
26 #include "system/network.h"
27 #include "lib/socket/netif.h"
28 #include "librpc/gen_ndr/ndr_nbt.h"
29 #include "torture/torture.h"
30 #include "torture/nbt/proto.h"
31
32 #define CHECK_VALUE(tctx, v, correct) \
33         torture_assert_int_equal(tctx, v, correct, "Incorrect value")
34
35 #define CHECK_STRING(tctx, v, correct) \
36         torture_assert_casestr_equal(tctx, v, correct, "Incorrect value")
37
38 #define CHECK_NAME(tctx, _name, correct) do { \
39         CHECK_STRING(tctx, (_name).name, (correct).name); \
40         CHECK_VALUE(tctx, (uint8_t)(_name).type, (uint8_t)(correct).type); \
41         CHECK_STRING(tctx, (_name).scope, (correct).scope); \
42 } while (0)
43
44
45 /*
46   test operations against a WINS server
47 */
48 static bool nbt_test_wins_name(struct torture_context *tctx, const char *address,
49                                struct nbt_name *name, uint16_t nb_flags)
50 {
51         struct nbt_name_register_wins io;
52         struct nbt_name_query query;
53         struct nbt_name_refresh_wins refresh;
54         struct nbt_name_release release;
55         NTSTATUS status;
56         struct nbt_name_socket *nbtsock = nbt_name_socket_init(tctx, NULL);
57         const char *myaddress = talloc_strdup(tctx, iface_best_ip(address));
58         struct socket_address *socket_address;
59
60         socket_address = socket_address_from_strings(tctx, 
61                                                      nbtsock->sock->backend_name,
62                                                      myaddress, 0);
63         torture_assert(tctx, socket_address != NULL, 
64                                    "Error getting address");
65
66         /* we do the listen here to ensure the WINS server receives the packets from
67            the right IP */
68         status = socket_listen(nbtsock->sock, socket_address, 0, 0);
69         torture_assert_ntstatus_ok(tctx, status, 
70                                                            "socket_listen for WINS failed");
71         talloc_free(socket_address);
72
73         torture_comment(tctx, "Testing name registration to WINS with name %s at %s nb_flags=0x%x\n", 
74                nbt_name_string(tctx, name), myaddress, nb_flags);
75
76         torture_comment(tctx, "release the name\n");
77         release.in.name = *name;
78         release.in.dest_addr = address;
79         release.in.address = myaddress;
80         release.in.nb_flags = nb_flags;
81         release.in.broadcast = False;
82         release.in.timeout = 3;
83         release.in.retries = 0;
84
85         status = nbt_name_release(nbtsock, tctx, &release);
86         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
87         CHECK_VALUE(tctx, release.out.rcode, 0);
88
89         torture_comment(tctx, "register the name\n");
90         io.in.name = *name;
91         io.in.wins_servers = str_list_make(tctx, address, NULL);
92         io.in.addresses = str_list_make(tctx, myaddress, NULL);
93         io.in.nb_flags = nb_flags;
94         io.in.ttl = 300000;
95         
96         status = nbt_name_register_wins(nbtsock, tctx, &io);
97         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register", address));
98         
99         CHECK_STRING(tctx, io.out.wins_server, address);
100         CHECK_VALUE(tctx, io.out.rcode, 0);
101
102         if (name->type != NBT_NAME_MASTER &&
103             name->type != NBT_NAME_LOGON && 
104             name->type != NBT_NAME_BROWSER && 
105             (nb_flags & NBT_NM_GROUP)) {
106                 torture_comment(tctx, "Try to register as non-group\n");
107                 io.in.nb_flags &= ~NBT_NM_GROUP;
108                 status = nbt_name_register_wins(nbtsock, tctx, &io);
109                 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register\n",
110                         address));
111                 CHECK_VALUE(tctx, io.out.rcode, NBT_RCODE_ACT);
112         }
113
114         torture_comment(tctx, "query the name to make sure its there\n");
115         query.in.name = *name;
116         query.in.dest_addr = address;
117         query.in.broadcast = False;
118         query.in.wins_lookup = True;
119         query.in.timeout = 3;
120         query.in.retries = 0;
121
122         status = nbt_name_query(nbtsock, tctx, &query);
123         if (name->type == NBT_NAME_MASTER) {
124                 torture_assert_ntstatus_equal(
125                           tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, 
126                           talloc_asprintf(tctx, "Bad response from %s for name query", address));
127                 return true;
128         }
129         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
130         
131         CHECK_NAME(tctx, query.out.name, *name);
132         CHECK_VALUE(tctx, query.out.num_addrs, 1);
133         if (name->type != NBT_NAME_LOGON &&
134             (nb_flags & NBT_NM_GROUP)) {
135                 CHECK_STRING(tctx, query.out.reply_addrs[0], "255.255.255.255");
136         } else {
137                 CHECK_STRING(tctx, query.out.reply_addrs[0], myaddress);
138         }
139
140
141         query.in.name.name = strupper_talloc(tctx, name->name);
142         if (query.in.name.name &&
143             strcmp(query.in.name.name, name->name) != 0) {
144                 torture_comment(tctx, "check case sensitivity\n");
145                 status = nbt_name_query(nbtsock, tctx, &query);
146                 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
147         }
148
149         query.in.name = *name;
150         if (name->scope) {
151                 query.in.name.scope = strupper_talloc(tctx, name->scope);
152         }
153         if (query.in.name.scope &&
154             strcmp(query.in.name.scope, name->scope) != 0) {
155                 torture_comment(tctx, "check case sensitivity on scope\n");
156                 status = nbt_name_query(nbtsock, tctx, &query);
157                 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
158         }
159
160         torture_comment(tctx, "refresh the name\n");
161         refresh.in.name = *name;
162         refresh.in.wins_servers = str_list_make(tctx, address, NULL);
163         refresh.in.addresses = str_list_make(tctx, myaddress, NULL);
164         refresh.in.nb_flags = nb_flags;
165         refresh.in.ttl = 12345;
166         
167         status = nbt_name_refresh_wins(nbtsock, tctx, &refresh);
168         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name refresh", address));
169         
170         CHECK_STRING(tctx, refresh.out.wins_server, address);
171         CHECK_VALUE(tctx, refresh.out.rcode, 0);
172
173         torture_comment(tctx, "release the name\n");
174         release.in.name = *name;
175         release.in.dest_addr = address;
176         release.in.address = myaddress;
177         release.in.nb_flags = nb_flags;
178         release.in.broadcast = False;
179         release.in.timeout = 3;
180         release.in.retries = 0;
181
182         status = nbt_name_release(nbtsock, tctx, &release);
183         torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
184         
185         CHECK_NAME(tctx, release.out.name, *name);
186         CHECK_VALUE(tctx, release.out.rcode, 0);
187
188         torture_comment(tctx, "release again\n");
189         status = nbt_name_release(nbtsock, tctx, &release);
190         torture_assert_ntstatus_ok(tctx, status, 
191                                 talloc_asprintf(tctx, "Bad response from %s for name query",
192                        address));
193         
194         CHECK_NAME(tctx, release.out.name, *name);
195         CHECK_VALUE(tctx, release.out.rcode, 0);
196
197
198         torture_comment(tctx, "query the name to make sure its gone\n");
199         query.in.name = *name;
200         status = nbt_name_query(nbtsock, tctx, &query);
201         if (name->type != NBT_NAME_LOGON &&
202             (nb_flags & NBT_NM_GROUP)) {
203                 torture_assert_ntstatus_ok(tctx, status, 
204                                 "ERROR: Name query failed after group release");
205         } else {
206                 torture_assert_ntstatus_equal(tctx, status, 
207                                                                           NT_STATUS_OBJECT_NAME_NOT_FOUND,
208                                 "Incorrect response to name query");
209         }
210         
211         return true;
212 }
213
214
215
216 /*
217   test operations against a WINS server
218 */
219 static bool nbt_test_wins(struct torture_context *tctx)
220 {
221         struct nbt_name name;
222         uint32_t r = (uint32_t)(random() % (100000));
223         const char *address;
224         bool ret = true;
225
226         if (!torture_nbt_get_name(tctx, &name, &address))
227                 return false;
228
229         name.name = talloc_asprintf(tctx, "_TORTURE-%5u", r);
230
231         name.type = NBT_NAME_CLIENT;
232         name.scope = NULL;
233         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
234
235         name.type = NBT_NAME_MASTER;
236         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
237
238         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
239
240         name.type = NBT_NAME_SERVER;
241         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
242
243         name.type = NBT_NAME_LOGON;
244         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
245
246         name.type = NBT_NAME_BROWSER;
247         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
248
249         name.type = NBT_NAME_PDC;
250         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
251
252         name.type = 0xBF;
253         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
254
255         name.type = 0xBE;
256         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
257
258         name.scope = "example";
259         name.type = 0x72;
260         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
261
262         name.scope = "example";
263         name.type = 0x71;
264         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H | NBT_NM_GROUP);
265
266         name.scope = "foo.example.com";
267         name.type = 0x72;
268         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
269
270         name.name = talloc_asprintf(tctx, "_T\01-%5u.foo", r);
271         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
272
273         name.name = "";
274         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
275
276         name.name = talloc_asprintf(tctx, ".");
277         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
278
279         name.name = talloc_asprintf(tctx, "%5u-\377\200\300FOO", r);
280         ret &= nbt_test_wins_name(tctx, address, &name, NBT_NODE_H);
281
282         return ret;
283 }
284
285 /*
286   test WINS operations
287 */
288 struct torture_suite *torture_nbt_wins(void)
289 {
290         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), 
291                                                                                                            "WINS");
292
293         torture_suite_add_simple_test(suite, "wins", nbt_test_wins);
294
295         return suite;
296 }