LCOV - code coverage report
Current view: top level - source4/nbt_server/wins - winsdb.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 401 519 77.3 %
Date: 2021-09-23 10:06:22 Functions: 21 23 91.3 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    WINS database routines
       5             : 
       6             :    Copyright (C) Andrew Tridgell        2005
       7             :    Copyright (C) Stefan Metzmacher      2005
       8             :       
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             :    
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             :    
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "nbt_server/nbt_server.h"
      25             : #include "nbt_server/wins/winsdb.h"
      26             : #include <ldb.h>
      27             : #include <ldb_errors.h>
      28             : #include "librpc/gen_ndr/ndr_nbt.h"
      29             : #include "system/time.h"
      30             : #include "ldb_wrap.h"
      31             : #include "system/network.h"
      32             : #include "lib/socket/netif.h"
      33             : #include "param/param.h"
      34             : #include "lib/util/smb_strtox.h"
      35             : 
      36             : #undef strcasecmp
      37             : 
      38        5570 : uint64_t winsdb_get_maxVersion(struct winsdb_handle *h)
      39             : {
      40             :         int ret;
      41        5570 :         struct ldb_context *ldb = h->ldb;
      42             :         struct ldb_dn *dn;
      43        5570 :         struct ldb_result *res = NULL;
      44        5570 :         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
      45        5570 :         uint64_t maxVersion = 0;
      46             : 
      47        5570 :         dn = ldb_dn_new(tmp_ctx, ldb, "CN=VERSION");
      48        5570 :         if (!dn) goto failed;
      49             : 
      50             :         /* find the record in the WINS database */
      51        5570 :         ret = ldb_search(ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
      52        5570 :         if (ret != LDB_SUCCESS) goto failed;
      53        5570 :         if (res->count > 1) goto failed;
      54             : 
      55        5570 :         if (res->count == 1) {
      56         165 :                 maxVersion = ldb_msg_find_attr_as_uint64(res->msgs[0], "maxVersion", 0);
      57             :         }
      58             : 
      59        9518 : failed:
      60        5570 :         talloc_free(tmp_ctx);
      61        5570 :         return maxVersion;
      62             : }
      63             : 
      64             : /*
      65             :  if newVersion == 0 return the old maxVersion + 1 and save it
      66             :  if newVersion > 0 return MAX(oldMaxVersion, newMaxVersion) and save it
      67             : */
      68         286 : uint64_t winsdb_set_maxVersion(struct winsdb_handle *h, uint64_t newMaxVersion)
      69             : {
      70             :         int trans;
      71             :         int ret;
      72             :         struct ldb_dn *dn;
      73         286 :         struct ldb_result *res = NULL;
      74         286 :         struct ldb_message *msg = NULL;
      75         286 :         struct ldb_context *wins_db = h->ldb;
      76         286 :         TALLOC_CTX *tmp_ctx = talloc_new(wins_db);
      77         286 :         uint64_t oldMaxVersion = 0;
      78             : 
      79         286 :         trans = ldb_transaction_start(wins_db);
      80         286 :         if (trans != LDB_SUCCESS) goto failed;
      81             : 
      82         286 :         dn = ldb_dn_new(tmp_ctx, wins_db, "CN=VERSION");
      83         286 :         if (!dn) goto failed;
      84             : 
      85             :         /* find the record in the WINS database */
      86         286 :         ret = ldb_search(wins_db, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
      87         286 :         if (ret != LDB_SUCCESS) goto failed;
      88         286 :         if (res->count > 1) goto failed;
      89             : 
      90         286 :         if (res->count == 1) {
      91         285 :                 oldMaxVersion = ldb_msg_find_attr_as_uint64(res->msgs[0], "maxVersion", 0);
      92             :         }
      93             : 
      94         286 :         if (newMaxVersion == 0) {
      95         286 :                 newMaxVersion = oldMaxVersion + 1;
      96             :         } else {
      97           0 :                 newMaxVersion = MAX(oldMaxVersion, newMaxVersion);
      98             :         }
      99             : 
     100         286 :         msg = ldb_msg_new(tmp_ctx);
     101         286 :         if (!msg) goto failed;
     102         286 :         msg->dn = dn;
     103             : 
     104             : 
     105         286 :         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
     106         286 :         if (ret != LDB_SUCCESS) goto failed;
     107         286 :         ret = ldb_msg_add_string(msg, "objectClass", "winsMaxVersion");
     108         286 :         if (ret != LDB_SUCCESS) goto failed;
     109         286 :         ret = ldb_msg_add_empty(msg, "maxVersion", LDB_FLAG_MOD_REPLACE, NULL);
     110         286 :         if (ret != LDB_SUCCESS) goto failed;
     111         286 :         ret = ldb_msg_add_fmt(msg, "maxVersion", "%llu", (long long)newMaxVersion);
     112         286 :         if (ret != LDB_SUCCESS) goto failed;
     113             : 
     114         286 :         ret = ldb_modify(wins_db, msg);
     115         286 :         if (ret != LDB_SUCCESS) ret = ldb_add(wins_db, msg);
     116         286 :         if (ret != LDB_SUCCESS) goto failed;
     117             : 
     118         286 :         trans = ldb_transaction_commit(wins_db);
     119         286 :         if (trans != LDB_SUCCESS) goto failed;
     120             : 
     121         286 :         talloc_free(tmp_ctx);
     122         286 :         return newMaxVersion;
     123             : 
     124           0 : failed:
     125           0 :         if (trans == LDB_SUCCESS) ldb_transaction_cancel(wins_db);
     126           0 :         talloc_free(tmp_ctx);
     127           0 :         return 0;
     128             : }
     129             : 
     130             : /*
     131             :   return a DN for a nbt_name
     132             : */
     133        2243 : static struct ldb_dn *winsdb_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
     134             :                                 const struct nbt_name *name)
     135             : {
     136             :         struct ldb_dn *dn;
     137             : 
     138        2243 :         dn = ldb_dn_new_fmt(mem_ctx, ldb, "type=0x%02X", name->type);
     139        2243 :         if (ldb_dn_is_valid(dn) && name->name && *name->name) {
     140        2227 :                 ldb_dn_add_child_fmt(dn, "name=%s", name->name);
     141             :         }
     142        2243 :         if (ldb_dn_is_valid(dn) && name->scope && *name->scope) {
     143         421 :                 ldb_dn_add_child_fmt(dn, "scope=%s", name->scope);
     144             :         }
     145        2243 :         return dn;
     146             : }
     147             : 
     148        1497 : static NTSTATUS winsdb_nbt_name(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct nbt_name **_name)
     149             : {
     150             :         NTSTATUS status;
     151             :         struct nbt_name *name;
     152             :         unsigned int comp_num;
     153        1497 :         uint32_t cur = 0;
     154        1497 :         int error = 0;
     155             : 
     156        1497 :         name = talloc(mem_ctx, struct nbt_name);
     157        1497 :         if (!name) {
     158           0 :                 status = NT_STATUS_NO_MEMORY;
     159           0 :                 goto failed;
     160             :         }
     161             : 
     162        1497 :         comp_num = ldb_dn_get_comp_num(dn);
     163             : 
     164        1497 :         if (comp_num > 3) {
     165           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     166           0 :                 goto failed;
     167             :         }
     168             : 
     169        1497 :         if (comp_num > cur && strcasecmp("scope", ldb_dn_get_component_name(dn, cur)) == 0) {
     170         306 :                 name->scope  = (const char *)talloc_strdup(name, (char *)ldb_dn_get_component_val(dn, cur)->data);
     171         306 :                 cur++;
     172             :         } else {
     173        1191 :                 name->scope  = NULL;
     174             :         }
     175             : 
     176        1497 :         if (comp_num > cur && strcasecmp("name", ldb_dn_get_component_name(dn, cur)) == 0) {
     177        1490 :                 name->name   = (const char *)talloc_strdup(name, (char *)ldb_dn_get_component_val(dn, cur)->data);
     178        1490 :                 cur++;
     179             :         } else {
     180           7 :                 name->name   = talloc_strdup(name, "");
     181           7 :                 if (!name->name) {
     182           0 :                         status = NT_STATUS_NO_MEMORY;
     183           0 :                         goto failed;
     184             :                 }
     185             :         }
     186             : 
     187        1497 :         if (comp_num > cur && strcasecmp("type", ldb_dn_get_component_name(dn, cur)) == 0) {
     188        1497 :                 name->type =
     189        1497 :                         smb_strtoul(
     190        1497 :                                 (char *)ldb_dn_get_component_val(dn, cur)->data,
     191             :                                 NULL,
     192             :                                 0,
     193             :                                 &error,
     194             :                                 SMB_STR_STANDARD);
     195        1497 :                 if (error != 0) {
     196           0 :                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     197           0 :                         goto failed;
     198             :                 }
     199        1497 :                 cur++;
     200             :         } else {
     201           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     202           0 :                 goto failed;
     203             :         }
     204             : 
     205        1497 :         *_name = name;
     206        1497 :         return NT_STATUS_OK;
     207           0 : failed:
     208           0 :         talloc_free(name);
     209           0 :         return status;
     210             : }
     211             : 
     212             : /*
     213             :  decode the winsdb_addr("address") attribute:
     214             :  "172.31.1.1" or 
     215             :  "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z;"
     216             :  are valid records
     217             : */
     218        1764 : static NTSTATUS winsdb_addr_decode(struct winsdb_handle *h, struct winsdb_record *rec, struct ldb_val *val,
     219             :                                    TALLOC_CTX *mem_ctx, struct winsdb_addr **_addr)
     220             : {
     221             :         NTSTATUS status;
     222             :         struct winsdb_addr *addr;
     223             :         const char *address;
     224             :         const char *wins_owner;
     225             :         const char *expire_time;
     226             :         char *p;
     227             : 
     228        1764 :         addr = talloc(mem_ctx, struct winsdb_addr);
     229        1764 :         if (!addr) {
     230           0 :                 status = NT_STATUS_NO_MEMORY;
     231           0 :                 goto failed;
     232             :         }
     233             : 
     234        1764 :         address = (char *)val->data;
     235             : 
     236        1764 :         p = strchr(address, ';');
     237        1764 :         if (!p) {
     238             :                 /* support old entries, with only the address */
     239          26 :                 addr->address                = (const char *)talloc_steal(addr, val->data);
     240          26 :                 addr->wins_owner     = talloc_strdup(addr, rec->wins_owner);
     241          26 :                 if (!addr->wins_owner) {
     242           0 :                         status = NT_STATUS_NO_MEMORY;
     243           0 :                         goto failed;
     244             :                 }
     245          26 :                 addr->expire_time    = rec->expire_time;
     246          26 :                 *_addr = addr;
     247          26 :                 return NT_STATUS_OK;
     248             :         }
     249             : 
     250        1738 :         *p = '\0'; p++;
     251        1738 :         addr->address = talloc_strdup(addr, address);
     252        1738 :         if (!addr->address) {
     253           0 :                 status = NT_STATUS_NO_MEMORY;
     254           0 :                 goto failed;
     255             :         }
     256             : 
     257        1738 :         if (strncmp("winsOwner:", p, 10) != 0) {
     258           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     259           0 :                 goto failed;
     260             :         }
     261        1738 :         wins_owner = p + 10;
     262        1738 :         p = strchr(wins_owner, ';');
     263        1738 :         if (!p) {
     264           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     265           0 :                 goto failed;
     266             :         }
     267             : 
     268        1738 :         *p = '\0';p++;
     269        1738 :         if (strcmp(wins_owner, "0.0.0.0") == 0) {
     270           0 :                 wins_owner = h->local_owner;
     271             :         }
     272        1738 :         addr->wins_owner = talloc_strdup(addr, wins_owner);
     273        1738 :         if (!addr->wins_owner) {
     274           0 :                 status = NT_STATUS_NO_MEMORY;
     275           0 :                 goto failed;
     276             :         }
     277             : 
     278        1738 :         if (strncmp("expireTime:", p, 11) != 0) {
     279           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     280           0 :                 goto failed;
     281             :         }
     282             : 
     283        1738 :         expire_time = p + 11;
     284        1738 :         p = strchr(expire_time, ';');
     285        1738 :         if (!p) {
     286           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     287           0 :                 goto failed;
     288             :         }
     289             : 
     290        1738 :         *p = '\0';p++;
     291        1738 :         addr->expire_time = ldb_string_to_time(expire_time);
     292             : 
     293        1738 :         *_addr = addr;
     294        1738 :         return NT_STATUS_OK;
     295           0 : failed:
     296           0 :         talloc_free(addr);
     297           0 :         return status;
     298             : }
     299             : 
     300             : /*
     301             :  encode the winsdb_addr("address") attribute like this:
     302             :  non-static record:
     303             :  "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z;"
     304             :  static record:
     305             :  "172.31.1.1"
     306             : */
     307        1102 : static int ldb_msg_add_winsdb_addr(struct ldb_message *msg, struct winsdb_record *rec,
     308             :                                    const char *attr_name, struct winsdb_addr *addr)
     309             : {
     310             :         const char *str;
     311             : 
     312        1102 :         if (rec->is_static) {
     313          13 :                 str = talloc_strdup(msg, addr->address);
     314          13 :                 if (!str) return LDB_ERR_OPERATIONS_ERROR;
     315             :         } else {
     316             :                 char *expire_time;
     317        1089 :                 expire_time = ldb_timestring(msg, addr->expire_time);
     318        1089 :                 if (!expire_time) return LDB_ERR_OPERATIONS_ERROR;
     319        1089 :                 str = talloc_asprintf(msg, "%s;winsOwner:%s;expireTime:%s;",
     320             :                                       addr->address, addr->wins_owner,
     321             :                                       expire_time);
     322        1089 :                 talloc_free(expire_time);
     323        1089 :                 if (!str) return LDB_ERR_OPERATIONS_ERROR;
     324             :         }
     325             : 
     326        1102 :         return ldb_msg_add_string(msg, attr_name, str);
     327             : }
     328             : 
     329         761 : struct winsdb_addr **winsdb_addr_list_make(TALLOC_CTX *mem_ctx)
     330             : {
     331             :         struct winsdb_addr **addresses;
     332             : 
     333         761 :         addresses = talloc_array(mem_ctx, struct winsdb_addr *, 1);
     334         761 :         if (!addresses) return NULL;
     335             : 
     336         761 :         addresses[0] = NULL;
     337             : 
     338         761 :         return addresses;
     339             : }
     340             : 
     341         667 : static int winsdb_addr_sort_list (struct winsdb_addr **p1, struct winsdb_addr **p2, void *opaque)
     342             : {
     343         667 :         struct winsdb_addr *a1 = talloc_get_type(*p1, struct winsdb_addr);
     344         667 :         struct winsdb_addr *a2 = talloc_get_type(*p2, struct winsdb_addr);
     345         667 :         struct winsdb_handle *h= talloc_get_type(opaque, struct winsdb_handle);
     346         667 :         bool a1_owned = false;
     347         667 :         bool a2_owned = false;
     348             : 
     349             :         /*
     350             :          * first the owned addresses with the newest to the oldest address
     351             :          * then the replica addresses with the newest to the oldest address
     352             :          */
     353         667 :         if (a2->expire_time != a1->expire_time) {
     354          22 :                 return a2->expire_time - a1->expire_time;
     355             :         }
     356             : 
     357         645 :         if (strcmp(a2->wins_owner, h->local_owner) == 0) {
     358          75 :                 a2_owned = true;
     359             :         }
     360             : 
     361         645 :         if (strcmp(a1->wins_owner, h->local_owner) == 0) {
     362          75 :                 a1_owned = true;
     363             :         }
     364             : 
     365         645 :         return a2_owned - a1_owned;
     366             : }
     367             : 
     368         950 : struct winsdb_addr **winsdb_addr_list_add(struct winsdb_handle *h, const struct winsdb_record *rec,
     369             :                                           struct winsdb_addr **addresses, const char *address,
     370             :                                           const char *wins_owner, time_t expire_time,
     371             :                                           bool is_name_registration)
     372             : {
     373         950 :         struct winsdb_addr *old_addr = NULL;
     374         950 :         size_t len = 0;
     375             :         size_t i;
     376         950 :         bool found_old_replica = false;
     377             : 
     378             :         /*
     379             :          * count the addresses and maybe
     380             :          * find an old entry for the new address
     381             :          */
     382        1303 :         for (i=0; addresses[i]; i++) {
     383         353 :                 if (old_addr) continue;
     384         338 :                 if (strcmp(addresses[i]->address, address) == 0) {
     385          48 :                         old_addr = addresses[i];
     386             :                 }
     387             :         }
     388         950 :         len = i;
     389             : 
     390             :         /*
     391             :          * the address is already there
     392             :          * and we can replace it
     393             :          */
     394         950 :         if (old_addr) {
     395          48 :                 goto remove_old_addr;
     396             :         }
     397             : 
     398             :         /*
     399             :          * if we don't have 25 addresses already,
     400             :          * we can just add the new address
     401             :          */
     402         902 :         if (len < 25) {
     403         902 :                 goto add_new_addr;
     404             :         }
     405             : 
     406             :         /*
     407             :          * if we haven't found the address,
     408             :          * and we have already have 25 addresses
     409             :          * if so then we need to do the following:
     410             :          * - if it isn't a name registration, then just ignore the new address
     411             :          * - if it is a name registration, then first search for 
     412             :          *   the oldest replica and if there's no replica address
     413             :          *   search the oldest owned address
     414             :          */
     415           0 :         if (!is_name_registration) {
     416           0 :                 return addresses;
     417             :         }
     418             : 
     419             :         /*
     420             :          * find the oldest replica address, if there's no replica
     421             :          * record at all, find the oldest owned address
     422             :          */
     423           0 :         for (i=0; addresses[i]; i++) {
     424           0 :                 bool cur_is_replica = false;
     425             :                 /* find out if the current address is a replica */
     426           0 :                 if (strcmp(addresses[i]->wins_owner, h->local_owner) != 0) {
     427           0 :                         cur_is_replica = true;
     428             :                 }
     429             : 
     430             :                 /*
     431             :                  * if we already found a replica address and the current address
     432             :                  * is not a replica, then skip it
     433             :                  */
     434           0 :                 if (found_old_replica && !cur_is_replica) continue;
     435             : 
     436             :                 /*
     437             :                  * if we found the first replica address, reset the address
     438             :                  * that would be replaced
     439             :                  */
     440           0 :                 if (!found_old_replica && cur_is_replica) {
     441           0 :                         found_old_replica = true;
     442           0 :                         old_addr = addresses[i];
     443           0 :                         continue;
     444             :                 }
     445             : 
     446             :                 /*
     447             :                  * if the first address isn't a replica, just start with 
     448             :                  * the first one
     449             :                  */
     450           0 :                 if (!old_addr) {
     451           0 :                         old_addr = addresses[i];
     452           0 :                         continue;
     453             :                 }
     454             : 
     455             :                 /*
     456             :                  * see if we find an older address
     457             :                  */
     458           0 :                 if (addresses[i]->expire_time < old_addr->expire_time) {
     459           0 :                         old_addr = addresses[i];
     460           0 :                         continue;
     461             :                 }
     462             :         }
     463             : 
     464           0 : remove_old_addr:
     465          48 :         winsdb_addr_list_remove(addresses, old_addr->address);
     466          48 :         len --;
     467             : 
     468         950 : add_new_addr:
     469         950 :         addresses = talloc_realloc(addresses, addresses, struct winsdb_addr *, len + 2);
     470         950 :         if (!addresses) return NULL;
     471             : 
     472         950 :         addresses[len] = talloc(addresses, struct winsdb_addr);
     473         950 :         if (!addresses[len]) {
     474           0 :                 talloc_free(addresses);
     475           0 :                 return NULL;
     476             :         }
     477             : 
     478         950 :         addresses[len]->address = talloc_strdup(addresses[len], address);
     479         950 :         if (!addresses[len]->address) {
     480           0 :                 talloc_free(addresses);
     481           0 :                 return NULL;
     482             :         }
     483             : 
     484         950 :         addresses[len]->wins_owner = talloc_strdup(addresses[len], wins_owner);
     485         950 :         if (!addresses[len]->wins_owner) {
     486           0 :                 talloc_free(addresses);
     487           0 :                 return NULL;
     488             :         }
     489             : 
     490         950 :         addresses[len]->expire_time = expire_time;
     491             : 
     492         950 :         addresses[len+1] = NULL;
     493             : 
     494         950 :         LDB_TYPESAFE_QSORT(addresses, len+1, h, winsdb_addr_sort_list);
     495             : 
     496         950 :         return addresses;
     497             : }
     498             : 
     499         138 : void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address)
     500             : {
     501             :         size_t i;
     502             : 
     503         162 :         for (i=0; addresses[i]; i++) {
     504         162 :                 if (strcmp(addresses[i]->address, address) == 0) {
     505         138 :                         break;
     506             :                 }
     507             :         }
     508             : 
     509         307 :         for (; addresses[i]; i++) {
     510         169 :                 addresses[i] = addresses[i+1];
     511             :         }
     512             : 
     513         138 :         return;
     514             : }
     515             : 
     516         214 : struct winsdb_addr *winsdb_addr_list_check(struct winsdb_addr **addresses, const char *address)
     517             : {
     518             :         size_t i;
     519             : 
     520         246 :         for (i=0; addresses[i]; i++) {
     521         220 :                 if (strcmp(addresses[i]->address, address) == 0) {
     522         188 :                         return addresses[i];
     523             :                 }
     524             :         }
     525             : 
     526          26 :         return NULL;
     527             : }
     528             : 
     529        1638 : size_t winsdb_addr_list_length(struct winsdb_addr **addresses)
     530             : {
     531             :         size_t i;
     532        1638 :         for (i=0; addresses[i]; i++);
     533        1638 :         return i;
     534             : }
     535             : 
     536          60 : const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **addresses)
     537             : {
     538          60 :         size_t len = winsdb_addr_list_length(addresses);
     539          60 :         const char **str_list=NULL;
     540             :         size_t i;
     541             : 
     542         126 :         for (i=0; i < len; i++) {
     543          66 :                 str_list = str_list_add(str_list, addresses[i]->address);
     544          66 :                 if (!str_list[i]) {
     545           0 :                         return NULL;
     546             :                 }
     547             :         }
     548          60 :         talloc_steal(mem_ctx, str_list);
     549          60 :         return str_list;
     550             : }
     551             : 
     552             : /*
     553             :   load a WINS entry from the database
     554             : */
     555        1192 : NTSTATUS winsdb_lookup(struct winsdb_handle *h, 
     556             :                        const struct nbt_name *name,
     557             :                        TALLOC_CTX *mem_ctx,
     558             :                        struct winsdb_record **_rec)
     559             : {
     560             :         NTSTATUS status;
     561        1192 :         struct ldb_result *res = NULL;
     562             :         int ret;
     563             :         struct winsdb_record *rec;
     564        1192 :         struct ldb_context *wins_db = h->ldb;
     565        1192 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     566        1192 :         time_t now = time(NULL);
     567             : 
     568             :         /* find the record in the WINS database */
     569        1192 :         ret = ldb_search(wins_db, tmp_ctx, &res,
     570             :                          winsdb_dn(tmp_ctx, wins_db, name),
     571             :                          LDB_SCOPE_BASE, NULL, NULL);
     572             : 
     573        1192 :         if (ret != LDB_SUCCESS || res->count > 1) {
     574           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     575           0 :                 goto failed;
     576        1192 :         } else if (res->count== 0) {
     577         222 :                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
     578         222 :                 goto failed;
     579             :         }
     580             : 
     581         970 :         status = winsdb_record(h, res->msgs[0], tmp_ctx, now, &rec);
     582         970 :         if (!NT_STATUS_IS_OK(status)) goto failed;
     583             : 
     584         970 :         talloc_steal(mem_ctx, rec);
     585         970 :         talloc_free(tmp_ctx);
     586         970 :         *_rec = rec;
     587         970 :         return NT_STATUS_OK;
     588             : 
     589         222 : failed:
     590         222 :         talloc_free(tmp_ctx);
     591         222 :         return status;
     592             : }
     593             : 
     594        1497 : NTSTATUS winsdb_record(struct winsdb_handle *h, struct ldb_message *msg, TALLOC_CTX *mem_ctx, time_t now, struct winsdb_record **_rec)
     595             : {
     596             :         NTSTATUS status;
     597             :         struct winsdb_record *rec;
     598             :         struct ldb_message_element *el;
     599             :         struct nbt_name *name;
     600             :         uint32_t i, j, num_values;
     601             : 
     602        1497 :         rec = talloc(mem_ctx, struct winsdb_record);
     603        1497 :         if (rec == NULL) {
     604           0 :                 status = NT_STATUS_NO_MEMORY;
     605           0 :                 goto failed;
     606             :         }
     607             : 
     608        1497 :         status = winsdb_nbt_name(rec, msg->dn, &name);
     609        1497 :         if (!NT_STATUS_IS_OK(status)) goto failed;
     610             : 
     611        1497 :         if (strlen(name->name) > 15) {
     612           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     613           0 :                 goto failed;
     614             :         }
     615        1497 :         if (name->scope && strlen(name->scope) > 238) {
     616           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     617           0 :                 goto failed;
     618             :         }
     619             : 
     620             :         /* parse it into a more convenient winsdb_record structure */
     621        1497 :         rec->name            = name;
     622        1497 :         rec->type            = ldb_msg_find_attr_as_int(msg, "recordType", WREPL_TYPE_UNIQUE);
     623        1497 :         rec->state           = ldb_msg_find_attr_as_int(msg, "recordState", WREPL_STATE_RELEASED);
     624        1497 :         rec->node            = ldb_msg_find_attr_as_int(msg, "nodeType", WREPL_NODE_B);
     625        1497 :         rec->is_static               = ldb_msg_find_attr_as_int(msg, "isStatic", 0);
     626        1497 :         rec->expire_time     = ldb_string_to_time(ldb_msg_find_attr_as_string(msg, "expireTime", NULL));
     627        1497 :         rec->version         = ldb_msg_find_attr_as_uint64(msg, "versionID", 0);
     628        1497 :         rec->wins_owner              = ldb_msg_find_attr_as_string(msg, "winsOwner", NULL);
     629        1497 :         rec->registered_by   = ldb_msg_find_attr_as_string(msg, "registeredBy", NULL);
     630        1497 :         talloc_steal(rec, rec->wins_owner);
     631        1497 :         talloc_steal(rec, rec->registered_by);
     632             : 
     633        1497 :         if (!rec->wins_owner || strcmp(rec->wins_owner, "0.0.0.0") == 0) {
     634           0 :                 rec->wins_owner = h->local_owner;
     635             :         }
     636             : 
     637        1497 :         el = ldb_msg_find_element(msg, "address");
     638        1497 :         if (el) {
     639        1420 :                 num_values = el->num_values;
     640             :         } else {
     641          77 :                 num_values = 0;
     642             :         }
     643             : 
     644        1497 :         if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_GROUP) {
     645         694 :                 if (num_values != 1) {
     646           0 :                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     647           0 :                         goto failed;
     648             :                 }
     649             :         }
     650        1497 :         if (rec->state == WREPL_STATE_ACTIVE) {
     651         909 :                 if (num_values < 1) {
     652           0 :                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     653           0 :                         goto failed;
     654             :                 }
     655             :         }
     656        1497 :         if (num_values > 25) {
     657           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     658           0 :                 goto failed;
     659             :         }
     660             : 
     661        1497 :         rec->addresses     = talloc_array(rec, struct winsdb_addr *, num_values+1);
     662        1497 :         if (rec->addresses == NULL) {
     663           0 :                 status = NT_STATUS_NO_MEMORY;
     664           0 :                 goto failed;
     665             :         }
     666             : 
     667        3261 :         for (i=0,j=0;i<num_values;i++) {
     668        1764 :                 bool we_are_owner = false;
     669             : 
     670        1764 :                 status = winsdb_addr_decode(h, rec, &el->values[i], rec->addresses, &rec->addresses[j]);
     671        1764 :                 if (!NT_STATUS_IS_OK(status)) goto failed;
     672             : 
     673        1764 :                 if (strcmp(rec->addresses[j]->wins_owner, h->local_owner) == 0) {
     674         446 :                         we_are_owner = true;
     675             :                 }
     676             : 
     677             :                 /*
     678             :                  * the record isn't static and is active
     679             :                  * then don't add the address if it's expired,
     680             :                  * but only if we're the owner of the address
     681             :                  *
     682             :                  * This is important for SGROUP records,
     683             :                  * because each server thinks he's the owner of the
     684             :                  * record and the record isn't replicated on a
     685             :                  * name_refresh. So addresses owned by another owner
     686             :                  * could expire, but we still need to return them
     687             :                  * (as windows does).
     688             :                  */
     689        3502 :                 if (!rec->is_static &&
     690        1738 :                     rec->addresses[j]->expire_time <= now &&
     691           0 :                     rec->state == WREPL_STATE_ACTIVE &&
     692             :                     we_are_owner) {
     693           0 :                         DEBUG(5,("WINS: expiring name addr %s of %s (expired at %s)\n", 
     694             :                                  rec->addresses[j]->address, nbt_name_string(rec->addresses[j], rec->name),
     695             :                                  timestring(rec->addresses[j], rec->addresses[j]->expire_time)));
     696           0 :                         talloc_free(rec->addresses[j]);
     697           0 :                         rec->addresses[j] = NULL;
     698           0 :                         continue;
     699             :                 }
     700        1764 :                 j++;
     701             :         }
     702        1497 :         rec->addresses[j] = NULL;
     703        1497 :         num_values = j;
     704             : 
     705        1497 :         if (rec->is_static && rec->state == WREPL_STATE_ACTIVE) {
     706          26 :                 rec->expire_time = get_time_t_max();
     707          52 :                 for (i=0;rec->addresses[i];i++) {
     708          26 :                         rec->addresses[i]->expire_time = rec->expire_time;
     709             :                 }
     710             :         }
     711             : 
     712        1497 :         if (rec->state == WREPL_STATE_ACTIVE) {
     713         909 :                 if (num_values < 1) {
     714           0 :                         DEBUG(5,("WINS: expiring name %s (because it has no active addresses)\n", 
     715             :                                  nbt_name_string(mem_ctx, rec->name)));
     716           0 :                         rec->state = WREPL_STATE_RELEASED;
     717             :                 }
     718             :         }
     719             : 
     720        1497 :         *_rec = rec;
     721        1497 :         return NT_STATUS_OK;
     722           0 : failed:
     723           0 :         if (NT_STATUS_EQUAL(NT_STATUS_INTERNAL_DB_CORRUPTION, status)) {
     724           0 :                 DEBUG(1,("winsdb_record: corrupted record: %s\n", ldb_dn_get_linearized(msg->dn)));
     725             :         }
     726           0 :         talloc_free(rec);
     727           0 :         return status;
     728             : }
     729             : 
     730             : /*
     731             :   form a ldb_message from a winsdb_record
     732             : */
     733        1025 : static struct ldb_message *winsdb_message(struct ldb_context *ldb,
     734             :                                           struct winsdb_record *rec,
     735             :                                           TALLOC_CTX *mem_ctx)
     736             : {
     737             :         int i, ret;
     738             :         size_t addr_count;
     739             :         const char *expire_time;
     740        1025 :         struct ldb_message *msg = ldb_msg_new(mem_ctx);
     741        1025 :         if (msg == NULL) goto failed;
     742             : 
     743             :         /* make sure we don't put in corrupted records */
     744        1025 :         addr_count = winsdb_addr_list_length(rec->addresses);
     745        1025 :         if (rec->state == WREPL_STATE_ACTIVE && addr_count == 0) {
     746          26 :                 rec->state = WREPL_STATE_RELEASED;
     747             :         }
     748        1025 :         if (rec->type == WREPL_TYPE_UNIQUE && addr_count > 1) {
     749           0 :                 rec->type = WREPL_TYPE_MHOMED;
     750             :         }
     751             : 
     752        1025 :         expire_time = ldb_timestring(msg, rec->expire_time);
     753        1025 :         if (!expire_time) {
     754           0 :                 goto failed;
     755             :         }
     756             : 
     757        1025 :         msg->dn = winsdb_dn(msg, ldb, rec->name);
     758        1025 :         if (msg->dn == NULL) goto failed;
     759        1025 :         ret = ldb_msg_add_fmt(msg, "type", "0x%02X", rec->name->type);
     760        1025 :         if (rec->name->name && *rec->name->name) {
     761        1020 :                 ret |= ldb_msg_add_string(msg, "name", rec->name->name);
     762             :         }
     763        1025 :         if (rec->name->scope && *rec->name->scope) {
     764         176 :                 ret |= ldb_msg_add_string(msg, "scope", rec->name->scope);
     765             :         }
     766        1025 :         ret |= ldb_msg_add_fmt(msg, "objectClass", "winsRecord");
     767        1025 :         ret |= ldb_msg_add_fmt(msg, "recordType", "%u", rec->type);
     768        1025 :         ret |= ldb_msg_add_fmt(msg, "recordState", "%u", rec->state);
     769        1025 :         ret |= ldb_msg_add_fmt(msg, "nodeType", "%u", rec->node);
     770        1025 :         ret |= ldb_msg_add_fmt(msg, "isStatic", "%u", rec->is_static);
     771        1025 :         ret |= ldb_msg_add_empty(msg, "expireTime", 0, NULL);
     772        1025 :         if (!(rec->is_static && rec->state == WREPL_STATE_ACTIVE)) {
     773        1012 :                 ret |= ldb_msg_add_string(msg, "expireTime", expire_time);
     774             :         }
     775        1025 :         ret |= ldb_msg_add_fmt(msg, "versionID", "%llu", (long long)rec->version);
     776        1025 :         ret |= ldb_msg_add_string(msg, "winsOwner", rec->wins_owner);
     777        1025 :         ret |= ldb_msg_add_empty(msg, "address", 0, NULL);
     778        2127 :         for (i=0;rec->addresses[i];i++) {
     779        1102 :                 ret |= ldb_msg_add_winsdb_addr(msg, rec, "address", rec->addresses[i]);
     780             :         }
     781        1025 :         if (rec->registered_by) {
     782         458 :                 ret |= ldb_msg_add_empty(msg, "registeredBy", 0, NULL);
     783         458 :                 ret |= ldb_msg_add_string(msg, "registeredBy", rec->registered_by);
     784             :         }
     785        1025 :         if (ret != LDB_SUCCESS) goto failed;
     786        1025 :         return msg;
     787             : 
     788           0 : failed:
     789           0 :         talloc_free(msg);
     790           0 :         return NULL;
     791             : }
     792             : 
     793             : /*
     794             :   save a WINS record into the database
     795             : */
     796         207 : uint8_t winsdb_add(struct winsdb_handle *h, struct winsdb_record *rec, uint32_t flags)
     797             : {
     798             :         struct ldb_message *msg;
     799         207 :         struct ldb_context *wins_db = h->ldb;
     800         207 :         TALLOC_CTX *tmp_ctx = talloc_new(wins_db);
     801         207 :         int trans = -1;
     802             :         int ret;
     803             : 
     804         207 :         trans = ldb_transaction_start(wins_db);
     805         207 :         if (trans != LDB_SUCCESS) goto failed;
     806             : 
     807         207 :         if (flags & WINSDB_FLAG_ALLOC_VERSION) {
     808             :                 /* passing '0' means auto-allocate a new one */
     809         194 :                 rec->version = winsdb_set_maxVersion(h, 0);
     810         194 :                 if (rec->version == 0) goto failed;
     811             :         }
     812         207 :         if (flags & WINSDB_FLAG_TAKE_OWNERSHIP) {
     813         194 :                 rec->wins_owner = h->local_owner;
     814             :         }
     815             : 
     816         207 :         msg = winsdb_message(wins_db, rec, tmp_ctx);
     817         207 :         if (msg == NULL) goto failed;
     818         207 :         ret = ldb_add(wins_db, msg);
     819         207 :         if (ret != LDB_SUCCESS) goto failed;
     820             : 
     821         207 :         trans = ldb_transaction_commit(wins_db);
     822         207 :         if (trans != LDB_SUCCESS) goto failed;
     823             : 
     824         207 :         wins_hook(h, rec, WINS_HOOK_ADD, h->hook_script);
     825             : 
     826         207 :         talloc_free(tmp_ctx);
     827         207 :         return NBT_RCODE_OK;
     828             : 
     829           0 : failed:
     830           0 :         if (trans == LDB_SUCCESS) ldb_transaction_cancel(wins_db);
     831           0 :         talloc_free(tmp_ctx);
     832           0 :         return NBT_RCODE_SVR;
     833             : }
     834             : 
     835             : 
     836             : /*
     837             :   modify a WINS record in the database
     838             : */
     839         818 : uint8_t winsdb_modify(struct winsdb_handle *h, struct winsdb_record *rec, uint32_t flags)
     840             : {
     841             :         struct ldb_message *msg;
     842         818 :         struct ldb_context *wins_db = h->ldb;
     843         818 :         TALLOC_CTX *tmp_ctx = talloc_new(wins_db);
     844             :         int trans;
     845             :         int ret;
     846             :         unsigned int i;
     847             : 
     848         818 :         trans = ldb_transaction_start(wins_db);
     849         818 :         if (trans != LDB_SUCCESS) goto failed;
     850             : 
     851         818 :         if (flags & WINSDB_FLAG_ALLOC_VERSION) {
     852             :                 /* passing '0' means auto-allocate a new one */
     853          92 :                 rec->version = winsdb_set_maxVersion(h, 0);
     854          92 :                 if (rec->version == 0) goto failed;
     855             :         }
     856         818 :         if (flags & WINSDB_FLAG_TAKE_OWNERSHIP) {
     857          92 :                 rec->wins_owner = h->local_owner;
     858             :         }
     859             : 
     860         818 :         msg = winsdb_message(wins_db, rec, tmp_ctx);
     861         818 :         if (msg == NULL) goto failed;
     862             : 
     863       10225 :         for (i=0;i<msg->num_elements;i++) {
     864        9407 :                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
     865             :         }
     866             : 
     867         818 :         ret = ldb_modify(wins_db, msg);
     868         818 :         if (ret != LDB_SUCCESS) goto failed;
     869             : 
     870         818 :         trans = ldb_transaction_commit(wins_db);
     871         818 :         if (trans != LDB_SUCCESS) goto failed;
     872             : 
     873         818 :         wins_hook(h, rec, WINS_HOOK_MODIFY, h->hook_script);
     874             : 
     875         818 :         talloc_free(tmp_ctx);
     876         818 :         return NBT_RCODE_OK;
     877             : 
     878           0 : failed:
     879           0 :         if (trans == LDB_SUCCESS) ldb_transaction_cancel(wins_db);
     880           0 :         talloc_free(tmp_ctx);
     881           0 :         return NBT_RCODE_SVR;
     882             : }
     883             : 
     884             : 
     885             : /*
     886             :   delete a WINS record from the database
     887             : */
     888          26 : uint8_t winsdb_delete(struct winsdb_handle *h, struct winsdb_record *rec)
     889             : {
     890          26 :         struct ldb_context *wins_db = h->ldb;
     891          26 :         TALLOC_CTX *tmp_ctx = talloc_new(wins_db);
     892             :         struct ldb_dn *dn;
     893             :         int trans;
     894             :         int ret;
     895             : 
     896          26 :         trans = ldb_transaction_start(wins_db);
     897          26 :         if (trans != LDB_SUCCESS) goto failed;
     898             : 
     899          26 :         dn = winsdb_dn(tmp_ctx, wins_db, rec->name);
     900          26 :         if (dn == NULL) goto failed;
     901             : 
     902          26 :         ret = ldb_delete(wins_db, dn);
     903          26 :         if (ret != LDB_SUCCESS) goto failed;
     904             : 
     905          26 :         trans = ldb_transaction_commit(wins_db);
     906          26 :         if (trans != LDB_SUCCESS) goto failed;
     907             : 
     908          26 :         wins_hook(h, rec, WINS_HOOK_DELETE, h->hook_script);
     909             : 
     910          26 :         talloc_free(tmp_ctx);
     911          26 :         return NBT_RCODE_OK;
     912             : 
     913           0 : failed:
     914           0 :         if (trans == LDB_SUCCESS) ldb_transaction_cancel(wins_db);
     915           0 :         talloc_free(tmp_ctx);
     916           0 :         return NBT_RCODE_SVR;
     917             : }
     918             : 
     919         126 : static bool winsdb_check_or_add_module_list(struct tevent_context *ev_ctx, 
     920             :                                             struct loadparm_context *lp_ctx, struct winsdb_handle *h,
     921             :                                             const char *wins_path)
     922             : {
     923             :         int trans;
     924             :         int ret;
     925             :         struct ldb_dn *dn;
     926         126 :         struct ldb_result *res = NULL;
     927         126 :         struct ldb_message *msg = NULL;
     928         126 :         TALLOC_CTX *tmp_ctx = talloc_new(h);
     929         126 :         unsigned int flags = 0;
     930             : 
     931         126 :         trans = ldb_transaction_start(h->ldb);
     932         126 :         if (trans != LDB_SUCCESS) goto failed;
     933             : 
     934             :         /* check if we have a special @MODULES record already */
     935         126 :         dn = ldb_dn_new(tmp_ctx, h->ldb, "@MODULES");
     936         126 :         if (!dn) goto failed;
     937             : 
     938             :         /* find the record in the WINS database */
     939         126 :         ret = ldb_search(h->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, NULL, NULL);
     940         126 :         if (ret != LDB_SUCCESS) goto failed;
     941             : 
     942         126 :         if (res->count > 0) goto skip;
     943             : 
     944             :         /* if there's no record, add one */
     945          62 :         msg = ldb_msg_new(tmp_ctx);
     946          62 :         if (!msg) goto failed;
     947          62 :         msg->dn = dn;
     948             : 
     949          62 :         ret = ldb_msg_add_string(msg, "@LIST", "wins_ldb");
     950          62 :         if (ret != LDB_SUCCESS) goto failed;
     951             : 
     952          62 :         ret = ldb_add(h->ldb, msg);
     953          62 :         if (ret != LDB_SUCCESS) goto failed;
     954             : 
     955          62 :         trans = ldb_transaction_commit(h->ldb);
     956          62 :         if (trans != LDB_SUCCESS) goto failed;
     957             : 
     958             :         /* close and reopen the database, with the modules */
     959          62 :         trans = LDB_ERR_OTHER;
     960          62 :         talloc_free(h->ldb);
     961          62 :         h->ldb = NULL;
     962             : 
     963          62 :         if (lpcfg_parm_bool(lp_ctx, NULL,"winsdb", "nosync", false)) {
     964           0 :                 flags |= LDB_FLG_NOSYNC;
     965             :         }
     966             : 
     967          62 :         h->ldb = ldb_wrap_connect(h, ev_ctx, lp_ctx, wins_path,
     968             :                                   NULL, NULL, flags);
     969          62 :         if (!h->ldb) goto failed;
     970             : 
     971          62 :         talloc_free(tmp_ctx);
     972          62 :         return true;
     973             : 
     974          64 : skip:
     975          64 :         if (trans == LDB_SUCCESS) ldb_transaction_cancel(h->ldb);
     976          64 :         talloc_free(tmp_ctx);
     977          64 :         return true;
     978             : 
     979           0 : failed:
     980           0 :         if (trans == LDB_SUCCESS) ldb_transaction_cancel(h->ldb);
     981           0 :         talloc_free(tmp_ctx);
     982           0 :         return false;
     983             : }
     984             : 
     985         126 : struct winsdb_handle *winsdb_connect(TALLOC_CTX *mem_ctx, 
     986             :                                      struct tevent_context *ev_ctx,
     987             :                                      struct loadparm_context *lp_ctx,
     988             :                                      const char *owner,
     989             :                                      enum winsdb_handle_caller caller)
     990             : {
     991          88 :         const struct loadparm_substitution *lp_sub =
     992          38 :                 lpcfg_noop_substitution();
     993         126 :         struct winsdb_handle *h = NULL;
     994         126 :         unsigned int flags = 0;
     995             :         bool ret;
     996             :         int ldb_err;
     997             :         char *wins_path;
     998             : 
     999         126 :         h = talloc_zero(mem_ctx, struct winsdb_handle);
    1000         126 :         if (!h) return NULL;
    1001             : 
    1002         126 :         wins_path = lpcfg_state_path(h, lp_ctx, "wins.ldb");
    1003             : 
    1004         126 :         if (lpcfg_parm_bool(lp_ctx, NULL,"winsdb", "nosync", false)) {
    1005           0 :                 flags |= LDB_FLG_NOSYNC;
    1006             :         }
    1007             : 
    1008         126 :         h->ldb = ldb_wrap_connect(h, ev_ctx, lp_ctx, wins_path,
    1009             :                                   NULL, NULL, flags);
    1010         126 :         if (!h->ldb) goto failed;
    1011             : 
    1012         126 :         h->caller = caller;
    1013         126 :         h->hook_script = lpcfg_wins_hook(lp_ctx, lp_sub, h);
    1014             : 
    1015         126 :         h->local_owner = talloc_strdup(h, owner);
    1016         126 :         if (!h->local_owner) goto failed;
    1017             : 
    1018             :         /* make sure the module list is available and used */
    1019         126 :         ret = winsdb_check_or_add_module_list(ev_ctx, lp_ctx, h, wins_path);
    1020         126 :         if (!ret) goto failed;
    1021             : 
    1022         126 :         ldb_err = ldb_set_opaque(h->ldb, "winsdb_handle", h);
    1023         126 :         if (ldb_err != LDB_SUCCESS) goto failed;
    1024             : 
    1025         122 :         return h;
    1026           0 : failed:
    1027           0 :         talloc_free(h);
    1028           0 :         return NULL;
    1029             : }
    1030             : 

Generated by: LCOV version 1.13