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             : }
       |