r5358: - added initial WINS server code. It passes most of the NBT-WINS test, but...
authorAndrew Tridgell <tridge@samba.org>
Sat, 12 Feb 2005 11:33:42 +0000 (11:33 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:09:45 +0000 (13:09 -0500)
  do secure server WACK responses

- added a ldap_string_to_time() function, for converting a LDAP
  formatted time to a time_t
(This used to be commit 9aa3313b3f93e47e3f93028e072f6a23b3c22385)

source4/include/structs.h
source4/lib/time.c
source4/libcli/nbt/nbtname.c
source4/librpc/idl/nbt.idl
source4/nbt_server/config.mk
source4/nbt_server/defense.c
source4/nbt_server/nbt_server.h
source4/nbt_server/packet.c
source4/nbt_server/winsdb.c [new file with mode: 0644]
source4/nbt_server/winsdb.h [new file with mode: 0644]
source4/nbt_server/winsserver.c

index 61c1f4211c46b5aaeb385c2eeab1167c4b8b45c1..32a30d9d9da3966e5273042838587bbba28ef322 100644 (file)
@@ -173,7 +173,9 @@ struct stream_server_ops;
 
 struct nbtd_server;
 struct nbtd_interface;
+struct wins_server;
 
 struct mutex_ops;
 
 struct ads_struct;
+
index 7a4059f646ea037c47660803cdf792db21c31a20..67397e953a6d9446862247d0ff0dadf1ac5c9d15 100644 (file)
@@ -292,9 +292,9 @@ char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
        return buf;
 }
 
-/***************************************************************************
-return a LDAP time string
-  ***************************************************************************/
+/*
+  return a LDAP time string
+*/
 char *ldap_timestring(TALLOC_CTX *mem_ctx, time_t t)
 {
        struct tm *tm = gmtime(&t);
@@ -311,6 +311,28 @@ char *ldap_timestring(TALLOC_CTX *mem_ctx, time_t t)
                               tm->tm_sec);
 }
 
+
+/*
+  convert a LDAP time string to a time_t. Return 0 if unable to convert
+*/
+time_t ldap_string_to_time(const char *s)
+{
+       struct tm tm;
+       
+       if (s == NULL) return 0;
+       
+       ZERO_STRUCT(tm);
+       if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z", 
+                  &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
+                  &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+               return 0;
+       }
+       tm.tm_year -= 1900;
+       tm.tm_mon -= 1;
+       
+       return timegm(&tm);
+}
+
 /****************************************************************************
  Return the date and time as a string
 ****************************************************************************/
index adc66980c4fa23a9ed6e639d9da0ab20c5736a36..b937d0aa26d68969bb60d0a99571ebed2693bc71 100644 (file)
@@ -359,10 +359,10 @@ static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
 /*
   form a string for a NBT name
 */
