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

Generated by: LCOV version 1.14