Line data Source code
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 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 "lib/util/dlinklist.h"
24 : #include "lib/events/events.h"
25 : #include "lib/socket/socket.h"
26 : #include "libcli/resolve/resolve.h"
27 : #include "system/network.h"
28 : #include "lib/socket/netif.h"
29 : #include "librpc/gen_ndr/ndr_nbt.h"
30 : #include "torture/torture.h"
31 : #include "torture/nbt/proto.h"
32 : #include "param/param.h"
33 :
34 : /* rcode used when you don't want to check the rcode */
35 : #define WINS_TEST_RCODE_WE_DONT_CARE 255
36 :
37 :
38 : #define CHECK_VALUE(tctx, v, correct) \
39 : torture_assert_int_equal(tctx, v, correct, "Incorrect value")
40 :
41 : #define CHECK_STRING(tctx, v, correct) \
42 : torture_assert_casestr_equal(tctx, v, correct, "Incorrect value")
43 :
44 : #define CHECK_NAME(tctx, _name, correct) do { \
45 : CHECK_STRING(tctx, (_name).name, (correct).name); \
46 : CHECK_VALUE(tctx, (uint8_t)(_name).type, (uint8_t)(correct).type); \
47 : CHECK_STRING(tctx, (_name).scope, (correct).scope); \
48 : } while (0)
49 :
50 :
51 : /*
52 : test operations against a WINS server
53 : */
54 25 : static bool nbt_test_wins_name(struct torture_context *tctx, const char *address,
55 : struct nbt_name *name, uint16_t nb_flags,
56 : bool try_low_port,
57 : uint8_t register_rcode)
58 : {
59 : struct nbt_name_register_wins io;
60 : struct nbt_name_register name_register;
61 : struct nbt_name_query query;
62 : struct nbt_name_refresh_wins refresh;
63 : struct nbt_name_release release;
64 : struct nbt_name_request *req;
65 : NTSTATUS status;
66 25 : struct nbt_name_socket *nbtsock = torture_init_nbt_socket(tctx);
67 : const char *myaddress;
68 : struct socket_address *socket_address;
69 : struct interface *ifaces;
70 25 : bool low_port = try_low_port;
71 : char **l;
72 :
73 25 : load_interface_list(tctx, tctx->lp_ctx, &ifaces);
74 :
75 25 : myaddress = talloc_strdup(tctx, iface_list_best_ip(ifaces, address));
76 :
77 50 : socket_address = socket_address_from_strings(tctx,
78 25 : nbtsock->sock->backend_name,
79 : myaddress, lpcfg_nbt_port(tctx->lp_ctx));
80 25 : torture_assert(tctx, socket_address != NULL,
81 : "Error getting address");
82 :
83 : /* we do the listen here to ensure the WINS server receives the packets from
84 : the right IP */
85 25 : status = socket_listen(nbtsock->sock, socket_address, 0, 0);
86 25 : talloc_free(socket_address);
87 25 : if (!NT_STATUS_IS_OK(status)) {
88 0 : low_port = false;
89 0 : socket_address = socket_address_from_strings(tctx,
90 0 : nbtsock->sock->backend_name,
91 : myaddress, 0);
92 0 : torture_assert(tctx, socket_address != NULL,
93 : "Error getting address");
94 :
95 0 : status = socket_listen(nbtsock->sock, socket_address, 0, 0);
96 0 : talloc_free(socket_address);
97 0 : torture_assert_ntstatus_ok(tctx, status,
98 : "socket_listen for WINS failed");
99 : }
100 :
101 25 : torture_comment(tctx, "Testing name registration to WINS with name %s at %s nb_flags=0x%x\n",
102 : nbt_name_string(tctx, name), myaddress, nb_flags);
103 :
104 25 : torture_comment(tctx, "release the name\n");
105 25 : release.in.name = *name;
106 25 : release.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
107 25 : release.in.dest_addr = address;
108 25 : release.in.address = myaddress;
109 25 : release.in.nb_flags = nb_flags;
110 25 : release.in.broadcast = false;
111 25 : release.in.timeout = 3;
112 25 : release.in.retries = 0;
113 :
114 25 : status = nbt_name_release(nbtsock, tctx, &release);
115 25 : torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
116 25 : CHECK_VALUE(tctx, release.out.rcode, 0);
117 :
118 25 : if (nb_flags & NBT_NM_GROUP) {
119 : /* ignore this for group names */
120 21 : } else if (!low_port) {
121 9 : torture_comment(tctx, "no low port - skip: register the name with a wrong address\n");
122 : } else {
123 12 : torture_comment(tctx, "register the name with a wrong address (makes the next request slow!)\n");
124 12 : io.in.name = *name;
125 12 : io.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
126 12 : io.in.wins_servers = const_str_list(
127 : str_list_make_single(tctx, address));
128 12 : io.in.addresses = const_str_list(
129 : str_list_make_single(tctx, "127.64.64.1"));
130 12 : io.in.nb_flags = nb_flags;
131 12 : io.in.ttl = 300000;
132 :
133 12 : status = nbt_name_register_wins(nbtsock, tctx, &io);
134 12 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
135 0 : torture_assert_ntstatus_ok(tctx, status,
136 : talloc_asprintf(tctx, "No response from %s for name register\n",
137 : address));
138 : }
139 12 : torture_assert_ntstatus_ok(tctx, status,
140 : talloc_asprintf(tctx, "Bad response from %s for name register\n",
141 : address));
142 :
143 12 : CHECK_STRING(tctx, io.out.wins_server, address);
144 12 : if (register_rcode != WINS_TEST_RCODE_WE_DONT_CARE) {
145 5 : CHECK_VALUE(tctx, io.out.rcode, 0);
146 : }
147 :
148 12 : torture_comment(tctx, "register the name correct address\n");
149 12 : name_register.in.name = *name;
150 12 : name_register.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
151 12 : name_register.in.dest_addr = address;
152 12 : name_register.in.address = myaddress;
153 12 : name_register.in.nb_flags = nb_flags;
154 12 : name_register.in.register_demand= false;
155 12 : name_register.in.broadcast = false;
156 12 : name_register.in.multi_homed = true;
157 12 : name_register.in.ttl = 300000;
158 12 : name_register.in.timeout = 3;
159 12 : name_register.in.retries = 2;
160 :
161 : /*
162 : * test if the server ignores resent requests
163 : */
164 12 : req = nbt_name_register_send(nbtsock, &name_register);
165 : while (true) {
166 36 : tevent_loop_once(nbtsock->event_ctx);
167 24 : if (req->state != NBT_REQUEST_WAIT) {
168 1 : break;
169 : }
170 23 : if (req->received_wack) {
171 : /*
172 : * if we received the wack response
173 : * we resend the request and the
174 : * server should ignore that
175 : * and not handle it as new request
176 : */
177 11 : req->state = NBT_REQUEST_SEND;
178 11 : DLIST_ADD_END(nbtsock->send_queue, req);
179 11 : TEVENT_FD_WRITEABLE(nbtsock->fde);
180 11 : break;
181 : }
182 : }
183 :
184 12 : status = nbt_name_register_recv(req, tctx, &name_register);
185 12 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
186 0 : torture_assert_ntstatus_ok(tctx, status,
187 : talloc_asprintf(tctx, "No response from %s for name register\n",
188 : address));
189 : }
190 12 : torture_assert_ntstatus_ok(tctx, status,
191 : talloc_asprintf(tctx, "Bad response from %s for name register\n",
192 : address));
193 :
194 12 : if (register_rcode != WINS_TEST_RCODE_WE_DONT_CARE) {
195 5 : CHECK_VALUE(tctx, name_register.out.rcode, 0);
196 : }
197 12 : CHECK_STRING(tctx, name_register.out.reply_addr, myaddress);
198 : }
199 :
200 25 : torture_comment(tctx, "register the name correct address\n");
201 25 : io.in.name = *name;
202 25 : io.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
203 25 : l = str_list_make_single(tctx, address);
204 25 : io.in.wins_servers = discard_const_p(const char *, l);
205 25 : l = str_list_make_single(tctx, myaddress);
206 25 : io.in.addresses = discard_const_p(const char *, l);
207 25 : io.in.nb_flags = nb_flags;
208 25 : io.in.ttl = 300000;
209 :
210 25 : status = nbt_name_register_wins(nbtsock, tctx, &io);
211 25 : torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register", address));
212 :
213 25 : CHECK_STRING(tctx, io.out.wins_server, address);
214 25 : if (register_rcode != WINS_TEST_RCODE_WE_DONT_CARE) {
215 18 : CHECK_VALUE(tctx, io.out.rcode, register_rcode);
216 : }
217 :
218 25 : if (register_rcode != NBT_RCODE_OK) {
219 8 : return true;
220 : }
221 :
222 32 : if (name->type != NBT_NAME_MASTER &&
223 29 : name->type != NBT_NAME_LOGON &&
224 27 : name->type != NBT_NAME_BROWSER &&
225 : (nb_flags & NBT_NM_GROUP)) {
226 1 : torture_comment(tctx, "Try to register as non-group\n");
227 1 : io.in.nb_flags &= ~NBT_NM_GROUP;
228 1 : status = nbt_name_register_wins(nbtsock, tctx, &io);
229 1 : torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register\n",
230 : address));
231 1 : CHECK_VALUE(tctx, io.out.rcode, NBT_RCODE_ACT);
232 : }
233 :
234 17 : torture_comment(tctx, "query the name to make sure its there\n");
235 17 : query.in.name = *name;
236 17 : query.in.dest_addr = address;
237 17 : query.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
238 17 : query.in.broadcast = false;
239 17 : query.in.wins_lookup = true;
240 17 : query.in.timeout = 3;
241 17 : query.in.retries = 0;
242 :
243 17 : status = nbt_name_query(nbtsock, tctx, &query);
244 17 : if (name->type == NBT_NAME_MASTER) {
245 2 : torture_assert_ntstatus_equal(
246 : tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
247 : talloc_asprintf(tctx, "Bad response from %s for name query", address));
248 2 : return true;
249 : }
250 15 : torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
251 :
252 15 : CHECK_NAME(tctx, query.out.name, *name);
253 15 : CHECK_VALUE(tctx, query.out.num_addrs, 1);
254 15 : if (name->type != NBT_NAME_LOGON &&
255 : (nb_flags & NBT_NM_GROUP)) {
256 2 : CHECK_STRING(tctx, query.out.reply_addrs[0], "255.255.255.255");
257 : } else {
258 13 : CHECK_STRING(tctx, query.out.reply_addrs[0], myaddress);
259 : }
260 :
261 :
262 15 : query.in.name.name = strupper_talloc(tctx, name->name);
263 28 : if (query.in.name.name &&
264 13 : strcmp(query.in.name.name, name->name) != 0) {
265 1 : torture_comment(tctx, "check case sensitivity\n");
266 1 : status = nbt_name_query(nbtsock, tctx, &query);
267 1 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
268 : }
269 :
270 15 : query.in.name = *name;
271 15 : if (name->scope) {
272 8 : query.in.name.scope = strupper_talloc(tctx, name->scope);
273 : }
274 23 : if (query.in.name.scope &&
275 8 : strcmp(query.in.name.scope, name->scope) != 0) {
276 7 : torture_comment(tctx, "check case sensitivity on scope\n");
277 7 : status = nbt_name_query(nbtsock, tctx, &query);
278 7 : torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND, talloc_asprintf(tctx, "Bad response from %s for name query", address));
279 : }
280 :
281 15 : torture_comment(tctx, "refresh the name\n");
282 15 : refresh.in.name = *name;
283 15 : refresh.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
284 15 : l = str_list_make_single(tctx, address);
285 15 : refresh.in.wins_servers = discard_const_p(const char *, l);
286 15 : l = str_list_make_single(tctx, myaddress);
287 15 : refresh.in.addresses = discard_const_p(const char *, l);
288 15 : refresh.in.nb_flags = nb_flags;
289 15 : refresh.in.ttl = 12345;
290 :
291 15 : status = nbt_name_refresh_wins(nbtsock, tctx, &refresh);
292 15 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
293 0 : torture_assert_ntstatus_ok(tctx, status,
294 : talloc_asprintf(tctx, "No response from %s for name refresh",
295 : address));
296 : }
297 15 : torture_assert_ntstatus_ok(tctx, status,
298 : talloc_asprintf(tctx, "Bad response from %s for name refresh",
299 : address));
300 :
301 15 : CHECK_STRING(tctx, refresh.out.wins_server, address);
302 15 : CHECK_VALUE(tctx, refresh.out.rcode, 0);
303 :
304 15 : printf("release the name\n");
305 15 : release.in.name = *name;
306 15 : release.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
307 15 : release.in.dest_addr = address;
308 15 : release.in.address = myaddress;
309 15 : release.in.nb_flags = nb_flags;
310 15 : release.in.broadcast = false;
311 15 : release.in.timeout = 3;
312 15 : release.in.retries = 0;
313 :
314 15 : status = nbt_name_release(nbtsock, tctx, &release);
315 15 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
316 0 : torture_assert_ntstatus_ok(tctx, status,
317 : talloc_asprintf(tctx, "No response from %s for name release",
318 : address));
319 : }
320 15 : torture_assert_ntstatus_ok(tctx, status,
321 : talloc_asprintf(tctx, "Bad response from %s for name release",
322 : address));
323 :
324 15 : CHECK_NAME(tctx, release.out.name, *name);
325 15 : CHECK_VALUE(tctx, release.out.rcode, 0);
326 :
327 15 : if (nb_flags & NBT_NM_GROUP) {
328 : /* ignore this for group names */
329 12 : } else if (!low_port) {
330 7 : torture_comment(tctx, "no low port - skip: register the name with a wrong address\n");
331 : } else {
332 5 : torture_comment(tctx, "register the name with a wrong address (makes the next request slow!)\n");
333 5 : io.in.name = *name;
334 5 : io.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
335 5 : io.in.wins_servers = const_str_list(
336 : str_list_make_single(tctx, address));
337 5 : io.in.addresses = const_str_list(
338 : str_list_make_single(tctx, "127.64.64.1"));
339 5 : io.in.nb_flags = nb_flags;
340 5 : io.in.ttl = 300000;
341 :
342 5 : status = nbt_name_register_wins(nbtsock, tctx, &io);
343 5 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
344 0 : torture_assert_ntstatus_ok(tctx, status,
345 : talloc_asprintf(tctx, "No response from %s for name register\n",
346 : address));
347 : }
348 5 : torture_assert_ntstatus_ok(tctx, status,
349 : talloc_asprintf(tctx, "Bad response from %s for name register\n",
350 : address));
351 :
352 5 : CHECK_STRING(tctx, io.out.wins_server, address);
353 5 : CHECK_VALUE(tctx, io.out.rcode, 0);
354 : }
355 :
356 15 : torture_comment(tctx, "refresh the name with the correct address\n");
357 15 : refresh.in.name = *name;
358 15 : refresh.in.wins_port = lpcfg_nbt_port(tctx->lp_ctx);
359 15 : refresh.in.wins_servers = const_str_list(
360 : str_list_make_single(tctx, address));
361 15 : refresh.in.addresses = const_str_list(
362 : str_list_make_single(tctx, myaddress));
363 15 : refresh.in.nb_flags = nb_flags;
364 15 : refresh.in.ttl = 12345;
365 :
366 15 : status = nbt_name_refresh_wins(nbtsock, tctx, &refresh);
367 15 : if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
368 0 : torture_assert_ntstatus_ok(tctx, status,
369 : talloc_asprintf(tctx, "No response from %s for name refresh",
370 : address));
371 : }
372 15 : torture_assert_ntstatus_ok(tctx, status,
373 : talloc_asprintf(tctx, "Bad response from %s for name refresh",
374 : address));
375 :
376 15 : CHECK_STRING(tctx, refresh.out.wins_server, address);
377 15 : CHECK_VALUE(tctx, refresh.out.rcode, 0);
378 :
379 15 : torture_comment(tctx, "release the name\n");
380 15 : release.in.name = *name;
381 15 : release.in.dest_port = lpcfg_nbt_port(tctx->lp_ctx);
382 15 : release.in.dest_addr = address;
383 15 : release.in.address = myaddress;
384 15 : release.in.nb_flags = nb_flags;
385 15 : release.in.broadcast = false;
386 15 : release.in.timeout = 3;
387 15 : release.in.retries = 0;
388 :
389 15 : status = nbt_name_release(nbtsock, tctx, &release);
390 15 : torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
391 :
392 15 : CHECK_NAME(tctx, release.out.name, *name);
393 15 : CHECK_VALUE(tctx, release.out.rcode, 0);
394 :
395 15 : torture_comment(tctx, "release again\n");
396 15 : status = nbt_name_release(nbtsock, tctx, &release);
397 15 : torture_assert_ntstatus_ok(tctx, status,
398 : talloc_asprintf(tctx, "Bad response from %s for name query",
399 : address));
400 :
401 15 : CHECK_NAME(tctx, release.out.name, *name);
402 15 : CHECK_VALUE(tctx, release.out.rcode, 0);
403 :
404 :
405 15 : torture_comment(tctx, "query the name to make sure its gone\n");
406 15 : query.in.name = *name;
407 15 : status = nbt_name_query(nbtsock, tctx, &query);
408 15 : if (name->type != NBT_NAME_LOGON &&
409 : (nb_flags & NBT_NM_GROUP)) {
410 2 : torture_assert_ntstatus_ok(tctx, status,
411 : "ERROR: Name query failed after group release");
412 : } else {
413 13 : torture_assert_ntstatus_equal(tctx, status,
414 : NT_STATUS_OBJECT_NAME_NOT_FOUND,
415 : "Incorrect response to name query");
416 : }
417 :
418 15 : return true;
419 : }
420 :
421 :
422 2 : static char *test_nbt_wins_scope_string(TALLOC_CTX *mem_ctx, uint8_t count)
423 : {
424 : char *res;
425 : uint8_t i;
426 :
427 2 : res = talloc_array(mem_ctx, char, count+1);
428 2 : if (res == NULL) {
429 0 : return NULL;
430 : }
431 :
432 477 : for (i=0; i < count; i++) {
433 475 : switch (i) {
434 6 : case 63:
435 : case 63 + 1 + 63:
436 : case 63 + 1 + 63 + 1 + 63:
437 6 : res[i] = '.';
438 6 : break;
439 469 : default:
440 469 : res[i] = '0' + (i%10);
441 469 : break;
442 : }
443 : }
444 :
445 2 : res[count] = '\0';
446 :
447 2 : talloc_set_name_const(res, res);
448 :
449 2 : return res;
450 : }
451 :
452 : /*
453 : test operations against a WINS server
454 : */
455 1 : static bool nbt_test_wins(struct torture_context *tctx)
456 : {
457 : struct nbt_name name;
458 1 : uint32_t r = (uint32_t)(random() % (100000));
459 : const char *address;
460 1 : bool ret = true;
461 :
462 1 : if (!torture_nbt_get_name(tctx, &name, &address))
463 0 : return false;
464 :
465 1 : name.name = talloc_asprintf(tctx, "_TORTURE-%5u", r);
466 :
467 1 : name.type = NBT_NAME_CLIENT;
468 1 : name.scope = NULL;
469 1 : ret &= nbt_test_wins_name(tctx, address, &name,
470 : NBT_NODE_H, true, NBT_RCODE_OK);
471 :
472 1 : name.type = NBT_NAME_MASTER;
473 1 : ret &= nbt_test_wins_name(tctx, address, &name,
474 : NBT_NODE_H, false, NBT_RCODE_OK);
475 :
476 1 : ret &= nbt_test_wins_name(tctx, address, &name,
477 : NBT_NODE_H | NBT_NM_GROUP, false, NBT_RCODE_OK);
478 :
479 1 : name.type = NBT_NAME_SERVER;
480 1 : ret &= nbt_test_wins_name(tctx, address, &name,
481 : NBT_NODE_H, true, NBT_RCODE_OK);
482 :
483 1 : name.type = NBT_NAME_LOGON;
484 1 : ret &= nbt_test_wins_name(tctx, address, &name,
485 : NBT_NODE_H | NBT_NM_GROUP, false, NBT_RCODE_OK);
486 :
487 1 : name.type = NBT_NAME_BROWSER;
488 1 : ret &= nbt_test_wins_name(tctx, address, &name,
489 : NBT_NODE_H | NBT_NM_GROUP, false, NBT_RCODE_OK);
490 :
491 1 : name.type = NBT_NAME_PDC;
492 1 : ret &= nbt_test_wins_name(tctx, address, &name,
493 : NBT_NODE_H, true, NBT_RCODE_OK);
494 :
495 1 : name.type = 0xBF;
496 1 : ret &= nbt_test_wins_name(tctx, address, &name,
497 : NBT_NODE_H, true, NBT_RCODE_OK);
498 :
499 1 : name.type = 0xBE;
500 1 : ret &= nbt_test_wins_name(tctx, address, &name,
501 : NBT_NODE_H, false, NBT_RCODE_OK);
502 :
503 1 : name.scope = "example";
504 1 : name.type = 0x72;
505 1 : ret &= nbt_test_wins_name(tctx, address, &name,
506 : NBT_NODE_H, true, NBT_RCODE_OK);
507 :
508 1 : name.scope = "example";
509 1 : name.type = 0x71;
510 1 : ret &= nbt_test_wins_name(tctx, address, &name,
511 : NBT_NODE_H | NBT_NM_GROUP, false, NBT_RCODE_OK);
512 :
513 1 : name.scope = "foo.example.com";
514 1 : name.type = 0x72;
515 1 : ret &= nbt_test_wins_name(tctx, address, &name,
516 : NBT_NODE_H, false, NBT_RCODE_OK);
517 :
518 1 : name.name = talloc_asprintf(tctx, "_T\01-%5u.foo", r);
519 1 : ret &= nbt_test_wins_name(tctx, address, &name,
520 : NBT_NODE_H, false, NBT_RCODE_OK);
521 :
522 1 : name.name = "";
523 1 : ret &= nbt_test_wins_name(tctx, address, &name,
524 : NBT_NODE_H, false, NBT_RCODE_OK);
525 :
526 1 : name.name = talloc_asprintf(tctx, ".");
527 1 : ret &= nbt_test_wins_name(tctx, address, &name,
528 : NBT_NODE_H, false, NBT_RCODE_OK);
529 :
530 1 : name.name = talloc_asprintf(tctx, "%5u-\377\200\300FOO", r);
531 1 : ret &= nbt_test_wins_name(tctx, address, &name,
532 : NBT_NODE_H, false, NBT_RCODE_OK);
533 :
534 1 : name.scope = test_nbt_wins_scope_string(tctx, 237);
535 1 : ret &= nbt_test_wins_name(tctx, address, &name,
536 : NBT_NODE_H, false, NBT_RCODE_OK);
537 :
538 1 : name.scope = test_nbt_wins_scope_string(tctx, 238);
539 1 : ret &= nbt_test_wins_name(tctx, address, &name,
540 : NBT_NODE_H, false, NBT_RCODE_SVR);
541 :
542 1 : return ret;
543 : }
544 :
545 : /*
546 : * Test that the WINS server does not call 'wins hook' when the name
547 : * contains dodgy characters.
548 : */
549 1 : static bool nbt_test_wins_bad_names(struct torture_context *tctx)
550 : {
551 1 : const char *address = NULL;
552 1 : const char *wins_hook_file = NULL;
553 1 : bool ret = true;
554 : int err;
555 : bool ok;
556 1 : struct nbt_name name = {};
557 : size_t i, j;
558 1 : FILE *fh = NULL;
559 :
560 : struct {
561 : const char *name;
562 : bool should_succeed;
563 1 : } test_cases[] = {
564 : {"NORMAL", true},
565 : {"|look|", false},
566 : {"look&true", false},
567 : {"look\\;false", false},
568 : {"&ls>foo", false}, /* already fails due to DN syntax */
569 : {"has spaces", false},
570 : {"hyphen-dot.0", true},
571 : };
572 :
573 1 : wins_hook_file = talloc_asprintf(tctx, "%s/wins_hook_writes_here",
574 : getenv("SELFTEST_TMPDIR"));
575 :
576 1 : if (!torture_nbt_get_name(tctx, &name, &address)) {
577 0 : return false;
578 : }
579 :
580 8 : for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
581 7 : err = unlink(wins_hook_file);
582 7 : if (err != 0 && errno != ENOENT) {
583 : /* we expect ENOENT, but nothing else */
584 0 : torture_comment(tctx,
585 : "unlink %zu of '%s' failed\n",
586 : i, wins_hook_file);
587 : }
588 :
589 7 : name.name = test_cases[i].name;
590 7 : name.type = NBT_NAME_CLIENT;
591 7 : ok = nbt_test_wins_name(tctx, address,
592 : &name,
593 : NBT_NODE_H,
594 : true,
595 : WINS_TEST_RCODE_WE_DONT_CARE
596 : );
597 7 : if (ok == false) {
598 : /*
599 : * This happens when the name interferes with
600 : * the DN syntax when it is put in winsdb.
601 : *
602 : * The wins hook will not be reached.
603 : */
604 0 : torture_comment(tctx, "tests for '%s' failed\n",
605 : name.name);
606 : }
607 :
608 : /*
609 : * poll for the file being created by the wins hook.
610 : */
611 57 : for (j = 0; j < 10; j++) {
612 52 : usleep(200000);
613 52 : fh = fopen(wins_hook_file, "r");
614 52 : if (fh != NULL) {
615 2 : break;
616 : }
617 : }
618 :
619 7 : if (fh == NULL) {
620 5 : if (errno == ENOENT) {
621 5 : if (test_cases[i].should_succeed) {
622 0 : torture_comment(
623 : tctx,
624 : "wins hook for '%s' failed\n",
625 : test_cases[i].name);
626 0 : ret = false;
627 : }
628 : } else {
629 0 : torture_comment(
630 : tctx,
631 : "wins hook for '%s' unexpectedly failed with %d\n",
632 : test_cases[i].name,
633 0 : errno);
634 0 : ret = false;
635 : }
636 : } else {
637 2 : char readback[17] = {0};
638 2 : size_t n = fread(readback, 1, 16, fh);
639 2 : torture_comment(tctx,
640 : "wins hook wrote '%s' read '%.*s'\n",
641 : test_cases[i].name,
642 : (int)n, readback);
643 :
644 2 : if (! test_cases[i].should_succeed) {
645 0 : torture_comment(tctx,
646 : "wins hook for '%s' should fail\n",
647 : test_cases[i].name);
648 0 : ret = false;
649 : }
650 2 : fclose(fh);
651 : }
652 : }
653 1 : err = unlink(wins_hook_file);
654 1 : if (err != 0 && errno != ENOENT) {
655 0 : torture_comment(tctx, "final unlink of '%s' failed\n",
656 : wins_hook_file);
657 : }
658 1 : torture_assert(tctx, ret, "wins hook failure\n");
659 1 : return ret;
660 : }
661 :
662 :
663 : /*
664 : test WINS operations
665 : */
666 964 : struct torture_suite *torture_nbt_wins(TALLOC_CTX *mem_ctx)
667 : {
668 964 : struct torture_suite *suite = torture_suite_create(mem_ctx, "wins");
669 :
670 964 : torture_suite_add_simple_test(suite, "wins", nbt_test_wins);
671 964 : torture_suite_add_simple_test(suite, "wins_bad_names",
672 : nbt_test_wins_bad_names);
673 :
674 964 : return suite;
675 : }
|