-const char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
+char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
 {
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
-       const char *ret;
+       char *ret;
        if (name->scope) {              
                ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
                                      nbt_hex_encode(tmp_ctx, name->name),
index 859cecd593fc952a061e73ef669f7d477ddade58..04fe0c4f90507e207ed86d14f5d37f4722e403b4 100644 (file)
@@ -38,6 +38,7 @@ interface nbt
 
        /* rcode values */
        typedef enum {
+               NBT_RCODE_OK  = 0x0,
                NBT_RCODE_FMT = 0x1,
                NBT_RCODE_SVR = 0x2,
                NBT_RCODE_NAM = 0x3,
index 8054ebc4de2f4a9a43cafc2148a9d91de57afd2c..12d0a09b6bcb73399ab944e4d205c254217e7647 100644 (file)
@@ -10,10 +10,11 @@ ADD_OBJ_FILES = \
                nbt_server/register.o \
                nbt_server/query.o \
                nbt_server/nodestatus.o \
-               nbt_server/winsserver.o \
                nbt_server/winsclient.o \
                nbt_server/defense.o \
-               nbt_server/packet.o
+               nbt_server/packet.o \
+               nbt_server/winsserver.o \
+               nbt_server/winsdb.o
 REQUIRED_SUBSYSTEMS = \
                LIBCLI_NBT
 # End SUBSYSTEM SMB
index 00e0e740afb16bb8be9f222b91effe338c481533..c59877e4b74d66c207dbfee4c7b2e206d4e6e347 100644 (file)
@@ -60,8 +60,8 @@ void nbtd_request_defense(struct nbt_name_socket *nbtsock,
                DEBUG(2,("Defending name %s on %s against %s\n",
                         nbt_name_string(packet, name), 
                         iface->bcast_address, src_address));
-               nbtd_negative_name_registration_reply(nbtsock, packet, 
-                                                     src_address, src_port);
+               nbtd_name_registration_reply(nbtsock, packet, 
+                                            src_address, src_port, NBT_RCODE_ACT);
        } else {
                nbtd_winsserver_request(nbtsock, packet, src_address, src_port);
        }
index 309c01a639e0def914f48e4e8e23d14cd5ec457b..a698ebf1a027c02bb658eb0033a594f2de22a528 100644 (file)
@@ -67,8 +67,7 @@ struct nbtd_server {
           our names with a WINS server */
        struct nbtd_interface *wins_interface;
 
-       /* wins server database handle, if configured */
-       struct ldb_wrap *wins_db;
+       struct wins_server *winssrv;
 };
 
 
index e6eec27fdcdd85d06125c53a79e38987fae872f5..638390914968b892a5b964b57f25457384332a95 100644 (file)
@@ -178,11 +178,12 @@ failed:
 }
 
 /*
-  send a name defense reply
+  send a name registration reply
 */
-void nbtd_negative_name_registration_reply(struct nbt_name_socket *nbtsock, 
-                                          struct nbt_name_packet *request_packet, 
-                                          const char *src_address, int src_port)
+void nbtd_name_registration_reply(struct nbt_name_socket *nbtsock, 
+                                 struct nbt_name_packet *request_packet, 
+                                 const char *src_address, int src_port,
+                                 uint8_t rcode)
 {
        struct nbt_name_packet *packet;
        struct nbt_name *name = &request_packet->questions[0].name;
@@ -198,7 +199,7 @@ void nbtd_negative_name_registration_reply(struct nbt_name_socket *nbtsock,
                NBT_FLAG_AUTHORITIVE |
                NBT_FLAG_RECURSION_DESIRED |
                NBT_FLAG_RECURSION_AVAIL |
-               NBT_RCODE_ACT;
+               rcode;
        
        packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
        if (packet->answers == NULL) goto failed;
@@ -206,10 +207,53 @@ void nbtd_negative_name_registration_reply(struct nbt_name_socket *nbtsock,
        packet->answers[0].name     = *name;
        packet->answers[0].rr_type  = NBT_QTYPE_NETBIOS;
        packet->answers[0].rr_class = NBT_QCLASS_IP;
-       packet->answers[0].ttl      = 0;
+       packet->answers[0].ttl      = request_packet->additional[0].ttl;
        packet->answers[0].rdata    = request_packet->additional[0].rdata;
 
-       DEBUG(7,("Sending negative name registration reply for %s to %s:%d\n", 
+       DEBUG(7,("Sending %s name registration reply for %s to %s:%d\n", 
+                rcode==0?"positive":"negative",
+                nbt_name_string(packet, name), src_address, src_port));
+       
+       nbt_name_reply_send(nbtsock, src_address, src_port, packet);
+
+failed:
+       talloc_free(packet);
+}
+
+
+/*
+  send a name release reply
+*/
+void nbtd_name_release_reply(struct nbt_name_socket *nbtsock, 
+                            struct nbt_name_packet *request_packet, 
+                            const char *src_address, int src_port,
+                            uint8_t rcode)
+{
+       struct nbt_name_packet *packet;
+       struct nbt_name *name = &request_packet->questions[0].name;
+
+       packet = talloc_zero(nbtsock, struct nbt_name_packet);
+       if (packet == NULL) return;
+
+       packet->name_trn_id = request_packet->name_trn_id;
+       packet->ancount = 1;
+       packet->operation = 
+               NBT_FLAG_REPLY | 
+               NBT_OPCODE_RELEASE |
+               NBT_FLAG_AUTHORITIVE |
+               rcode;
+       
+       packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
+       if (packet->answers == NULL) goto failed;
+
+       packet->answers[0].name     = *name;
+       packet->answers[0].rr_type  = NBT_QTYPE_NETBIOS;
+       packet->answers[0].rr_class = NBT_QCLASS_IP;
+       packet->answers[0].ttl      = request_packet->additional[0].ttl;
+       packet->answers[0].rdata    = request_packet->additional[0].rdata;
+
+       DEBUG(7,("Sending %s name release reply for %s to %s:%d\n", 
+                rcode==0?"positive":"negative",
                 nbt_name_string(packet, name), src_address, src_port));
        
        nbt_name_reply_send(nbtsock, src_address, src_port, packet);
diff --git a/source4/nbt_server/winsdb.c b/source4/nbt_server/winsdb.c
new file mode 100644 (file)
index 0000000..bb7ce49
--- /dev/null
@@ -0,0 +1,178 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   WINS database routines
+
+   Copyright (C) Andrew Tridgell       2005
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "nbt_server/nbt_server.h"
+#include "nbt_server/winsdb.h"
+#include "lib/ldb/include/ldb.h"
+#include "db_wrap.h"
+
+/*
+  load a WINS entry from the database
+*/
+struct winsdb_record *winsdb_load(struct wins_server *winssrv, 
+                                 struct nbt_name *name, TALLOC_CTX *mem_ctx)
+{
+       struct ldb_message **res = NULL;
+       int ret;
+       struct winsdb_record *rec;
+       struct ldb_message_element *el;
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       const char *expr;
+       int i;
+
+       expr = talloc_asprintf(tmp_ctx, "dn=%s", nbt_name_string(tmp_ctx, name));
+       if (expr == NULL) goto failed;
+
+       /* find the record in the WINS database */
+       ret = ldb_search(winssrv->wins_db->ldb, NULL, LDB_SCOPE_ONELEVEL, expr, NULL, &res);
+       if (res != NULL) {
+               talloc_steal(tmp_ctx, res);
+       }
+       if (ret != 1) goto failed;
+
+       rec = talloc(tmp_ctx, struct winsdb_record);
+       if (rec == NULL) goto failed;
+
+       /* parse it into a more convenient winsdb_record structure */
+       rec->name           = name;
+       rec->state          = ldb_msg_find_int(res[0], "active", WINS_REC_RELEASED);
+       rec->nb_flags       = ldb_msg_find_int(res[0], "nbFlags", 0);
+       rec->expire_time    = ldap_string_to_time(ldb_msg_find_string(res[0], "expires", NULL));
+       rec->registered_by  = ldb_msg_find_string(res[0], "registeredBy", NULL);
+       talloc_steal(rec, rec->registered_by);
+
+       el = ldb_msg_find_element(res[0], "address");
+       if (el == NULL) goto failed;
+
+       rec->addresses     = talloc_array(rec, const char *, el->num_values+1);
+       if (rec->addresses == NULL) goto failed;
+
+       for (i=0;i<el->num_values;i++) {
+               rec->addresses[i] = talloc_steal(rec->addresses, el->values[i].data);
+       }
+       rec->addresses[i] = NULL;
+
+       talloc_steal(mem_ctx, rec);
+       talloc_free(tmp_ctx);
+       return rec;
+
+failed:
+       talloc_free(tmp_ctx);
+       return NULL;
+}
+
+
+/*
+  form a ldb_message from a winsdb_record
+*/
+static struct ldb_message *winsdb_message(struct wins_server *winssrv, 
+                                         struct winsdb_record *rec, TALLOC_CTX *mem_ctx)
+{
+       int i, ret=0;
+       struct ldb_context *ldb = winssrv->wins_db->ldb;
+       struct ldb_message *msg = ldb_msg_new(mem_ctx);
+       if (msg == NULL) goto failed;
+
+       msg->dn = nbt_name_string(msg, rec->name);
+       if (msg->dn == NULL) goto failed;
+       ret |= ldb_msg_add_fmt(ldb, msg, "active", "%u", rec->state);
+       ret |= ldb_msg_add_fmt(ldb, msg, "nbFlags", "0x%04x", rec->nb_flags);
+       ret |= ldb_msg_add_string(ldb, msg, "registeredBy", rec->registered_by);
+       ret |= ldb_msg_add_string(ldb, msg, "expires", 
+                                 ldap_timestring(msg, rec->expire_time));
+       for (i=0;rec->addresses[i];i++) {
+               ret |= ldb_msg_add_string(ldb, msg, "address", rec->addresses[i]);
+       }
+       if (ret != 0) goto failed;
+       return msg;
+
+failed:
+       talloc_free(msg);
+       return NULL;
+}
+
+/*
+  save a WINS record into the database
+*/
+uint8_t winsdb_add(struct wins_server *winssrv, struct winsdb_record *rec)
+{
+       struct ldb_context *ldb = winssrv->wins_db->ldb;
+       struct ldb_message *msg;
+       TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
+       int ret;
+
+       msg = winsdb_message(winssrv, rec, tmp_ctx);
+       if (msg == NULL) goto failed;
+       ret = ldb_add(ldb, msg);
+       if (ret != 0) goto failed;
+
+       talloc_free(tmp_ctx);
+       return NBT_RCODE_OK;
+
+failed:
+       talloc_free(tmp_ctx);
+       return NBT_RCODE_SVR;
+}
+
+
+/*
+  modify a WINS record in the database
+*/
+uint8_t winsdb_modify(struct wins_server *winssrv, struct winsdb_record *rec)
+{
+       struct ldb_context *ldb = winssrv->wins_db->ldb;
+       struct ldb_message *msg;
+       TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
+       int ret;
+       int i;
+
+       msg = winsdb_message(winssrv, rec, tmp_ctx);
+       if (msg == NULL) goto failed;
+
+       for (i=0;i<msg->num_elements;i++) {
+               msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
+       }
+
+       ret = ldb_modify(ldb, msg);
+       if (ret != 0) goto failed;
+
+       talloc_free(tmp_ctx);
+       return NBT_RCODE_OK;
+
+failed:
+       talloc_free(tmp_ctx);
+       return NBT_RCODE_SVR;
+}
+
+/*
+  connect to the WINS database
+*/
+NTSTATUS winsdb_init(struct wins_server *winssrv)
+{
+       winssrv->wins_db = ldb_wrap_connect(winssrv, lp_wins_url(), 0, NULL);
+       if (winssrv->wins_db == NULL) {
+               return NT_STATUS_INTERNAL_DB_ERROR;
+       }
+
+       return NT_STATUS_OK;
+}
diff --git a/source4/nbt_server/winsdb.h b/source4/nbt_server/winsdb.h
new file mode 100644 (file)
index 0000000..72aeb8e
--- /dev/null
@@ -0,0 +1,46 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   WINS server structures
+
+   Copyright (C) Andrew Tridgell       2005
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+enum wins_record_state {
+       WINS_REC_RELEASED=0,
+       WINS_REC_ACTIVE=1
+};
+
+/*
+  each record in the database contains the following information
+*/
+struct winsdb_record {
+       struct nbt_name *name;
+       uint16_t nb_flags;
+       enum wins_record_state state;
+       time_t expire_time;
+       const char *registered_by;
+       const char **addresses;
+};
+
+struct wins_server {
+       /* wins server database handle */
+       struct ldb_wrap *wins_db;
+
+       uint32_t min_ttl;
+       uint32_t max_ttl;
+};
index 22cfee415c743757c0b3ff91ef8d9a059dc492ec..b59a1c9fa355ed656e57054c759fb95e6c3e90b3 100644 (file)
 
 #include "includes.h"
 #include "nbt_server/nbt_server.h"
+#include "nbt_server/winsdb.h"
+#include "system/time.h"
 
+/*
+  register a new name with WINS
+*/
+static uint8_t wins_register_new(struct nbt_name_socket *nbtsock, 
+                                struct nbt_name_packet *packet, 
+                                const char *src_address, int src_port)
+{
+       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
+                                                      struct nbtd_interface);
+       struct wins_server *winssrv = iface->nbtsrv->winssrv;
+       struct nbt_name *name = &packet->questions[0].name;
+       uint32_t ttl = packet->additional[0].ttl;
+       struct winsdb_record rec;
+
+       ttl = MIN(ttl, winssrv->max_ttl);
+       ttl = MAX(ttl, winssrv->min_ttl);
+
+       rec.name          = name;
+       rec.nb_flags      = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
+       rec.state         = WINS_REC_ACTIVE;
+       rec.expire_time   = time(NULL) + ttl;
+       rec.registered_by = src_address;
+       rec.addresses     = str_list_make(packet, 
+                                         packet->additional[0].rdata.netbios.addresses[0].ipaddr,
+                                         NULL);
+       
+       return winsdb_add(winssrv, &rec);
+}
 
 
+/*
+  register a name
+*/
+static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock, 
+                                    struct nbt_name_packet *packet, 
+                                    const char *src_address, int src_port)
+{
+       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
+                                                      struct nbtd_interface);
+       struct wins_server *winssrv = iface->nbtsrv->winssrv;
+       struct nbt_name *name = &packet->questions[0].name;
+       struct winsdb_record *rec;
+       uint8_t rcode = 0;
+
+       rec = winsdb_load(winssrv, name, packet);
+       if (rec == NULL) {
+               rcode = wins_register_new(nbtsock, packet, src_address, src_port);
+       } else if (rec->state != WINS_REC_ACTIVE) {
+               uint32_t ttl = packet->additional[0].ttl;
+               ttl = MIN(ttl, winssrv->max_ttl);
+               ttl = MAX(ttl, winssrv->min_ttl);
+               rec->nb_flags      = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
+               rec->state         = WINS_REC_ACTIVE;
+               rec->expire_time   = time(NULL) + ttl;
+               rec->registered_by = src_address;
+               rec->addresses     = str_list_make(packet, 
+                                                  packet->additional[0].rdata.netbios.addresses[0].ipaddr,
+                                                  NULL);
+               winsdb_modify(winssrv, rec);
+       } else {
+               rcode = NBT_RCODE_ACT;
+       }
+
+       nbtd_name_registration_reply(nbtsock, packet, src_address, src_port, rcode);
+}
+
+
+
+/*
+  query a name
+*/
 static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock, 
                                  struct nbt_name_packet *packet, 
                                  const char *src_address, int src_port)
 {
-       nbtd_negative_name_query_reply(nbtsock, packet, src_address, src_port);
-}
+       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
+                                                      struct nbtd_interface);
+       struct wins_server *winssrv = iface->nbtsrv->winssrv;
+       struct nbt_name *name = &packet->questions[0].name;
+       struct winsdb_record *rec;
+
+       rec = winsdb_load(winssrv, name, packet);
+       if (rec == NULL || rec->state != WINS_REC_ACTIVE) {
+               nbtd_negative_name_query_reply(nbtsock, packet, src_address, src_port);
+               return;
+       }
 
-static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock, 
-                                   struct nbt_name_packet *packet, 
-                                   const char *src_address, int src_port)
-{
-       nbtd_negative_name_registration_reply(nbtsock, packet, src_address, src_port);
+       nbtd_name_query_reply(nbtsock, packet, src_address, src_port, name, 
+                             0, rec->nb_flags, rec->addresses);
 }
 
-
+/*
+  release a name
+*/
 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, 
                                    struct nbt_name_packet *packet, 
                                    const char *src_address, int src_port)
 {
+       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
+                                                      struct nbtd_interface);
+       struct wins_server *winssrv = iface->nbtsrv->winssrv;
+       struct nbt_name *name = &packet->questions[0].name;
+       struct winsdb_record *rec;
+
+       rec = winsdb_load(winssrv, name, packet);
+       if (rec != NULL && rec->state == WINS_REC_ACTIVE) {
+               rec->state = WINS_REC_RELEASED;
+               winsdb_modify(winssrv, rec);
+       }
+
+       /* we match w2k3 by always giving a positive reply to name releases. */
+       nbtd_name_release_reply(nbtsock, packet, src_address, src_port, NBT_RCODE_OK);
 }
 
 
@@ -54,7 +147,10 @@ void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
                             struct nbt_name_packet *packet, 
                             const char *src_address, int src_port)
 {
-       if (packet->operation & NBT_FLAG_BROADCAST) {
+       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
+                                                      struct nbtd_interface);
+       struct wins_server *winssrv = iface->nbtsrv->winssrv;
+       if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
                return;
        }
 
@@ -83,14 +179,15 @@ void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
 {
        if (!lp_wins_support()) {
-               nbtsrv->wins_db = NULL;
+               nbtsrv->winssrv = NULL;
                return NT_STATUS_OK;
        }
 
-       nbtsrv->wins_db = ldb_wrap_connect(nbtsrv, lp_wins_url(), 0, NULL);
-       if (nbtsrv->wins_db == NULL) {
-               return NT_STATUS_INTERNAL_DB_ERROR;
-       }
+       nbtsrv->winssrv = talloc(nbtsrv, struct wins_server);
+       NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
+
+       nbtsrv->winssrv->max_ttl = lp_max_wins_ttl();
+       nbtsrv->winssrv->min_ttl = lp_min_wins_ttl();
 
-       return NT_STATUS_OK;
+       return winsdb_init(nbtsrv->winssrv);
 }