LCOV - code coverage report
Current view: top level - source4/nbt_server/wins - winsdb.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 404 563 71.8 %
Date: 2024-02-29 22:57:05 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.14